jni 调用java接口_JNI 调用 JAVA 接口

JNI 调用 JAVA 接口

介绍

JNI 是本地语言编程接口。它允许运行在JVM中的Java代码和用C、C++或汇编写的本地代码相互操作。

由于一些加密等情况的需要,需要在 so 层获取一些信息用于生成 license 的部分密钥。需要在 JNI 层调用 Java 接口获取一些信息。

JNI 层调用 JAVA 接口需要一步步声明 class 的路径,method 路径(包括静态 method ),method 输入输出参数等一系列信息。

调用规则稍显复杂。下面简单介绍一些用到的方法(系统知识还在学习中,欢迎交流分享)

例子:以获取设备的 IMEI 为例

// 注意,仅用于示例。获取 IMEI 的方法不一定适用(需要考虑 Android 6.0 等版本差异,以及设备具有多个 IMEI 等情况)

TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);

String imei = telephonyManager.getDeviceId();

0. 声明变量(非必要)

jclass cls_Context;

jclass cls_TelephonyManager;

jobject obj_telephonyManager;

jstring str_TELEPHONY_SERVICE;

jstring str_imei;

jmethodID mid_getSystemService;

jmethodID mid_getDeviceId;

jfieldID fid_TELEPHONY_SERVICE;

定义了一些接下来需要用到的变量。

个人习惯的问题,主要是方便后面偷懒用。(详细情况下方)

有更好的做法不妨交流一下。

1. 获取 getSystemService 接口

cls_Context = env->FindClass("android/content/Context");

mid_getSystemService = env->GetMethodID(cls_Context, "mid_getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");

其中 getSystemService 来源于 Content 类。

因此需要先获取 Content 类(jclass)。再通过 method 名称,method 的输入输出参数获取对应的 methodID(jmethodID)。

详细 methodID 的声明形式见 附录1:MethodID 参数对应列表

2. 获取 TelephonyManager 对象

fid_TELEPHONY_SERVICE = env->GetStaticFieldID(cls_Context, "TELEPHONY_SERVICE", "Ljava/lang/String;");

str_TELEPHONY_SERVICE = (jstring) env->GetStaticObjectField(cls_Context, fid_TELEPHONY_SERVICE);

obj_telephonyManager = env->CallObjectMethod(mContext, mid_getSystemService, str_TELEPHONY_SERVICE);

TELEPHONY_SERVICE 是 Context 类里的一个静态常量。

调用 getSystemService 接口需要的参数是 TELEPHONY_SERVICE 对应的字符串。

因此需要先拿到该 fieldID,然后获取其内容。

可以看一下 附录2:MethodID 和 FieldID 部分对比 的一些对比。

3. 获取 IMEI

cls_TelephonyManager = env->FindClass("android/telephony/TelephonyManager");

mid_getDeviceId = env->GetMethodID(cls_TelephonyManager, "getDeviceId", "()Ljava/lang/String;");

str_imei = (jstring) env->CallObjectMethod(obj_telephonyManager, mid_getDeviceId);

类似于第 2 步,想要调用函数必须先从拿到 class 开始,然后声明 method ,传入参数获取返回值。

4. 手动释放 jobject 资源。

env->DeleteLocalRef(cls_Context);

env->DeleteLocalRef(cls_TelephonyManager);

env->DeleteLocalRef(obj_telephonyManager);

env->DeleteLocalRef(str_TELEPHONY_SERVICE);

凡是继承于 jobject 的都需要手动释放,以防内存泄漏。

主要有:

jclass, jstring, jarray, jobjectArray, jbooleanArray, jbyteArray, jcharArray, jshortArray, jintArray, jlongArray, jfloatArray, jdoubleArray, jthrowable, jweak

当然还有 jobject 。

所以第 0 步的初始化,主要是为了在释放内存时使用。

JNI 层获取 IMEI 方法参考

JNIEXPORT jstring JNICALL

Java_org_xxx_DeviceInfo_JniGetIMEI(

JNIEnv* env, jobject /* this */

, jobject mContext

) {

/*

* TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);

* String imei = telephonyManager.getDeviceId();

*/

jclass cls_Context;

jclass cls_TelephonyManager;

jobject obj_telephonyManager;

jstring str_TELEPHONY_SERVICE;

jstring str_imei;

jmethodID mid_getSystemService;

jmethodID mid_getDeviceId;

jfieldID fid_TELEPHONY_SERVICE;

/* TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); */

cls_Context = env->FindClass("android/content/Context");

mid_getSystemService = env->GetMethodID(cls_Context, "mid_getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");

fid_TELEPHONY_SERVICE = env->GetStaticFieldID(cls_Context, "TELEPHONY_SERVICE", "Ljava/lang/String;");

str_TELEPHONY_SERVICE = (jstring) env->GetStaticObjectField(cls_Context, fid_TELEPHONY_SERVICE);

obj_telephonyManager = env->CallObjectMethod(mContext, mid_getSystemService, str_TELEPHONY_SERVICE);

/* String imei = telephonyManager.getDeviceId(); */

cls_TelephonyManager = env->FindClass("android/telephony/TelephonyManager");

mid_getDeviceId = env->GetMethodID(cls_TelephonyManager, "getDeviceId", "()Ljava/lang/String;");

str_imei = (jstring) env->CallObjectMethod(obj_telephonyManager, mid_getDeviceId);

quick_release: // class, object, string

env->DeleteLocalRef(cls_Context);

env->DeleteLocalRef(cls_TelephonyManager);

env->DeleteLocalRef(obj_telephonyManager);

env->DeleteLocalRef(str_TELEPHONY_SERVICE);

return str_imei;

}

这里没有做变量获取出错的判断,理论上是需要做的。

出错时 goto 到 quick_release 释放资源并退出。(也可以增加报错)

还有创建新对象的部分,这里暂不展开。

后面有空再补充吧!

附录1:MethodID 参数对应列表

Java 类型

JNI 类型

对应值

说明

示例

boolean

jboolean

Z

byte

jbyte

B

char

jchar

C

short

jshort

S

int

jint

I

long

jlong

J

float

jfloat

F

double

jdouble

D

int[]

[I

一维数组形式,以一个 "[" 表示一维数组

byte[][]

[[B

N 维数组则以 N 个 "[" 表示N维

String

jstring

Ljava/lang/String;

类参数,则以 "Lxxx/yyy;" 的形式表示,注意 "L" 开头和 ";" 结尾。xxx/yyy 则是类的路径(都属于 jobject )

返回值 void

V

函数形式

(xxx)yyy

"()"内为输入参数,右侧为输出参数

注意:jarray, jclass, jstring, jthrowable, jweak 等都继承于 jobject。

附录2:MethodID 和 FieldID 部分对比

ID 类型

JNI Type

获取非静态ID

获取静态ID

获取值 / 调用函数

MethodID

jmethodID

GetMethodID

GetStaticMethodID

CallFloatMethod / CallObjectMethod / CallStaticIntMethod ... (视函数类型选择)

FieldID

jfieldID

GetFieldID

GetStaticFieldID

GetFloatField / GetObjectField / GetStaticIntField ...(视ID对应参数的类型而选择)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值