JNI分为静态注册和动态注册。前面的文章就是静态注册的例子,此篇会写动态注册的例子。
静态注册:
流程:
1.编写Java代码,实现Native方法;
2.利用javah指令生成对应的.h文件;
3.对.h文件中的声明进行实现;
优点:理解和使用方法简单,使用相关工具按照流程操作就行。
缺点:编写不方便,JNI方法名字必须遵循规则且名字很长。当需要更改类名,包名或者方法适合,需要按照之前方法重新生成头文件,灵活性不高。
动态注册:
优点:灵活性高,更改类名,包名,方法时,只需要对更改模块进行少量修改,效率高。
缺点:对新手不容易理解,会搞错签名,方法,导致注册失败。
举个动态注册的栗子:
1.创建Java类并实现native方法
package cn.zzw.jnidemo2.fromjni;
public class JniTools {
static {
System.loadLibrary("myjni");
}
public JniTools() {
}
public native String getMessageFromJni();
}
2.创建C文件,实现Java中的native方法
jstring cn_zzw_jnidemo2_fromjni_JniTools_getMessageFromJni(JNIEnv* env, jobject thiz)
{
return (*env)->NewStringUTF(env, "我是zuowei.zhang, 动态注册JNI");
}
3.编写c代码,编写参数映射表,就是需要注册的函数列表,放在JNINativeMethod 类型的数组中,只要有native方法就在这里添加
static const JNINativeMethod g_methods[] = {
{ "getMessageFromJni", "()Ljava/lang/String;", (void*)cn_zzw_jnidemo2_fromjni_JniTools_getMessageFromJni},
};
4.注册native方法
static int register_cn_zzw_jnidemo2_fromjni_JniTools(JNIEnv* env) {
jclass clazz = (*env)->FindClass(env,"cn/zzw/jnidemo2/fromjni/JniTools");
if (clazz == NULL) {
return JNI_FALSE;
}
if ((*env)->RegisterNatives( env,clazz, g_methods, sizeof(g_methods)/ sizeof(g_methods[0])) < 0) {
return JNI_FALSE;
}
return JNI_TRUE;
}
5. 加载jni,实现JNI_OnLoad方法
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env = NULL;
jint result = -1;
if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
return -1;
}
if (register_cn_zzw_jnidemo2_fromjni_JniTools(env) != JNI_TRUE ) {
return -1;
}
//成功
result = JNI_VERSION_1_4;
return result;
}
6.详细的c文件如下:
//
// Created by zuowe on 2019/5/28.
//
#include <jni.h>
jstring cn_zzw_jnidemo2_fromjni_JniTools_getMessageFromJni(JNIEnv* env, jobject thiz)
{
return (*env)->NewStringUTF(env, "我是zuowei.zhang, 动态注册JNI");
}
static const JNINativeMethod g_methods[] = {
{ "getMessageFromJni", "()Ljava/lang/String;", (void*)cn_zzw_jnidemo2_fromjni_JniTools_getMessageFromJni},
};
static int register_cn_zzw_jnidemo2_fromjni_JniTools(JNIEnv* env) {
jclass clazz = (*env)->FindClass(env,"cn/zzw/jnidemo2/fromjni/JniTools");
if (clazz == NULL) {
return JNI_FALSE;
}
if ((*env)->RegisterNatives( env,clazz, g_methods, sizeof(g_methods)/ sizeof(g_methods[0])) < 0) {
return JNI_FALSE;
}
return JNI_TRUE;
}
/*
* System.loadLibrary("lib")时调用
* 如果成功返回JNI版本, 失败返回-1
*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env = NULL;
jint result = -1;
if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
return -1;
}
if (register_cn_zzw_jnidemo2_fromjni_JniTools(env) != JNI_TRUE ) {
return -1;
}
//成功
result = JNI_VERSION_1_4;
return result;
}
7. 在jni目录下创建Android.mk文件
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := myjni
LOCAL_SRC_FILES := ctools.c
include $(BUILD_SHARED_LIBRARY)
8.编译生成.so文件
9.编写app下的build.gradle文件
ndk{
moduleName "myjni"
}
sourceSets.main{
jni.srcDirs = []
jniLibs.srcDir "src/main/libs"
}
9.调用jni
package cn.zzw.jnidemo2;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import cn.zzw.jnidemo2.fromjni.JniTools;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView mTv = findViewById(R.id.mTv);
JniTools tools=new JniTools();
mTv.setText(tools.getMessageFromJni());
}
}
10.结果
完整代码:https://download.csdn.net/download/zzw0221/11212803