Android_NDK JNI实现原理和简单实现(D7)

本文深入解析了Android NDK中的JNI开发流程,包括定义本地native方法、生成.h头文件、调用库函数,以及使用JNI在Java与C/C++之间的交互。实例演示了如何在Kotlin中调用C++函数并处理字符串和基本类型操作。
摘要由CSDN通过智能技术生成

Android_NDK JNI实现原理和简单实现

JNI开发一般流程

  1. 定义本地native方法
  2. 生成.h头文件
  3. 添加.h的工程目录依赖添加
  4. 实现头文件中的native方法
  5. load动态库
定义java native方法

kotlin

external fun signatureParams(params: String): String


init {
        System.loadLibrary("lib_network_sign")
    }
  • System.load 加载一个具体路径上的.so库
    动态下载下来来加载
  • System.loadLibrary 加载Android libs目录下的.so库
生产头文件

c文件

#include <jni.h>
#include <string>
#include <android/log.h>
#include "md5.h"
//<>引入系统头文件,""引入入自己的头文件

...

extern "C"
JNIEXPORT void JNICALL
Java_com_sweet_lib_1network_1sign_SignatureUtils_signatureVerify(JNIEnv *env, jobject thiz,
                                                                 jobject context)

.h头文件和实现文件

引入一个.h头文件相当于把.h头文件的实现拷贝到当前文件

//打了一个标记,编译时会把头文件拷贝到引入的地方,重复引用和相互引用都只拷贝一次
#ifndef 
//相当于if语句 c++
#ifdef _cplusplus
//不管是c和c++都统一用c的编译方式。
//因为c中不允许函数重载,但是c++可以,通过包名找ndk函数的时候确保唯一
extern "C"
//JNIEXPORT 标记为外部可以调用
//void java中的void
//JNICALL 标记JNI调用
//JNIEnv C和java相互调用的桥梁,搞清楚里面的方法就行
//jobject java传递的对象,本文就是String
//jclass java传递的class对象,本项目String.class
JNIEXPORT void JNICALL
Java_com_sweet_lib_1network_1sign_SignatureUtils_signatureVerify(JNIEnv *env, jobject thiz,
                                                                 jobject context){
                                                                     //c++写法
    jclass j_clz = env->GetObjectClass(context);
    //c写法
     jclass j_clz = (*env)->GetObjectClass(context);
 }

->调用必须是一级指针取值,所以c和c++取值方法不同

JNI实现原理

#if defined(__cplusplus)
    typedef _JNIEnv JNIEnv;
    typedef _JavaVM JavaVM;
#else
    typedef const struct JNINativeInterface* JNIEnv;
    typedef const struct JNIInvokeInterface* JavaVM;
#endif

在c++中就是_JNIEnv的结构体别名,在c中是JNINativeInterface的指针别名

访问java属性

JNIEXPORT void JNICALL Java_com_sweet_lib_1network_1sign_changeName
(JNIEnv *env, jobject jobj){
	// 获取 name 属性然后修改为 Jack

	// 3.获取 jclass 
	jclass j_clz = (*env)->GetObjectClass(env, jobj);
	// 获取 jfieldId (JNIEnv *env, jclass clazz, const char *name, const char *sig)
	// name 获取哪个属性的属性名 
	// 2.sig 属性的签名
	jfieldID j_fid = (*env)->GetFieldID(env, j_clz, "name", "Ljava/lang/String;");
	// 1.获取 name 属性的值
	jstring j_str = (*env)->GetObjectField(env, jobj, j_fid);

	// 打印字符串 jstring -> c_str
	char* c_str = (*env)->GetStringUTFChars(env,j_str,NULL);

	printf("name is %s",c_str);

	// 修改成 jack
	jstring jackName = (*env)->NewStringUTF(env,"Jack");
	(*env)->SetObjectField(env, jobj, j_fid, jackName);

}

JNIEXPORT void JNICALL Java_com_sweet_lib_1network_1sign_changeAge
(JNIEnv * env, jclass jcls){
	// 首先获取原来的

	jfieldID j_fid = (*env)->GetStaticFieldID(env,jcls,"age","I");
	// Static 获取静态的
	jint age = (*env)->GetStaticIntField(env, jcls, j_fid);

	// jint -> int
	age += 12;

	// 设置新的 age 参数
	(*env)->SetStaticIntField(env,jcls,j_fid,age);
}


JNIEXPORT void JNICALL Java_com_sweet_lib_1network_1sign_callAddMathod
(JNIEnv *env, jobject jobj){
	
	jclass j_clz = (*env)->GetObjectClass(env,jobj);
	// 获取 methodid 
	jmethodID j_mid = (*env)->GetMethodID(env, j_clz, "add", "(II)I");
	// 去调用 java 的方法
	jint sum = (*env)->CallIntMethod(env, jobj, j_mid,2,3);

	printf("sum = %d",sum);
}

JNIEXPORT void JNICALL Java_com_sweet_lib_1network_1sign_callStaticMethod
(JNIEnv *env, jclass jclz){

	// 2.获取 methodId
	jmethodID j_mid = (*env)->GetStaticMethodID(env,jclz,"getUUID","()Ljava/lang/String;");
	// 1. 调用 getUUID 的方法 static 
	jstring j_uuid = (*env)->CallStaticObjectMethod(env, jclz,j_mid);

	// jstring -> c_str
	char* c_uuid = (*env)->GetStringUTFChars(env,j_uuid,NULL);
	
	// 回收,字符串回收 
	(*env)->ReleaseStringUTFChars(env,j_uuid,c_uuid);

	printf("c_uuid = %s",c_uuid);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值