Pale uses Tauri Mobile for the Android client. The Android build packages the same React interface as the desktop app and compiles the Rust backend for Android.
The current Android CI builds an arm64 APK. That proves the project can package for Android, but it does not replace testing on a real phone with microphone, camera, notification, network, and background-mode permissions.
- Node.js 22
- Rust stable
- JDK 17
- Android SDK command-line tools
- Android NDK
27.2.12479018 - Android platform API 35 or newer
- Android build tools 35 or newer
Set these environment variables before building:
export ANDROID_HOME="$HOME/Android/Sdk"
export ANDROID_NDK_ROOT="$ANDROID_HOME/ndk/27.2.12479018"
export NDK_HOME="$ANDROID_NDK_ROOT"
export PATH="$ANDROID_HOME/platform-tools:$ANDROID_HOME/cmdline-tools/latest/bin:$PATH"Install the Rust targets used by the Android build:
rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-androidInstall JavaScript dependencies:
npm ciTauri generates the Android Gradle project under src-tauri/gen/android.
npm run tauri android initRun this once per checkout, or again after changing Tauri mobile configuration.
For the supported arm64 build:
npm run tauri android build -- --target aarch64 --apkThe APK is written under:
src-tauri/gen/android/app/build/outputs/apk/
Android video depends on:
- PJSIP Java classes under
org.pjsip(shipped inpackaging/android/java/) PaleJni.prepare(activity)on the main thread (injected into MainActivity by CI) — registersCameraManagerwithPjCameraInfo2and attachesPaleVideoOverlay- Rust
JNI_OnLoad+ ClassLoader-safe FindClass (src-tauri/crates/pale-core/src/android_jni.rs); PJSIP worker threads use the app ClassLoader viapale_android_find_class - Surface bind on media state (
android_video.rs): remoteANativeWindow+ local preview (pjsua_vid_preview_start); answer/outbound usevid_cnt = 1 - Linked system libs:
mediandk,EGL,GLESv2,OpenSLES - R8 keep rules for
org.pjsip.*so release minification does not strip camera classes
Without those, the app either crashes in and_factory_init or has no camera devices.
Details: packaging/android/README.md.
Gradle may emit an unsigned release APK. Android will refuse to install it until it is signed (v2/v3). Sign with the repo sideload cert (or your own):
./scripts/sign-android-apk.sh \
src-tauri/gen/android/app/build/outputs/apk/**/app-*-unsigned.apk \
dist/android/Pale.apkDetails: packaging/android/README.md.
- Use a signed APK named
Pale.apk/*-signed.apk— not*-unsigned.apk. - Enable Install unknown apps for the browser or Files app.
- If an older Pale build used a different certificate, uninstall it first.
- Honor / Magic / Xiaomi: turn off pure-mode / external-source blocks if install is blocked.
- Optional:
adb install -r Pale.apkwith USB debugging.
Public download (signed sideload):
- Website (stable name): https://drcpbx.com/downloads/Pale.apk
- Versioned mirror: https://drcpbx.com/downloads/current/Pale_0.1.6_android.apk
- Checksums: https://drcpbx.com/downloads/pale-android-SHA256SUMS.txt
- GitHub release (video path): https://github.com/loreste/palephone/releases/tag/android-video-full-0.1.6
- CI artifact
pale-android-apkon each green Android workflow run
Emulator-validated (API 34): install + launch, camera enum (“Back camera”), video codecs (H.264/VP8/VP9). Confirm on a physical phone with CAMERA + MIC and a live SIP peer before calling the fleet certified.
Enable USB debugging on the phone, connect it, then run:
adb devices
npm run tauri android devIf the device does not appear in adb devices, fix the USB debugging, cable, or driver issue before debugging Pale.
Before considering an Android build usable, test these flows on real hardware:
- Sign in to a Pale server over HTTPS.
- Keep the app installed, rebuild/update it, and confirm the saved server/account settings remain.
- Open Calls, Chat, People, Files, Calendar, Settings, and Admin for an admin user.
- Grant microphone permission and place a test call.
- Grant camera permission and start a video-capable flow.
- Enable notifications and confirm incoming call/message notification behavior.
- Lock the phone and confirm the expected background behavior for your deployment.
If the build cannot find the NDK, check ANDROID_HOME, ANDROID_NDK_ROOT, and NDK_HOME.
If Rust reports that core cannot be found for an Android target, install the missing target with rustup target add.
If Gradle fails after a Tauri upgrade, regenerate the Android project with npm run tauri android init.
If the APK builds but the app cannot connect to the server, confirm the server URL uses HTTPS with a certificate trusted by Android. Self-signed or private certificates must be installed on the device or replaced with a public CA certificate.