Android JNI静态和动态注入方法

Android调用C/C++的代码目前比较流行的方式之一便是通过JNI,其中按本地方法的实现有两种方式:静态和动态

创建一个C项目或者C的Module:

创建成功之后会生成如下文件(CMakeLists.txt、nativelib.cpp):
其中:####
objectivec 复制代码
CMakeLists文件作用是将cpp(c++代码文件),打包成一个so库;
nativelib.cpp主要是编写C++代码的文件

1.静态注入方法的方式

新创建的好的项目或者module就是一个静态方式,会直接将c++代码编译成so库,并打包到apk文件中

本地方法声明:

本地方法实现:

本地方法调用:

本地方法注入so库:

build之后会生成so库:

静态库的方式编译:

2.动态注入的方式:

CMakeLists里面的配置:

cpp文件:

java 复制代码
#include <jni.h>
#include <string>
#include <android/log.h>
#define  LOG_TAG    "XXX"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

static jint JNICALL cAdd(JNIEnv *env, jobject jobj, jint x, jint y){
LOGI("cAdd x is :%d  y is :%d", x, y);
return x + y;
}

static jstring JNICALL cSayHi(JNIEnv *env, jobject jobj, jint x, jint y){
LOGI("cSayHi runs... will return a string in c");
return env->NewStringUTF("hello from cSayHi");
}

/**
   第一个参数:javaAdd 是java中的方法名称
   第二个参数:(II)I  是java中方法的签名,可以通过javap -s -p 类名.class 查看
   第三个参数: (jstring *)cSayHi  (返回值类型)映射到native的方法名称

*/
static const JNINativeMethod gMethods[] = {
        {"javaAdd", "(II)I", (jint *)cAdd},
        {"javaSayHi","()Ljava/lang/String;",(jstring *)cSayHi}
};


static jclass myClass;
// 这里是java调用C的存在Native方法的类路径
static const char* const className="com/example/jni/dynamic/JniOnloadTest";
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){
    LOGI("jni onload called");
    JNIEnv* env = NULL; //注册时在JNIEnv中实现的,所以必须首先获取它
    jint result = -1;
    if(vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) { //从JavaVM获取JNIEnv,一般使用1.4的版本
        return -1;
    }
    // 获取映射的java类
    myClass = env->FindClass(className);
    if(myClass == NULL)
    {
        printf("cannot get class:%s\n", className);
        return -1;
    }
    // 通过RegisterNatives方法动态注册
    if(env->RegisterNatives(myClass, gMethods, sizeof(gMethods)/sizeof(gMethods[0])) < 0)
    {
        printf("register native method failed!\n");
        return -1;
    }
    LOGI("jni onload called end...");
    return JNI_VERSION_1_4; //这里很重要,必须返回版本,否则加载会失败。
}

注意上边相当于:通过JNI_OnLoad给com/example/jni/dynamic/JniOnloadTest类,动态实现了gMethods里面中的方法,只不过gMethods里面的方法需要按照固定的格式缓存数据,最后看下JniOnloadTest类:

java 复制代码
package com.example.jni.dynamic;

public class JniOnloadTest {
    public native int  javaAdd(int x, int y);
    public native String javaSayHi();

    static {
        System.loadLibrary("test-dynamic");
    }
}
调用方式: 复制代码
Log.e("TAG", "onCreate: " + JniOnloadTest().javaAdd(Random .nextInt(5),Random .nextInt(6)) )

小结:不管是静态还是动态注入本地方法的方式,在Android Studio编译工具中打出的包,都可以通过命令查看里面注入的方法,执行:nm -D xxx.so

动态注入的方式会有JNI_OnLoad方法

静态注入会有Java_开头的代码:

思考:还有没有其他方式可以直接调用so库中的代码呢?

相关推荐
YM52e2 小时前
鸿蒙Flutter Padding内边距:EdgeInsets详解
android·学习·flutter·华为·harmonyos·鸿蒙
前端工作日常5 小时前
我学习到的Java中domain和dto区别
java·后端
码农学院5 小时前
基于Spring Boot的跨境电商多语言订单管理系统架构设计
java·大数据·spring boot
Rex叶然6 小时前
ScreenMatch适配安卓屏幕脚本,用于老项目
android·screenmatch·安卓屏幕适配
阿pin6 小时前
Android随笔-Activity启动流程深度分析
android·activity启动流程
技术小结-李爽6 小时前
【工具】pom文件的<packaging>
java·maven
l156469487 小时前
突围!图文混合知识库难以解析,Kimi-K3 原生视觉架构深耕知识工作,DMXAPI 统一接口,缩短项目开发周期
java·大数据·开发语言
zzq77977 小时前
加固包闪退四象限定位:targetSdk 与保护策略实战解析
android·安全·安卓·安全架构
布吉岛的石头8 小时前
Java 程序员第 45 阶段11:网关统一路由大模型接口,配合 Nacos 配置治理,灰度路由:基于Nacos元数据实现大模型服务灰度发布与权重路由
java·服务发现
我命由我123458 小时前
Android 开发问题:Cannot resolve method ‘repeat‘ in ‘String‘
android·java·java-ee·android studio·android jetpack·android-studio·android runtime