样例java类
HelloJni.java
package com.example.test;
public class HelloJni {
public native String stringFromJNI();
static {
System.loadLibrary("helloJni");
}
}
方法一:静态注册
遵守JNI标准规函数命名方式, JNI中方法命名为 Java_包名_类名_方法名
, 可以使用javah生成签名头文件, 靠这种方式实现Native方法与JNI方法之间的映射关系,即应用直接与框架层进行交互,这种规范常用与应用开发;
javah -jni 自动生成.h文件
在<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”);对应起来。
javap -s -p 查看函数签名
-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数组中对应相应的方法关系即可。