1. JNI函数详解
java中native方法在C++代码中一般如下:
extern "C" JNIEXPORT jstring JNICALL
Java_com_lucky_jnidemo_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
1. extern "C"
说明
表示下面的代码,都采用C的编译方式。
之所以用C的编译方式,是因为 JNIEnv 是C语言代码写的,避免一些函数重载等C语言中不支持的
查看JNIEnv
源码,进入到jni.h
,可以看到:
#if defined(__cplusplus)
typedef _JNIEnv JNIEnv; // 如果是C++代码,用这个宏定义
typedef _JavaVM JavaVM;
#else
typedef const struct JNINativeInterface* JNIEnv; //如果是C代码,用这个宏定义
typedef const struct JNIInvokeInterface* JavaVM;
#endif
继续跟踪 _JNIEnv
,可以看到:
struct _JNIEnv {
/* do not rename this; it does not seem to be entirely opaque */
const struct JNINativeInterface* functions;
因此,env的调用方式如下:
// C++的情况如下:
Java_com_lucky_jnidemo_MainActivity_stringFromJNI(JNIEnv * env, ...)
{
env->NewStringUTF(); //详细看源码中的结构体定义
}
C的情况如下:
Java_com_lucky_jnidemo_MainActivity_stringFromJNI(JNIEnv * env, ...)
{
(*env)->NewStringUTF(); //二级指针
}
2. JNIEXPORT
宏定义说明
针对Linux平台:该声明的作用是保证在本动态库中声明的方法 , 能够在其他项目中可以被调用 ;
3. JNICALL
宏定义说明
此宏定义为空,用来表示函数的调用规范。
4. jobject
与 jclass
jobject // java传递下来的对象,就是本项目中 MainActivity 对象
jclass // java传递下来的 class 对象,就是本项目中的 MainActivity class
2. JNI中函数操作
1. 在C层中修改Java/Kotlin层String变量(引用类型遍历)
Kotlin代码:
//即将要修改的代码熟悉
private var mName: String = "Lucky"
//native 修改String name
external fun changeStringName()
//点击按钮进行修改
binding.btn1.setOnClickListener {
Log.i("MainActivity", "修改前:$mName")
changeStringName()
Log.i("MainActivity", "修改后:$mName")
}
C层中的代码
extern "C"
JNIEXPORT void JNICALL
Java_com_lucky_jnidemo_MainActivity_changeStringName(JNIEnv *env, jobject thiz) {
//获取Class方式一
jclass mainActivityCls = env->FindClass("com/lucky/jnidemo/MainActivity");
//获取Class方式二
//jclass mainActivityCls = env->GetObjectClass(thiz);
// jfieldID GetFieldID(jclass clazz, const char* name, const char* sig)
jfieldID nameFid = env->GetFieldID(mainActivityCls, "mName", "Ljava/lang/String;");
// void SetObjectField(jobject obj, jfieldID fieldID, jobject value)
jstring value = env->NewStringUTF("Update Lucky");
//void SetObjectField(jobject obj, jfieldID fieldID, jobject value)
env->SetObjectField(thiz, nameFid, value); //修改值
}
打印结果:
com.lucky.jnidemo I/MainActivity: 修改前:Lucky
com.lucky.jnidemo I/MainActivity: 修改后:Update Lucky
2. 在C层中修改Kotlin层静态Int变量
通过apk查看编译后的MainActivity 类,可以看到静态mAege是在MainActivity 中
因此,这里跟修改MainActivity中的变量一样的操作
Kotlin代码:
companion object {
private var mAge: Int = 666
init {
System.loadLibrary("jnidemo")
}
external fun changeIntAge() //修改Int age
}
binding.btn2.setOnClickListener {
Log.i("MainActivity", "修改前:${
mAge}")
changeIntAge()
Log.i("MainActivity", "修改后:${
mAge}")
}
C层中的代码
extern "C"
JNIEXPORT void JNICALL
Java_com_lucky_jnidemo_MainActivity_000