”代码写的太烂怎么办“
“能跑吗?”
“你是说人还是程序?”
“有一个能跑就行”
Android Studio在较新版本已经自带cmake的方式实现对c层的支持,我们新建项目时可以看到选项
而实现jni_onload动态注册则可以减少每次更改都要改一堆方法名的尴尬
新建完成项目之后可以在cpp目录下看到CMakeLists.txt
其文件内容大致如下
add_library:用于添加一个需要生成的so文件,如果有多个so文件则需要写多个add_library,如果需要链接多个cpp文件则可以在第三个字段添加
解释一下这三个字段
第一个是so名,第二个是设置为共享库,第三个是需要链接在一起的cpp文件
注意cpp的路径是相对cpp这个文件夹的,比如我多加了一个路径jni就需要多写上jni/xxx.cpp
find_library:不做处理,想要深入了解自行百度
target_link_libraries:对应上面的so名,其他的字段不做处理,想深入了解可以百度
如果想要添加头文件则需要设置include_directories字段,如图示
这里解释一下意思,这段是设置头文件目录为cmake根目录(一般是cpp文件夹)下面jni里面headfile这个目录,具体如何写需要对照你的目录路径
做完处理之后就可以在cpp目录下面新建cpp文件了,注意文件名要与CMakeLists.txt里面的内容对应。
但在此之前我们需要先在java层对c层进行对接
新建一个java类
package com.dyc.testlib.loadlib;
public class Load_jni_lib//此类用于专门载入so文件 用于分割c与java层
{
static
{
System.loadLibrary("Dyc_dynamic");
}
public native int get_add_result(int a,int b);
}
暂且不关注c层的实现,这个类在java层面进行了so的载入和c层方法的注册,通过直接调用这个这个类中的方法即可
现在我们可以进行c层的编写
//
// Created by Dying'chen on 2021/5/22.
//
#include <jni.h>
#define JAVA_CLASS "com/dyc/testlib/loadlib/Load_jni_lib"
//类名,对应java注册方法的类
jint get_add_result(JNIEnv *env,jobject jobj,int a,int b)//这是add方法的具体实现
{
return a+b;
}
//用于注册的方法的数组
static JNINativeMethod methodArray[] ={
{"get_add_result","(II)I",(void *)get_add_result}
};
int registerNativeMethods(JNIEnv *env,char *name,JNINativeMethod *methods,jint method_number)
{
jclass jclasz;
jclasz = env->FindClass(name);
if(jclasz== nullptr)
{
return JNI_FALSE;
}
if(env->RegisterNatives(jclasz,methods,method_number)<0)//绑定之后的类的方法就已经实现并且具有实例
{
return JNI_FALSE;
}
return JNI_TRUE;
}
JNIEXPORT int JNICALL JNI_OnLoad(JavaVM *vm,void *reserved)//实现jni_onload接口
{
JNIEnv *env;
if(vm->GetEnv(reinterpret_cast<void **>(&env),JNI_VERSION_1_6)!=JNI_OK)//JNI_OK=0 不成功就直接返回false
{
return JNI_FALSE;
}
registerNativeMethods(env,JAVA_CLASS,methodArray,1);//调用前面我们自己写的注册方法
return JNI_VERSION_1_6;//需要返回调用的jni版本
}
这里解释一下methodArray里面的函数签名第一个字段是方法注册的方法名,第二个是函数签名,I对应int,这里的(II)I表示有两个int类型的参数,返回一个int类型的结果。值得注意的是每个需要注册的方法在具体实现时前面的两个参数都是JNIEnv *env和jobject jobj,然后才是我们自己的参数
然后我们在主活动调用一下这个方法验证是否成功
//最基础的cmake实现jni_onload动态注册
public class MainActivity extends AppCompatActivity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = findViewById(R.id.sample_text);
Load_jni_lib loader = new Load_jni_lib();
int temp = loader.get_add_result(5,10);
tv.setText("结果为:"+String.valueOf(temp));
}
}
编译生成app,安装验证