样例java类 HelloJni.java
package com.example.test; public class HelloJni { public native String stringFromJNI(); static { System.loadLibrary("helloJni"); } }遵守JNI标准规函数命名方式, JNI中方法命名为 Java_包名_类名_方法名, 可以使用javah生成签名头文件, 靠这种方式实现Native方法与JNI方法之间的映射关系,即应用直接与框架层进行交互,这种规范常用与应用开发;
在<project>\bin\classes目录下执行
javah -classpath .;<sdkPath>\sdk\platforms\android-19\android.jar -jni com.pachong.test.Hello(pakageName.className)即可生成对应的.h头文件,在这个头文件中就有我们需要实现的c&c++方法了,这里加上<sdkPath>\sdk\platforms\android-19\android.jar是因为我们的类中有引用到系统相关的一些类或方法需要加上android.jar才能生成对应.h文件。 com_example_test_HelloJni.h
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_test_HelloJni */ #ifndef _Included_com_example_test_HelloJni #define _Included_com_example_test_HelloJni #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_test_HelloJni * Method: stringFromJNI * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_example_test_HelloJni_stringFromJNI (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif在项目根目录下新建jni文件夹,将刚刚生成的.h文件拷贝到这个目录下,同时新建一个对应的.cpp文件和Android.mk文件用于编译生成so文件。
com_example_test_HelloJni.cpp
/* DO NOT EDIT THIS FILE - it is machine generated */ #include "com_example_test_HelloJni.h" /* Header for class com_example_test_HelloJni */ /* * Class: com_example_test_HelloJni * Method: stringFromJNI * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_example_test_HelloJni_stringFromJNI (JNIEnv *, jobject) { return env->NewStringUTF("Hello from JNI !"); }Android.mk
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libhelloJni LOCAL_SRC_FILES := com_example_test_HelloJni.cpp include $(BUILD_SHARED_LIBRARY)注:LOCAL_MODULE := libhelloJni要和System.loadLibrary(“helloJni”);对应起来。
-s: 显示签名(只显示public类型的签名) -p:显示所有函数、成员变量的签名
javap -classpath .;<sdkPath>\sdk\platforms\android-19\android.jar -s -p com.pachong.test.Hello(pakageName.className)(注:<sdkPath>\sdk\platforms\android-19\android.jar是可选项),通过签名我们就可以在写jni相关的代码时写入相应的签名即可。
这是Android自定义的一种规范, 应用框架层采用该规范, 即应用框架层 与 框架层 进行交互, 底层源码开发多使用该规范;
动态注册是通过调用JNI_OnLoad方法,去注册相关类的方法来实现的,来看下具体的实现。 customHelloJni.cpp
#include <jni.h> static jstring hello(JNIEnv* evn, jobject thiz) { return env->NewStringUTF("Hello from JNI !"); } //需要调用实现JNI的类 static const char* classPathName = "com/example/test/HelloJni"; //绑定相应的方法 static JNINativeMethod methods[] = { {"stringFromJNI", "()Ljava/lang/String",(void*)hello}, }; //注册指定类的相关方法 static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods, int numMethods) { jclass clazz; clazz = env->FindClass(className); if (class == NULL) { return JNI_FALSE; } if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) { return JNI_FALSE; } return JNI_TRUE; } static int registerNatives(JNIEnv* env) { if (!registerNativeMethods(env, classPathName, methods, sizeof(methods)/sizeof(methods[0]))) { return JNI_FALSE; } return JNI_TRUE; } //注册JNI方法入口 jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL; jint result = -1; if (vm->GetEnv(&env, JNI_VERSION_1_4) != JNI_OK) { return result; } if (registerNatives(env) != JNI_TRUE) { return result; } result = JNI_VERSION_1_4; return result; }通过上面的代码实现,我们知道动态注册比静态注册在实现函数命名上更加自由,我们不需要按照JNI的那套标准规则来命名相关方法,只需要在绑定方法函数时与Java类中方法对应即可,即JNINativeMethod数组中对应相应的方法关系即可。