安卓JNI动态注册

在安卓JNI静态注册一文中我提到要使用c/c++代码中的方法,就需要在android代码中对c/c++代码中的方法进行注册,注册方式有两种: 静态注册和动态注册,本文讲的是JNI动态注册

为什么有静态注册和动态注册之分,本文不讨论,本文送上的是如何实现的干货。

一,AS新建一个Native C++项目。好处是无需你配置JNI环境。

%title插图%num

创建好空项目后会提示你没有在AS中配置NDK路径,如下图:

%title插图%num

此时我们可以点击右上角的Project Structure按钮,在弹出的窗口中配置Android NDK location,即可,例如我这儿是如下图所示:

%title插图%num

Apply->Ok后就配置完成了。

二,随手布局和写几句java代码。

我这里布局只布局一个按钮,要实现的功能是点击按钮时通过jni动态注册的方式调用c++代码中的方法并获取返回内容最后弹窗显示返回内容。

%title插图%num

编写java代码,实现按钮点击事件

注意,如果有人尝试一步一步按照本文来操作的话,那么默认空项目里的hello,world的textview控件需要删除,自然而然MainActivity里就获取不到该控件了,对应的代码也需要删除

%title插图%num

删除后开始写自己的代码,我们布局的是一个按钮控件,功能是点击按钮时通过jni动态注册的方式调用c++代码中的方法并获取返回内容最后弹窗显示返回内容。

java代码如下:

package com.example.dynamicregister;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

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

        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String result = stringFromJNI();
                Toast.makeText(getApplicationContext(),result,Toast.LENGTH_LONG).show();
            }
        });
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}

三,开始编写JNI动态注册代码

由于AS已经帮我在java代码中自动写了System.loadLibrary和native声明的stringFromJNI方法,当然你也可以自己修改loadLibrary的库名称和stringFromJNI方法名称,但不是仅仅改java代码中的名称就完事儿,所以不清楚的话请不要去改。

基于上面的步骤都OK了之后,我们进入CPP目录,编辑native-lib.cpp文件,代码如下:

#include <jni.h>

//1,实现对应的方法
jstring stringFromJNI(JNIEnv *env, jobject){
    return env->NewStringUTF("Hi,我是JNI动态注册");
}

//2,注册对应的方法
JNINativeMethod methods[] = {
        {"stringFromJNI","()Ljava/lang/String;",(jstring *)stringFromJNI}
};

//3,使用JNI_OnLoad载入对应的方法
jint JNI_OnLoad(JavaVM *vm, void *unused) {
    JNIEnv *env;
    if(vm->GetEnv((void **) &env,JNI_VERSION_1_6) != JNI_OK)return JNI_ERR;
    jclass jc = env->FindClass("com/example/dynamicregister/MainActivity");
    env->RegisterNatives(jc,methods,sizeof(methods)/ sizeof(methods[0]));
    return JNI_VERSION_1_6;
}

大致总结起来就是三步走:

1,实现对应的方法
2,注册对应的方法
3,使用JNI_OnLoad载入对应的方法

四,点击AS右上角的绿色三角按钮,AS会自动编译so文件,自动打开模拟器自动安装app运行,第一次由于需要初始化AS的模拟器会需要点儿时间。

运行的效果如下图:

%title插图%num

发表回复