Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

android/gradlew.bat text eol=crlf
189 changes: 189 additions & 0 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
name: Android APK and AAB
on:
pull_request:
paths: ['android/**', 'native/**', 'app/**', 'engine/**', 'room/**', 'room.js', 'p2p.html', 'index.html', 'site/**', 'scripts/android-*', 'tests/duga/**', '.github/workflows/android.yml']
push:
branches: [main, feat/duga-android]
tags: ['android-v*']
workflow_dispatch:
permissions:
contents: read
concurrency:
group: android-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
oracle:
runs-on: ubuntu-24.04
timeout-minutes: 25
env:
DUGA_WEBGPU_MODULE: native/vulkan/oracle/node_modules/webgpu/index.js
DUGA_SOURCE_COMMIT: ${{ github.sha }}
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with: { node-version: 22 }
- name: Install native build and software Vulkan driver
run: sudo apt-get update && sudo apt-get install -y g++ libvulkan-dev mesa-vulkan-drivers spirv-tools
- name: Select the installed software Vulkan ICD
run: |
mapfile -t icds < <(find /usr/share/vulkan/icd.d -maxdepth 1 -type f -name '*lvp*.json' -print)
test "${#icds[@]}" -eq 1 || { echo 'Expected one installed Lavapipe driver'; exit 1; }
printf 'VK_ICD_FILENAMES=%s\n' "${icds[0]}" >> "$GITHUB_ENV"
- name: Install pinned shader compiler and WebGPU oracle
run: |
rustup update stable --no-self-update
cargo +stable install naga-cli --version 30.0.1 --locked
npm ci --prefix native/vulkan/oracle --no-audit --no-fund
- name: Compile original shader sources and Vulkan runners
run: |
node native/vulkan/shaders.mjs
node native/vulkan/export-reference.mjs
g++ -std=c++17 -O2 -ffp-contract=off -Inative/vulkan/build/shaders native/vulkan/vulkan.cpp native/vulkan/oracle.cpp -lvulkan -o native/vulkan/build/duga-vk-oracle
g++ -std=c++17 -O2 -ffp-contract=off -Inative/vulkan/build/shaders native/vulkan/vulkan.cpp native/vulkan/gguf.cpp native/vulkan/dense.cpp native/vulkan/model-run.cpp -lvulkan -o native/vulkan/build/duga-vk-model
- name: Capture WebGPU oracle and require exact Vulkan parity
env:
DUGA_SOURCE_COMMIT: ${{ github.sha }}
run: |
node native/vulkan/capture-oracle.mjs
native/vulkan/build/duga-vk-oracle native/vulkan/build/oracle.dvk
native/vulkan/build/duga-vk-oracle native/vulkan/build/oracle.dvk --reference
native/vulkan/build/duga-vk-oracle native/vulkan/build/oracle.dvk --on-device
node native/vulkan/check-model.mjs
node --test tests/duga/*.test.mjs
- name: Install the Android emulator's software Vulkan driver
uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407
with:
packages: emulator
log-accepted-android-sdk-licenses: false
- name: Capture the Android software-device reference
env:
DUGA_SOURCE_COMMIT: ${{ github.sha }}
run: |
export VK_ICD_FILENAMES="$ANDROID_HOME/emulator/lib64/vulkan/vk_swiftshader_icd.json"
test -f "$VK_ICD_FILENAMES"
node native/vulkan/capture-oracle.mjs
native/vulkan/build/duga-vk-oracle native/vulkan/build/oracle.dvk
native/vulkan/build/duga-vk-oracle native/vulkan/build/oracle.dvk --reference
native/vulkan/build/duga-vk-oracle native/vulkan/build/oracle.dvk --on-device
node native/vulkan/check-model.mjs
- name: Upload validated native shader inputs
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: native-vulkan-inputs
path: |
native/vulkan/build/shaders/
native/vulkan/build/oracle.dvk
native/vulkan/build/oracle.dvk.json
if-no-files-found: error
retention-days: 14

build:
needs: oracle
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with: { node-version: 22 }
- uses: actions/setup-java@cf277c60eb25467037889841efdb72551f06f6c3
with: { distribution: temurin, java-version: 17 }
- uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407
with:
packages: platform-tools
log-accepted-android-sdk-licenses: false
- uses: gradle/actions/setup-gradle@0b6dd653ba04f4f93bf581ec31e66cbd7dcb644d
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with: { name: native-vulkan-inputs, path: native/vulkan/build }
- name: Install pinned Android SDK components
run: sdkmanager 'platforms;android-36' 'build-tools;35.0.0' 'ndk;27.3.13750724' 'cmake;3.22.1'
- name: Validate version for tag delivery
if: startsWith(github.ref, 'refs/tags/android-v')
env: { RELEASE_TAG: '${{ github.ref_name }}' }
run: node scripts/android-version.mjs
- name: Configure release signing
if: startsWith(github.ref, 'refs/tags/android-v')
env:
KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
run: |
test -n "$KEYSTORE_BASE64" && test -n "$KEYSTORE_PASSWORD" && test -n "$KEY_ALIAS" && test -n "$KEY_PASSWORD" || { echo 'Android release signing secrets are required; refusing unsigned tag delivery.'; exit 1; }
printf '%s' "$KEYSTORE_BASE64" | base64 --decode > "$RUNNER_TEMP/duga-release.jks"
chmod 600 "$RUNNER_TEMP/duga-release.jks"
printf 'DUGA_KEYSTORE_PATH=%s\n' "$RUNNER_TEMP/duga-release.jks" >> "$GITHUB_ENV"
- name: Test and lint Android port
run: android/gradlew -p android testDebugUnitTest lintDebug --no-daemon
- name: Enable KVM access for the Android test device
run: |
test -e /dev/kvm
sudo chmod a+rw /dev/kvm
- name: Verify Android Vulkan logits, JNI and bundled UI
uses: ReactiveCircus/android-emulator-runner@a421e43855164a8197daf9d8d40fe71c6996bb0d
with:
api-level: 35
target: google_apis
arch: x86_64
ram-size: 2048M
emulator-options: -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim -camera-back none -camera-front none
script: |
npm ci --prefix native/vulkan/oracle --no-audit --no-fund
VK_ICD_FILENAMES="$ANDROID_HOME/emulator/lib64/vulkan/vk_swiftshader_icd.json" DUGA_WEBGPU_MODULE=native/vulkan/oracle/node_modules/webgpu/index.js node scripts/android-native-check.mjs
android/gradlew -p android connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.requireExactVulkan=true --no-daemon
- name: Build preview APK and AAB
if: ${{ !startsWith(github.ref, 'refs/tags/android-v') }}
run: android/gradlew -p android assembleDebug bundleDebug --no-daemon
- name: Build signed release APK and AAB
env:
DUGA_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
DUGA_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
DUGA_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
if: startsWith(github.ref, 'refs/tags/android-v')
run: |
android/gradlew -p android assembleRelease bundleRelease --no-daemon
"$ANDROID_HOME/build-tools/35.0.0/apksigner" verify android/app/build/outputs/apk/release/app-release.apk
jarsigner -verify android/app/build/outputs/bundle/release/app-release.aab > "$RUNNER_TEMP/aab-signature.txt"
grep -q "jar verified" "$RUNNER_TEMP/aab-signature.txt"
- name: Verify 16 KB native-library ZIP alignment
run: |
mapfile -t apks < <(find android/app/build/outputs/apk -name '*.apk' -type f -print)
test "${#apks[@]}" -gt 0
for apk in "${apks[@]}"; do
"$ANDROID_HOME/build-tools/35.0.0/zipalign" -c -P 16 4 "$apk"
done
- name: Package delivery files and checksums
run: |
mkdir -p android-delivery
if [[ "$GITHUB_REF" == refs/tags/android-v* ]]; then
cp android/app/build/outputs/apk/release/app-release.apk "android-delivery/duga-android-$DUGA_VERSION_NAME.apk"
cp android/app/build/outputs/bundle/release/app-release.aab "android-delivery/duga-android-$DUGA_VERSION_NAME.aab"
else
cp android/app/build/outputs/apk/debug/app-debug.apk android-delivery/duga-android-debug.apk
cp android/app/build/outputs/bundle/debug/app-debug.aab android-delivery/duga-android-debug.aab
fi
cd android-delivery
sha256sum *.apk *.aab > SHA256SUMS
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with: { name: duga-android, path: android-delivery/, if-no-files-found: error, retention-days: 30 }
- name: Remove temporary signing key
if: always()
run: rm -f "$RUNNER_TEMP/duga-release.jks"

release:
if: startsWith(github.ref, 'refs/tags/android-v')
needs: build
runs-on: ubuntu-24.04
permissions: { contents: write }
steps:
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with: { name: duga-android, path: android-delivery }
- name: Publish APK and AAB on the existing tag
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
RELEASE_TAG: ${{ github.ref_name }}
run: |
flags=()
[[ "$RELEASE_TAG" == *-*.*.*-* ]] && flags+=(--prerelease)
gh release create "$RELEASE_TAG" android-delivery/* --verify-tag --title "Duga Android ${RELEASE_TAG#android-v}" --generate-notes "${flags[@]}"
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,16 @@ tests/eval/results/
dist/
docs-site/dist/
docs-site/.astro/

# Android/native generated files and signing material
android/.gradle/
android/.cxx/
android/build/
android/app/build/
android/app/.cxx/
android/local.properties
native/vulkan/build/
*.jks
*.keystore
*.apk
*.aab
4 changes: 4 additions & 0 deletions .vercelignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,7 @@ docs-site/.astro
/dist



# Native Android builds are separate from the website.
android
native
Loading