NDK JNI 函数的静态注册与动态注册

函数的静态注册与动态注册

  1. 加载动态编译后的库

static {
    System.loadLibrary("native-lib");
}
  1. 静态注册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());
}
  1. 动态注册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;
}
  1. 完整代码

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sziitjin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值