Android_NDK JNI实现原理和简单实现
JNI开发一般流程
- 定义本地native方法
- 生成.h头文件
- 添加.h的工程目录依赖添加
- 实现头文件中的native方法
- load动态库
定义java native方法
kotlin
external fun signatureParams(params: String): String
init {
System.loadLibrary("lib_network_sign")
}
- System.load 加载一个具体路径上的.so库
动态下载下来来加载 - System.loadLibrary 加载Android libs目录下的.so库
生产头文件
c文件
#include <jni.h>
#include <string>
#include <android/log.h>
#include "md5.h"
//<>引入系统头文件,""引入入自己的头文件
...
extern "C"
JNIEXPORT void JNICALL
Java_com_sweet_lib_1network_1sign_SignatureUtils_signatureVerify(JNIEnv *env, jobject thiz,
jobject context)
.h头文件和实现文件
引入一个.h头文件相当于把.h头文件的实现拷贝到当前文件
//打了一个标记,编译时会把头文件拷贝到引入的地方,重复引用和相互引用都只拷贝一次
#ifndef
//相当于if语句 c++
#ifdef _cplusplus
//不管是c和c++都统一用c的编译方式。
//因为c中不允许函数重载,但是c++可以,通过包名找ndk函数的时候确保唯一
extern "C"
//JNIEXPORT 标记为外部可以调用
//void java中的void
//JNICALL 标记JNI调用
//JNIEnv C和java相互调用的桥梁,搞清楚里面的方法就行
//jobject java传递的对象,本文就是String
//jclass java传递的class对象,本项目String.class
JNIEXPORT void JNICALL
Java_com_sweet_lib_1network_1sign_SignatureUtils_signatureVerify(JNIEnv *env, jobject thiz,
jobject context){
//c++写法
jclass j_clz = env->GetObjectClass(context);
//c写法
jclass j_clz = (*env)->GetObjectClass(context);
}
->调用必须是一级指针取值,所以c和c++取值方法不同
JNI实现原理
#if defined(__cplusplus)
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
#else
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM;
#endif
在c++中就是_JNIEnv的结构体别名,在c中是JNINativeInterface的指针别名
访问java属性
JNIEXPORT void JNICALL Java_com_sweet_lib_1network_1sign_changeName
(JNIEnv *env, jobject jobj){
// 获取 name 属性然后修改为 Jack
// 3.获取 jclass
jclass j_clz = (*env)->GetObjectClass(env, jobj);
// 获取 jfieldId (JNIEnv *env, jclass clazz, const char *name, const char *sig)
// name 获取哪个属性的属性名
// 2.sig 属性的签名
jfieldID j_fid = (*env)->GetFieldID(env, j_clz, "name", "Ljava/lang/String;");
// 1.获取 name 属性的值
jstring j_str = (*env)->GetObjectField(env, jobj, j_fid);
// 打印字符串 jstring -> c_str
char* c_str = (*env)->GetStringUTFChars(env,j_str,NULL);
printf("name is %s",c_str);
// 修改成 jack
jstring jackName = (*env)->NewStringUTF(env,"Jack");
(*env)->SetObjectField(env, jobj, j_fid, jackName);
}
JNIEXPORT void JNICALL Java_com_sweet_lib_1network_1sign_changeAge
(JNIEnv * env, jclass jcls){
// 首先获取原来的
jfieldID j_fid = (*env)->GetStaticFieldID(env,jcls,"age","I");
// Static 获取静态的
jint age = (*env)->GetStaticIntField(env, jcls, j_fid);
// jint -> int
age += 12;
// 设置新的 age 参数
(*env)->SetStaticIntField(env,jcls,j_fid,age);
}
JNIEXPORT void JNICALL Java_com_sweet_lib_1network_1sign_callAddMathod
(JNIEnv *env, jobject jobj){
jclass j_clz = (*env)->GetObjectClass(env,jobj);
// 获取 methodid
jmethodID j_mid = (*env)->GetMethodID(env, j_clz, "add", "(II)I");
// 去调用 java 的方法
jint sum = (*env)->CallIntMethod(env, jobj, j_mid,2,3);
printf("sum = %d",sum);
}
JNIEXPORT void JNICALL Java_com_sweet_lib_1network_1sign_callStaticMethod
(JNIEnv *env, jclass jclz){
// 2.获取 methodId
jmethodID j_mid = (*env)->GetStaticMethodID(env,jclz,"getUUID","()Ljava/lang/String;");
// 1. 调用 getUUID 的方法 static
jstring j_uuid = (*env)->CallStaticObjectMethod(env, jclz,j_mid);
// jstring -> c_str
char* c_uuid = (*env)->GetStringUTFChars(env,j_uuid,NULL);
// 回收,字符串回收
(*env)->ReleaseStringUTFChars(env,j_uuid,c_uuid);
printf("c_uuid = %s",c_uuid);
}