Android进阶知识树——JNI和So库开发

1、Jni基础知识

JNI是Java Native Interface的缩写,意思是Java的本地接口,这个本地接口主要指Java可以通过本地接口去和其他的编程语言通信,有时在开发某个功能时想使用之前的技术积累或封装好的模块,但不幸的是之前不是用Java开发的,那对于此中情况该如何处理呢?对于经过时间验证的可靠程序不可能轻易重写和修改,所以就需要JNI作为程序的中转枢纽;

  • Jni使用场景
  1. 需要调用Java语言不支持的依赖时,
  2. 整合非Java语言开发的系统,如C、C++
  3. 节省运行时间提高运行效率,如:音视频等
  • Jni类型和Java类型的映射关系

既然Jni是Java和其他语言的沟通桥梁,那么它既必须有一套基础协议作为与Java代码沟通的基础,这个基础就是类型的映射和签名,类型映射就是在Java类型和Jni中的类型建立一一对应关系,从而实现二者的类型可读性和唯一性,签名指Java中类型、方法、属性等在Java中的展现形式,根据最终的签名查找方法的对应关系;

  1. native方法与Jni映射实例
public static native String action(short s , int i, long l, float f, double d, char c,
                     boolean z, byte b, String str, Object obj, ArrayList<String> array,
                     int[] arr, Action action);
//生成的Jni对应的代码
JNIEXPORT jstring JNICALL Java_com_alex_kotlin_jni_JniTest_action
  (JNIEnv *, jclass, jshort, jint, jlong, jfloat, jdouble, jchar, jboolean, jbyte, jstring, jobject, jobject, jintArray, jobject);
  1. 基本数据映射关系
    在这里插入图片描述
  2. 引用类型关系映射表
    在这里插入图片描述
  • Jni方法名:Java_类全路径_方法名
//native
public native void test();
//jni
JNIEXPORT jstring JNICALL Java_com_alex_kotlin_jni_JniTest_test (JNIEnv *, jobject);

上面是Java代码中声明的test()转换后的Jni方法,此方法名称在编译javah文件时生成,在实现的C文件中重写并实现即可,方法的命名规则:

  1. Java:表示C++实现Java方法的前缀
  2. com_alex_kotlin_jni_JniTest:JniTest的类名全路径
  3. test:native方法名称
  • 参数规则
  1. JNIEnv *:每个native函数的入口参数,执行JVM函数表的指针,JNIEnv即可在Native环境中使用Java资源
  2. jobject:调用java中native方法的实例或class对象,如果native方法是普通方法,则该参数是jobject,如果是静态方法,则是jclass
  3. 剩余参数为native方法的传入参数,此处为JNI中的映射类型(参照介绍映射关系)
  • Jni签名
  1. 数据类型签名:见上面对照表
  2. 方法签名:将参数签名和返回值类型签名组合一起作为方法签名
JNIEXPORT jstring JNICALL Java_com_alex_kotlin_jni_JniTest_setTest
        (JNIEnv *env, jobject cls, jstring j_str) {
   
}
方法签名:(Ljava/lang/Object,Ljava/lang/String)Lava/lang/String
1.1、 JNI 函数注册
  • 静态注册

静态注册JNI方法很简单,我们在Java中声明native方法后,会执行Java命令编译和生成Jni方法:

javac ***
javah ***

在执行javah的命令后,系统会在之间文件处创建.h文件,当我们在Java层调用native方法时,系统就会根据JNI方法命名规则,按照JNI方法名寻找对应的方法,在找到JNI方法后保存JNI指针建立方法间的联系,下次调用时直接使用函数指针就可以,不过静态注册在初次调用时需要查找再建立关联,影响效率,与静态注册对应的就是动态注册,不需要编译和查找关联;

  • 动态注册
  1. 在C++文件中实现native方法,此时方法名并没有严格要求
JNIEXPORT jstring JNICALL native_method(JNIEnv *env, jobject) {
   
    return env->NewStringUTF("Register method in Jni");
};
  1. 创建注册的方法数组,在数组中建立Java方法和Jni方法的对应关系
static JNINativeMethod methods[] = {
   
    //参数:1、Java声明的native方法名;2、方法签名;3、c中实现的方法名
    {
   "method", "()Ljava/lang/String;", (void *) native_method},
};
  1. 在重写的JNI_OnLoad()中调用注册方法实现注册
// 声明动态注册对应的Java类的路径
static const char *const PACKAGE_NAME = "com/alex/kotlin/jni/JniTest";

JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *) {
   
    JNIEnv *env;  //获取JNIEnv
    if (JNI_OK != vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6)) {
   
        return JNI_ERR;
    }
    jclass jclass1 = env->FindClass(PACKAGE_NAME); //根据类名获取jclass
    if (jclass1 == NULL) {
   
        return JNI_ERR;
    }
    jclassGlobal = static_cast<jclass>(env->NewWeakGlobalRef(jclass1)); //创建全局缓存jclass
    env->DeleteLocalRef(jclass1); //释放局部变量
    if (JNI_OK != env->RegisterNatives(jclassGlobal, method, 1)) {
    //注册方法
        return JNI_ERR;
    }
    return JNI_VERSION_1_6;
}

在创建的C++文件中重写Jni.h中的JNI_OnLoad()方法,在JNI_OnLoad中首先根据报名获取Java类的jclass对象,然后全局缓存jclass对象,最后调用RegisterNatives()方法传入jclass和关系数组实现方法的注册

  • 在UnLoad()中解除方法注解
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
   
    JNIEnv *env = NULL;
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
   
        return;
    }
    env->UnregisterNatives(jclassGlobal); //解除注册
    env->DeleteGlobalRef(jclassGlobal); //释放全局变量
}

2、Jni基本使用

在介绍完JNI基础知识后,一起来学习下JNI在开发中的基本使用,也就是Jni的基本语法,其实在上面动态注册时已经使用到了一些,这里根据使用频率介绍下最常用的方法;

2.1、字符串使用
JNIEXPORT jstring JNICALL Java_com_alex_kotlin_jni_JniTest_setTest
        (JNIEnv *env, jobject cls, jstring j_str) {
   
    const char *c_str = NULL;
    char buff[128] = {
   };
    jboolean copy;
    c_str = env->GetStringUTFChars(j_str, &copy); // 字符串访问
    if(c_str == NULL){
    
        return NULL;
    }
    sprintf(buff, "Jni %s", c_str); //字符串输出
    env->ReleaseStringUTFChars(j_str, c_str); 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值