When working with Android applications, sometimes we need to handle sensitive information or perform specific tasks that require a lower-level approach. Using a Native Library built with JNI (Java Native Interface) can be a great way to manage such needs, especially when you want to keep data secure and out of reach of typical Android decompilers. Let’s dive into how to build your own native library, store sensitive information securely, and use it within your Android project.
If you’re not familiar with mobile app architecture before, read my guide to mobile app architecture .
Why Use a Native Library for Sensitive Data?
Android applications often face security challenges, and when it comes to sensitive data (such as API keys or encryption logic), you want to ensure that your data isn’t easily accessible. Native libraries, written in C or C++, can add an extra layer of security because they’re harder to decompile than Java/Kotlin code. Although not entirely foolproof, it’s a step forward in securing critical data.
Note: Native libraries provide an added security layer but don’t fully protect data from reverse engineering. It’s crucial to combine native libraries with other security measures for optimal protection.
Set Up Your Native Library
Create a C/C++ File with Sensitive Data
First, create a C/C++ file (src/main/cpp/NativeLib.c) for your sensitive data. For example, let’s say we have a secret API key. We’ll store this in a C file and then create functions to retrieve it.
#include <jni.h>
JNIEXPORT jstring JNICALL
Java_com_example_securelibrary_NativeLib_getApiKey(JNIEnv *env, jobject obj) {
return (*env)->NewStringUTF(env, "YourSensitiveApiKey");
}
Integrate the Native Library in Your Android Project
In your Android project’s build.gradle file, make sure to specify CMake or NDK to build native code. Here’s how you can enable native support:
android {
...
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
}
}
}
Set Up CMakeLists.txt
In your C++ directory (e.g., src/main/cpp), create a CMakeLists.txt file to build the library:
cmake_minimum_required(VERSION 3.4.1)
add_library(securelib SHARED src/main/cpp/NativeLib.c)
find_library(log-lib log)
target_link_libraries(securelib ${log-lib})
Load and Use the Native Library in Kotlin
With our native library in place, let’s integrate it into the Android project. In your Kotlin or Java code, load the library and call the native function.
object NativeLib {
init {
System.loadLibrary("securelib")
}
external fun getApiKey(): String
}
Using the API Key in Your App
You can now use the NativeLib.getApiKey()
function in your app to retrieve the API key:
val apiKey = NativeLib.getApiKey()
println("Retrieved API Key: $apiKey")
Warning: Avoid displaying sensitive data in logs or UI for additional security.
Testing and Verifying Security
Testing a native library in Android involves verifying the function outputs while ensuring the data is safely hidden. To unit test JNI code, consider mocking the JNI environment to simulate library outputs.
Example Unit Test
Here’s an example of how to test the function output:
class NativeLibTest {
@Test
fun `test API key retrieval`() {
val apiKey = NativeLib.getApiKey()
assertEquals("YourSensitiveApiKey", apiKey)
}
}
Following these steps will allow you to create a native library that securely handles sensitive data in your Android application, enhancing both the performance and security of your app.
Did you like this article?
You can subscribe to my newsletter below and get updates about my new articles.