-> 调用的情况下必须是一级指针 *取值
env->GetXXFieldID
:获取字段的IDenv->GetXXField
:获取字段上的值,返回XX类型env->GetMethodID
:获取方法的IDenv->CallXXMethod
:调用方法。返回XX类型
1. JNI 的一般开发流程:
- 定义好本地的 native 方法,生成
.class
文件。 - 在存放
原文件 .java
的包名文件夹的最前面(src
文件夹下)使用javah 命令生成 .h 头文件javah -d jni -jni com.east.NdkSample
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15用法:
javah [options] <classes>
其中, [options] 包括:
-o <file> 输出文件 (只能使用 -d 或 -o 之一)
-d <dir> 输出目录
-v -verbose 启用详细输出
-h --help -? 输出此消息
-version 输出版本信息
-jni 生成 JNI 样式的标头文件 (默认值)
-force 始终写入输出文件
-classpath <path> 从中加载类的路径
-cp <path> 从中加载类的路径
-bootclasspath <path> 从中加载引导类的路径
<classes> 是使用其全限定名称指定的
(例如, java.lang.Object)。 - 拷贝
xxx.h
、jni_md.h
、jni.h
到 VS 的工程目录并添加依赖进来。(jni_md.h和jni.h在java安装目录下搜索即可查找到) - 实现我们头文件中的 native 方法
- VS生成解决方案即可生成
.dll 动态库
,java 引入 dll 动态库运行即可
java 中加载动态库:
System.loadLibrary
:android 加载apk中的libs目录下 .so 库System.load
: 加载一个具体路径上的 .so 库,去服务器上下载再进行加载(data/data)
2. 详解 .h 文件和实现文件
com_east_NdkSample.h:
1 |
|
Simple.c:
1 | // 实现我们的 native 方法 |
3. JNIEnv 的实现原理
1 |
|
看下 JNINativeInterface
的部分代码:
1 | struct JNINativeInterface { |
看下 _JNIEnv
的部分代码(调用的还是 JNINativeInterface
的方法):
1 | struct _JNIEnv { |
4. C 中访问和修改 java 的属性和方法
env->GetXXFieldID
:获取字段的IDenv->GetXXField
:获取字段上的值,返回XX类型
进入类编译后的.class
文件,全包名路径的目录下。
获取类中:属性和方法签名:javap -p -s com.east.jni07.NdkSample
-s
:输出内部类型签名-p
:显示所有类和成员
4.1 C中修改 java 的普通属性
java 中的属性:public String name = "Eastrise";
java 中的本地方法:public native void changeName();
c中的方法:
1 | JNIEXPORT void JNICALL Java_com_east_NdkSample1_changeName |
4.2 C中修改 java 的静态属性
java 中的属性:public static int age = 24;
java 中的本地静态方法:public static native void changeAge();
c中的方法:
1 | // 静态方法参数会变为 jclass 代表 NdkSample1.class |
4.3 c 调用 java 方法
env->GetMethodID
:获取方法的IDenv->CallXXMethod
:调用方法。返回XX类型
java 中的方法:
1 | public int add(int number1,int number2){ |
c中的方法:
1 | // c 调用 java 层普通方法 |