Files
mail/platform/android/TESTING.md
T

3.5 KiB

Android JNI regression checks

Issue #64 reported an UnsatisfiedLinkError when Java delivered a Google authorization result. NativeActivity opens the native library and calls ANativeActivity_onCreate, but this does not register the library with ART's Java native-method lookup. FlectarActivity must also call System.loadLibrary("flectar_mail_android") in its static initializer, before any native callback can run.

References:

Offline and packaged-library checks

python3 scripts/test-android-jni.py
python3 scripts/test-pdf-packaging.py
python3 scripts/verify-android-native.py path/to/flectar-mail.apk

The offline tests require a C compiler (cc) and GNU readelf or llvm-readelf. Set READELF to an NDK llvm-readelf path if needed. APK verification checks the dynamic symbol table for the native entry point and every Java callback, in every packaged ABI, after release stripping. Both Android release workflows already invoke this verifier through verify-android-apk.sh. Symbol checks alone cannot verify Java library loading.

Device JNI tests

Build and stage the release Rust library and PDFium with the normal test APK script, then run the instrumentation suite on a connected ARM64 test device:

./scripts/build-android-test-apk.sh
./platform/android/gradle/gradlew -p platform/android/gradle \
  :app:connectedDebugAndroidTest

This installs a debug application and a separate test APK. Use a test device or Android user profile without an existing Flectar installation signed by a different key. The Rust library is still the stripped release library staged by the build script. An emulator needs a matching native ABI staged under target/android/gradle-jni, or a Google APIs image with ARM64 translation. Both Android build workflows run these tests on the API 30 Google APIs x86_64 image, which supports ARM64 translation, and retain the instrumentation reports.

NativeCallbacksTest invokes all five native callbacks through the real FlectarActivity class and packaged Rust library. It intentionally does not load the library itself or launch the Activity. No Google account, network access, OAuth registration, or mailbox data is needed. Removing the static initializer must make the invocation tests fail with UnsatisfiedLinkError. These tests verify linkage, not OAuth authorization semantics.

Sign-in acceptance check

On the reported Pixel/GrapheneOS configuration and a supported stock Android device, use an APK whose signing certificate and package are registered for Google authorization. Exercise successful sign-in, consent cancellation, and an authorization failure. Check that a result reaches the app without UnsatisfiedLinkError; cancellation/failure must leave the app usable. Also background/resume the app and open/cancel the document picker, since those callbacks use the same library-loading path.

Record the APK version, Android version and test results before closing #64. If Google authorization still fails, preserve the provider's error separately from JNI linkage failures; never include access tokens or mailbox data in logs.