Introduction to JNI and NDK Development for Android
This article provides a comprehensive introduction to Android NDK development, covering JNI fundamentals, data type mappings, method registration (static and dynamic), JNIEnv usage, CMake build configuration, and multiple practical code examples in Kotlin, C++, and C.
Android development increasingly requires knowledge of the NDK and JNI, which enable Java code to call native C/C++ functions. This guide introduces the essential concepts and practical steps for using JNI in Android applications.
Basic Concepts
JNI (Java Native Interface) is a technology that allows Java bytecode to invoke native C/C++ code. The NDK (Native Development Kit) provides the tools to embed native code in Android apps, useful for porting applications, reusing existing libraries, and improving performance in compute‑intensive scenarios such as games.
Static method registration follows the naming convention Java_ _ _ , while dynamic registration uses a JNINativeMethod table and the RegisterNatives function, typically called from JNI_OnLoad .
Data Type Mapping
JNI defines primitive type equivalents (e.g., jint for Java int , jboolean for boolean ) and reference type mappings (e.g., jobject , jstring , jintArray ). Function signatures combine these type characters, such as (Ljava/lang/String;)V for a method taking a String and returning void .
JNI Environment (JNIEnv)
JNIEnv is a thread‑local structure that provides access to JNI functions. Each thread has its own JNIEnv* pointer, which cannot be shared across threads; native threads must attach to the JVM using JavaVM::AttachCurrentThread and detach when finished.
Building with CMake
CMake generates platform‑specific build files for the NDK. Common commands include:
add_library(compress SHARED compress.c)to create a shared library, and
target_link_libraries(compress libjpeg ${log-lib})to link required libraries. find_library can locate system libraries.
Example Code
Below are representative snippets demonstrating static registration, calling Java methods, handling parameters, and dynamic registration.
Static registration – return a string
extern "C" JNIEXPORT jstring JNICALL Java_com_wx_nativex_kt_demo_MainActivity_stringFromJNI(JNIEnv *env, jobject thiz) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}Static registration – call a Java void method
extern "C" JNIEXPORT void JNICALL Java_com_wx_nativex_kt_demo_MainActivity_callJNI(JNIEnv *env, jobject thiz) {
jclass cls = env->GetObjectClass(thiz);
jmethodID mid = env->GetMethodID(cls, "toast", "(Ljava/lang/String;)V");
env->CallVoidMethod(thiz, mid, env->NewStringUTF("Static registration call succeeded"));
}Static registration – method with parameter
extern "C" JNIEXPORT jstring JNICALL Java_com_wx_nativex_kt_demo_MainActivity_stringFromJNIwithParameter(JNIEnv *env, jobject thiz, jstring str) {
const char *data = env->GetStringUTFChars(str, NULL);
LOGE("Received data: %s", data);
env->ReleaseStringUTFChars(str, data);
return env->NewStringUTF("Processed");
}Dynamic registration
void regist(JNIEnv *env, jobject thiz, jobject call_back) {
LOGD("--Dynamic registration called--");
jclass cls = env->GetObjectClass(call_back);
jmethodID mid = env->GetMethodID(cls, "nmd", "(Ljava/lang/String;)V");
env->CallVoidMethod(call_back, mid, env->NewStringUTF("Callback from native"));
}
jint RegisterNatives(JNIEnv *env) {
jclass activityClass = env->FindClass("com/wx/nativex/kt/demo/MainActivity");
JNINativeMethod methods[] = {
{"dynamicRegisterCallBack", "(Lcom/wx/nativex/kt/demo/NativeCallBack;)V", (void*)regist}
};
return env->RegisterNatives(activityClass, methods, sizeof(methods)/sizeof(methods[0]));
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
if (vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) return JNI_ERR;
RegisterNatives(env);
return JNI_VERSION_1_6;
}The article concludes by summarizing the covered topics: static and dynamic method registration, primitive and reference type mappings, function signatures, JNIEnv usage, CMake build steps, and a series of practical JNI examples.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.