til
Build Variant Support for Android NDK
As part of the "Protect Secrets in your app" (Part 1, Part 2, Part 3) I have shown how to use Android NDK to improve the protection of secrets included in your App.
One of the downsides from the resulting sample was, that it would also enforce and require an implemented keystore fingerprint for debug builds, which in teams is unlikely (unless you share the same keystore throughout your team).
Or you simply want to differentiate keys for different environments.
For this situation it is beneficial to define a different logic to retrieve key and secret.
The first idea which comes to mind may be to specify a different externalNativeBuild
block, pointing at a different variants path. But sadly this is not supported.
debug {
externalNativeBuild {
ndkBuild {
// not allowed
path 'src/main/jni/Android.mk'
}
}
}
A problem occurred evaluating project ':app'.
> No signature of method: build_dn90m3wwrxt4hnmpusnescafr.android() is applicable for argument types: (build_dn90m3wwrxt4hnmpusnescafr$_run_closure1) values: [[email protected]]
While the path
is not supported to be different per variant ndk build arguments
are. This comes in handy as it gives us the possibility to inject arguments adjusting the source location.
debug {
externalNativeBuild {
ndkBuild {
arguments "BUILD_VARIANT=debug"
}
}
}
The same is afterwards accessible from within the Android.mk
# specify the src files to include in the native lib, including the variant folder
LOCAL_SRC_FILES := $(LOCAL_PATH)/../../$(BUILD_VARIANT)/jni/protected.c
The above snippet retrieves the LOCAL_PATH
will step 2 levels out and then go into the folder named debug
(BUILD_VARIANT
) and retrieve the protected.c
class.
Originally this .c
class was located in src/main/jni
.
Let's move it into src/release/jni
and create a stripped down variant for src/debug/jni
.
For debug we may simply return the credentials without any further validation.
// src/debug/jni/protected.c
#include <jni.h>
JNIEXPORT jstring JNICALL
Java_com_mikepenz_credsshowcase_CustomApplication_getSdkKey(JNIEnv *env, jobject thiz, jobject context) {
return (*env)->NewStringUTF(env, "amazing-key-dev");
}
JNIEXPORT jstring JNICALL
Java_com_mikepenz_credsshowcase_CustomApplication_getSdkSecret(JNIEnv *env, jobject thiz, jobject context) {
return (*env)->NewStringUTF(env, "super-secure-secret-dev");
}
And that's it. Run the sample app, and it should return amazing-key-dev
and super-secure-secret-dev
for the debug variant, and the previously defined key and secret for the release variant.