[NDK开发]Android JNI开发之动态注册

广告也精彩

前言

我们第一篇文章 [NDK开发]Android JNI 开发之第一个 JNI实例就是静态注册的。

除了有静态注册,还有动态注册

静态注册

静态注册:先由Java得到本地方法的声明,然后再通过JNI实现该声明方法。

  1. 优点: 理解和使用方式简单, 属于傻瓜式操作, 使用相关工具按流程操作就行, 出错率低
  2. 缺点: 当需要更改类名,包名或者方法时, 需要按照之前方法重新生成头文件, 灵活性不高

动态注册

动态注册:动态注册JAVA的Native方法,使得c/c++里面方法名 可以和 java 的Native方法名可以不同, 动态注册是将将二者方法名关联起来,以后在修改Native方法名时,只需修改动态注册关联的方法名称即可

  1. 优点: 灵活性高, 更改类名,包名或方法时, 只需对更改模块进行少量修改, 效率高
  2. 缺点: 对新手来说稍微有点难理解, 同时会由于搞错签名, 方法, 导致注册失败

正文

下面简单记录一下动态注册的使用。

系统初始化JNI在加载时,会调用JNI_OnLoad(),而卸载时会调用JNI_UnLoad();所以,我们可以通过重写JNI_OnLoad(),在JNI_OnLoad()中将函数注册到Android中,以便能通过Java访问。

第一步

MyDynamic.java代码

package com.biumall.mydynamic2;

public class MyDynamic {

    static {
        System.loadLibrary("MyDynamic");
    }

    /***
     *   1. javac MyDynamic2.java
     *   2. javap -s MyDynamic2.class
     *
     *  public static native java.lang.String StringFormJNI();
     *     Signature: ()Ljava/lang/String;
     *
     *   public static native void StringToJNI(java.lang.String);
     *     Signature: (Ljava/lang/String;)V
     *
     */

    public static native String StringFormJNI();
    public static native void StringToJNI(String message);
}

MainActivity.java

public class MainActivity extends AppCompatActivity {

    String TAG= "Dynamic_Android_Log";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.d(TAG, "onCreate  : "+ MyDynamic.StringFormJNI());
        MyDynamic.StringToJNI("Hello from Android.");
    }
}

第二步

MyDynamic.c

#include<string.h>
#include<jni.h>
#include<stdio.h>
#include <android/log.h>

#define LOG_TAG "Dynamic_JNI_Log"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

//获取数组大小
#define ARRAY_LENGTH(x) ((int)(sizeof(x) / sizeof((x)[0])))
//定义MyDynamic.java类目录(就是包名+类名,只不过.换成了/)
#define DYNAMIC_CLASS "com/biumall/mydynamic2/MyDynamic"

// 定义native 实现的StringFormJNI
JNIEXPORT jstring JNICALL native_StringFormJNI(JNIEnv *env , jclass clasz) {
    LOGD("--------native_StringFormJNI----------");
    return (*env)->NewStringUTF(env, "Hello form JNI.");
}

// 定义native 实现的StringToJNI
JNIEXPORT void JNICALL native_StringToJNI(JNIEnv *env, jclass clasz, jstring message){
     LOGD("native_StringToJNI===%s",(*env)->GetStringUTFChars(env, message, 0));
}

//定义JavaJNI函数的绑定表
// 方法数组,分别为:
// 方法名 | 方法签名 | 函数指针
// 可以通过javacjavap 获取 方法签名
JNINativeMethod method_table[]= {
 {"StringFormJNI", "()Ljava/lang/String;", (void*) native_StringFormJNI},
 {"StringToJNI", "(Ljava/lang/String;)V", (void *) native_StringToJNI},
};


int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod * methods, int methods_size){
    jclass clazz = NULL;
    //反射Java
    clazz = (*env)->FindClass(env, className);
    if(NULL == clazz){
        return JNI_ERR;
    }
    int result = (*env)->RegisterNatives(env, clazz, methods, methods_size);
    LOGD("--------registerNativeMethods---------- result : %d", result);
    if(result < 0){
        return JNI_ERR;
    }
    return JNI_OK;
}

JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved){
    JNIEnv * env = NULL;
    int result = (*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6);
    LOGD("--------JNI_OnLoad----------1 result : %d", result);
    if(result != JNI_OK){
        return JNI_ERR;
    }
    result = registerNativeMethods(env , DYNAMIC_CLASS, method_table, ARRAY_LENGTH(method_table));
    LOGD("--------JNI_OnLoad----------2 result : %d", result);
    if(result != JNI_OK){
        return JNI_ERR;
    }
    return JNI_VERSION_1_6;
}

第四步

Android.mk和Application.mk,这个代码跟之前一样的。

Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_LDLIBS := -llog

LOCAL_MODULE    := MyDynamic
LOCAL_SRC_FILES := MyDynamic.c

include $(BUILD_SHARED_LIBRARY)

Application.mk

APP_ABI := all

第五步

在工程中的build.gradle,新增如下内容:

android {
    compileSdkVersion 31

    // 

    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
}

参考文章

  1. Android JNI和NDK学习(03)--动态方式实现JNI
  2. [NDK开发]Android JNI 开发之第一个 JNI实例
  3. JNI静态注册和动态注册区别
  4. 你应该了解的JNI知识(一)——静态注册与动态注册

广告也精彩
版权声明:125la.com站长 发表于 2022年5月29日 上午8:08。
转载请注明:[NDK开发]Android JNI开发之动态注册 | 125啦读书导航

相关文章

广告也精彩

暂无评论

暂无评论...