函数的静态注册与动态注册
加载动态编译后的库
static {
System.loadLibrary("native-lib");
}
静态注册native方法
选中静态注册方法,按住快捷键【Alt+Enter】,可直接在native层生成静态注册方法
/**
* 静态注册
*
* @return
*/
public native String stringFromJNI();
/**
* 静态注册:
* 优点:开发简单
* 缺点:
* 1.JNI函数名非常长
* 2.捆绑 上层 包名 + 类名
* 3.运行期 才会去 匹配JNI函数,性能上 低于 动态注册
*/
extern "C" JNIEXPORT jstring JNICALL
Java_com_ndk_thread_MainActivity_stringFromJNI(JNIEnv *env, jobject /* this */) {
std::string hello = "Hello from C++";
LOGI("静态注册");
return env->NewStringUTF(hello.c_str());
}
动态注册native方法
1)Java层编写好动态注册的native方法
/**
* 动态注册
*/
public native void dynamicsRegister1();
public native int dynamicsRegister2(String str);
2)native层分为三步:
编写函数指针(动态注册函数)
void dynamicsMethod1() {
LOGD("我是动态注册的函数 dynamicsMethod1...");
}
int dynamicsMethod2(JNIEnv *env, jobject thiz, jstring valueStr) {
const char *text = env->GetStringUTFChars(valueStr, nullptr);
LOGD("我是动态注册的函数 dynamicsMethod2... %s", text);
env->ReleaseStringUTFChars(valueStr, text);
return 200;
}
编写动态注册函数的数组,可以一次性注册多个动态注册函数
static const JNINativeMethod jniNativeMethod[] = {
// {"Java层函数名", "Java层函数的签名", 函数指针(动态函数)}
{"dynamicsRegister1", "()V", (void *) (dynamicsMethod1)},
{"dynamicsRegister2", "(Ljava/lang/String;)I", (int *) (dynamicsMethod2)}
};
重写JNI_OnLoad函数,在执行System.loadLibrary时,调用该函数,在此进行动态注册
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *javaVm, void *) {
// 开始动态注册,通过JavaVM获取JNIEnv(操作杆),跟Java层大量交互都是通过JNIEnv来实现。
JNIEnv *jniEnv = nullptr;
int result = javaVm->GetEnv(reinterpret_cast<void **>(&jniEnv), JNI_VERSION_1_6);
// result 等于0 成功,非0 失败
if (result != 0) {
return -1;
}
// 获取MainActivity class,通过包名 + 类名 获取
jclass mainActivityClass = jniEnv->FindClass(mainActivityClassName);
// 动态注册函数, RegisterNatives(MainActivity class, 动态函数的数组, 注册动态函数数量)
jniEnv->RegisterNatives(mainActivityClass, jniNativeMethod,
sizeof(jniNativeMethod) / sizeof(JNINativeMethod));
LOGE("函数动态注册完成");
return JNI_VERSION_1_6;
}
完整代码
MainActivity
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
/**
* 静态注册
*
* @return
*/
public native String stringFromJNI();
/**
* 动态注册
*/
public native void dynamicsRegister1();
public native int dynamicsRegister2(String str);
public void dynamic01(View view) {
dynamicsRegister1();
int res = dynamicsRegister2("dynamicsRegister2");
Log.i("MainActivity", "调用动态函数,返回结果res = " + res);
}
}
native-lib.cpp
#include <jni.h>
#include <string>
#include <android/log.h>
#define TAG "NDK"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__);
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__);
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__);
/**
* 静态注册:
* 优点:开发简单
* 缺点:
* 1.JNI函数名非常长
* 2.捆绑 上层 包名 + 类名
* 3.运行期 才会去 匹配JNI函数,性能上 低于 动态注册
*/
extern "C" JNIEXPORT jstring JNICALL
Java_com_ndk_thread_MainActivity_stringFromJNI(JNIEnv *env, jobject /* this */) {
std::string hello = "Hello from C++";
LOGI("静态注册");
return env->NewStringUTF(hello.c_str());
}
/**
* 动态注册:
* 优点:速度快,执行System.loadLibrary时,注册好动态函数
* 缺点:定义方式繁琐
*/
// MainActivity类全称
const char *mainActivityClassName = "com/ndk/thread/MainActivity";
// TODO 1.编写函数指针(动态注册函数)
void dynamicsMethod1() {
LOGD("我是动态注册的函数 dynamicsMethod1...");
}
int dynamicsMethod2(JNIEnv *env, jobject thiz, jstring valueStr) {
const char *text = env->GetStringUTFChars(valueStr, nullptr);
LOGD("我是动态注册的函数 dynamicsMethod2... %s", text);
env->ReleaseStringUTFChars(valueStr, text);
return 200;
}
// TODO 2.编写动态注册函数的数组,可以一次性注册多个动态注册函数
static const JNINativeMethod jniNativeMethod[] = {
// {"Java层函数名", "Java层函数的签名", 函数指针(动态函数)}
{"dynamicsRegister1", "()V", (void *) (dynamicsMethod1)},
{"dynamicsRegister2", "(Ljava/lang/String;)I", (int *) (dynamicsMethod2)}
};
// TODO 3.重写JNI_OnLoad函数,在执行System.loadLibrary时,调用该函数,在此进行动态注册
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *javaVm, void *) {
// 开始动态注册,通过JavaVM获取JNIEnv(操作杆),跟Java层大量交互都是通过JNIEnv来实现。
JNIEnv *jniEnv = nullptr;
int result = javaVm->GetEnv(reinterpret_cast<void **>(&jniEnv), JNI_VERSION_1_6);
// result 等于0 成功,非0 失败
if (result != 0) {
return -1;
}
// 获取MainActivity class,通过包名 + 类名 获取
jclass mainActivityClass = jniEnv->FindClass(mainActivityClassName);
// 动态注册函数, RegisterNatives(MainActivity class, 动态函数的数组, 注册动态函数数量)
jniEnv->RegisterNatives(mainActivityClass, jniNativeMethod,
sizeof(jniNativeMethod) / sizeof(JNINativeMethod));
LOGE("函数动态注册完成");
return JNI_VERSION_1_6;
}