# Building and using a locally-modified version of JNA [Java Native Access](https://github.com/java-native-access/jna/) is an important dependency for the Application Services components on Android, as it provides the low-level interface from the JVM into the natively-compiled Rust code. If you need to work with a locally-modified version of JNA (e.g. to investigate an apparent JNA bug) then you may find these notes helpful. --- The JNA docs do have an [Android Development Environment guide](https://github.com/java-native-access/jna/blob/master/www/AndroidDevelopmentEnvironment.md) that is a good starting point, but the instructions did not work for me and appear a little out of date. Here are the steps that worked for me: * Modify your environment to specify `$NDK_PLATFORM`, and to ensure the Android NDK tools for each target platform are in your `$PATH`. On my Mac with Android Studio the config was as follows: ``` export NDK_ROOT="$HOME/Library/Android/sdk/ndk/28.2.13676358" export NDK_PLATFORM="$NDK_ROOT/platforms/android-25" export PATH="$PATH:$NDK_ROOT/toolchains/llvm/prebuilt/darwin-x86_64/bin" export PATH="$PATH:$NDK_ROOT/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin" export PATH="$PATH:$NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin" export PATH="$PATH:$NDK_ROOT/toolchains/x86-4.9/prebuilt/darwin-x86_64/bin" export PATH="$PATH:$NDK_ROOT/toolchains/x86_64-4.9/prebuilt/darwin-x86_64/bin" ``` You will probably need to tweak the paths and version numbers based on your operating system and the details of how you installed the Android NDK. * Install the `ant` build tool (using `brew install ant` worked for me). * Checkout the [JNA source](https://github.com/java-native-access/jna) from Github. Try doing a basic build via `ant dist` and `ant test`. This won't build for Android but will test the rest of the tooling. * Adjust `./native/Makefile` for compatibility with your Android NSK install. Here's what I had to do for mine: * Adjust the `$CC` variable to use clang instead of gcc: `CC=aarch64-linux-android21-clang`. * Adjust thd `$CCP` variable to use the version from your system: `CPP=cpp`. * Add `-landroid -llog` to the list of libraries to link against in `$LIBS`. * Build the JNA native libraries for the target platforms of interest: * `ant -Dos.prefix=android-aarch64` * `ant -Dos.prefix=android-armv7` * `ant -Dos.prefix=android-x86-64` * Package the newly-built native libraries into a JAR/AAR using `ant dist`. This should produce `./dist/jna.aar`. * Configure `build.gradle` for the consuming application to use the locally-built JNA artifact: ``` // Tell gradle where to look for local artifacts. repositories { flatDir { dirs "/PATH/TO/YOUR/CHECKOUT/OF/jna/dist" } } // Tell gradle to exclude the published version of JNA. configurations { implementation { exclude group: "net.java.dev.jna", module:"jna" } } // Take a direct dependency on the local JNA AAR. dependencies { implementation name: "jna", ext: "aar" } ``` * Rebuild and run your consuming application, and it should be using the locally-built JNA! If you're trying to debug some unexpected JNA behaviour (and if you favour old-school printf-style debugging) then you can this code snippet to print to the Android log from the compiled native code: ``` #ifdef __ANDROID__ #include #define HACKY_ANDROID_LOG(...) __android_log_print(ANDROID_LOG_VERBOSE, "HACKY-DEBUGGING-FOR-ALL", __VA_ARGS__) #else #define HACKY_ANDROID_LOG(MSG) #endif HACKY_ANDROID_LOG("this will go to the android logcat output"); HACKY_ANDROID_LOG("it accepts printf-style format sequences, like this: %d", 42); ```