android的ndk开发需要一个桥梁jni,来将java和c/c++联系起来。
分为动态注册和静态注册。
我们先来谈论一下如何进行动态注册
1、写java端的代码
package com.yuanxuzhen.testnative;
public class JNIDynamicLoad {
static {
System.loadLibrary("dynamic-lib");
}
public native int sum(int x, int y);
public native String getNativeString();
}
2要能够动态注册,必须有函数进行动态注册
①新建一个cpp文件 test_dynamic_load.cpp
② cmakelist文件加入配置,并重新编译,才可以引用jni的一些头文件
add_library(
dynamic-lib
SHARED
test_dynamic_load.cpp
)
③ test_dynamic_load.cpp完善
//
// Created by yuanxuzhen on 3/26/21.
//
#include <jni.h>
#define JAVA_CLASS "com/yuanxuzhen/testnative/JNIDynamicLoad"
int registerNativeMethod(JNIEnv* env, const char* name,
JNINativeMethod *method, jint nMethods){
jclass jcls;
jcls = env->FindClass(name);
if(jcls == nullptr){
return JNI_FALSE;
}
if(env->RegisterNatives(jcls, method, nMethods) < 0){
return JNI_FALSE;
}
return JNI_OK;
}
jint sum(JNIEnv* env, jobject jobj, int x, int y){
return x+y;
}
jstring getNativeString(JNIEnv* env, jobject jobj){
return env->NewStringUTF("yuanxzh dynamic load getNativeString");
}
static JNINativeMethod getMethods[] = {
{"getNativeString", "()Ljava/lang/String;", (void*)getNativeString},
{"sum", "(II)I", (void*)sum}
};
JNIEXPORT int JNICALL JNI_OnLoad(JavaVM *vm, void *reserved){
/*jni的调用需要使用到JNIEnv,可以通过JavaVM获取到*/
JNIEnv *env;
if(vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK){
return JNI_FALSE;
}
registerNativeMethod(env, JAVA_CLASS, getMethods, 2);
return JNI_VERSION_1_6;
}
注册中最重要的是JNIEnv,可以通过JavaVM获取
JNIEnv *env;
if(vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK){
return JNI_FALSE;
}
要注册方法要使用到
JNIEnv中的
jint RegisterNatives(jclass clazz, const JNINativeMethod* methods,
jint nMethods)
{ return functions->RegisterNatives(this, clazz, methods, nMethods); }
jclass 方法是java中定义nativie方法的类,
const JNINativeMethod* methods 是一个方法数组,定义了注册的方法
jint nMethods 要注册的方法数
来看下JNINativeMethod的定义
typedef struct {
const char* name; //nativie方法名
const char* signature; //natvie的参数类型和返回类型
void* fnPtr; //对应的C和C++的方法
} JNINativeMethod;
native方法和c/c++中的方法的参数类型和返回类型必须一样,方法名字可以不一样
④java代码中调用方式和正常的类没有区别
JNIDynamicLoad jniDynamicLoad = new JNIDynamicLoad();
jniDynamicLoad.sum(10, 20)
jniDynamicLoad.getNativeString()
这样就能够通过动态注册的方式实现java和c/c++端的互相调用了。