上一篇文章主要讲解有关JNI和NDK开发过程中需要理解的基本的知识,想要了解的,请移步https://blog.csdn.net/qq_36451275/article/details/95347000
开发:
一、JNI原生开发流程(Eclipse)
(1)基本流程
1.在java类中定义native方法
2.生成包含对应JNI函数声明的头文件
3.实现生成的JNI的函数
4.借助NDK编译生成动态链接库文件(.so)
5. 在Java类中加载动态连接库并调用native的方法
6. 运行安装到ARM模拟器上
(2)详细流程
1. 在Java类中定义native方法
在Activity类中声明: public native String helloJNI();
2. 生成包含对应JNI函数声明的头文件
1). 在命令行窗口中执行: javah Activity全类名(在src下执行)
说明有的电脑可能会提示GBK的不可映射字符: 添加 -encoding utf-8
2). 在src下会生成一个头文件: com_atguigu_hellojni_MainActivity.h
3). 头文件中包含一个native方法对应的JNI函数声明(需要后面实现):
JNIEXPORT jstring JNICALL Java_com_atguigu_hellojni_MainActivity_helloJNI(JNIEnv *, jobject)
3. 实现生成的JNI函数
1). 在应用下创建一个文件夹: jni
2). 将刚才生成的头文件复制到此文件夹下
3). 创建一个c文件来实现生成的JNI函数声明: test.c
#include "com_atguigu_hellojni_MainActivity.h"
JNIEXPORT jstring JNICALL Java_com_atguigu_hellojni_MainActivity_helloJNI
(JNIEnv * env, jobject jobj) {
return (*env)->NewStringUTF(env, "Hello from C");
}
4. 借助NDK编译生成动态链接库文件(.so)
1). 解压NDK包, 配置NDK文件夹到path(不能包含空格)
2). 借助NDK下的文档(ANDROID-MK.html)编写用于编译的文件(jni/Android.mk)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni #指定生成的so文件的唯一标识
LOCAL_SRC_FILES := test.c #指定包含JNI函数的c文件名
include $(BUILD_SHARED_LIBRARY)
3). 在命令行窗口中进入应用根目录, 执行ndk-build命令, 生成so动态链接库文件
so文件路径: /libs/armeabi/libhello-jni.so
5. 在Java类中加载动态连接库并调用native的方法
1). 在静态代码块中加载so文件:
static {
System.loadLibrary("hello-jni");
}
2). 调用native方法:
String result = helloJNI();
6. 运行安装到ARM模拟器上
(3)补充说明
JNIEXPORT :
在Jni编程中所有本地语言实现Jni接口的方法前面都有一个"JNIEXPORT",这个可以看做是Jni的一个标志,至今为止没发现它有什么特殊的用处。
JNICALL :
这个可以理解为Jni 和Call两个部分,和起来的意思就是 Jni调用XXX(后面的XXX就是JAVA的方法名)。
二、NDK集成开发流程(Eclipse)
(1)基本流程
1. 安装配置NDK
2. 将NDK关联到eclipse
3. 为当前应用自动生成c文件和mk文件
4. 定义naitve方法
5. 实现native方法对应的JNI函数
6. 一锤编译生成so文件
7. 加载动态库, 并调用native方法
8. 运行应用安装到ARM模拟器上
(2)详细流程
1. 安装配置NDK
1). 解压NDK的zip包到非中文目录
2). 配置path : 解压后NDK的根目录----->ndk-build
2. 将NDK关联到eclipse
Window-->Preferences-->Android-->NDK-->配置NDK的根目录
3. 为当前应用自动生成c文件和mk文件
1). 选中当前应用右键-->Android Tools-->Add Native Support
2). 将生成的.cpp文件改为.c文件
3). 修改mk文件: 将.cpp改为.c
4. 配置关联jni.h (见"配置关联jni.h文件"截图)
1). 选中当前应用右键-->Properties-->C/C++ General-->Paths and Symbols
2). 选择add-->选择File System-->选择文件夹android-ndk-r9\platforms\android-18\arch-arm\usr\include
3). 点击ok-->点击apply
5. 定义naitve方法
public native String helloNDK();
6. 实现native方法对应的JNI函数
1). 使用javah命令, 生成JNI头文件, 将其复制到jni文件下
2). 在c文件中实现h文件中的函数声明
3). 利用* 的NewStringUTF()函数, 返回字符串
7. 一锤编译生成so文件
1). 使用工具栏中的"Build"工具点击锤子按钮生成
2). 文件路径: /libs/armeabi/libNDKTest.so
8. 加载动态库, 并调用native方法
static {
System.loadLibrary("NDKTest");
}
String result = helloNDK();
9. 运行应用安装到ARM模拟器上
(3)补充说明
1.修改C函数, 不需要再单独编译生成so文件, 可直接运行安装
2.APK只是将so打包了, 本质并不需要jni文件夹下的相关文件
3.多平台交叉编译:arm、intel、mips
1>. 参照NDK文档: APPLICATION-MK.html
2>. 在jni文件夹下创建: Application.mk
APP_ABI := all
3>. 编译时会生成多个so文件来支持不同类型的CPU
4>. 不同CPU的说明
armeabi: 是指的该so库用于ARM的通用CPU,armeabi通用性强,但速度
armeabi-v7a: CPU支持硬件浮点运算, 能充分发挥v7a CPU的能力,
x86: 用于Intel的CPU
mips : 另一种CPU, 用得特别少
4.Android.mk详细介绍
#必须定义好LOCAL_PATH变量。它用于在开发树中查找源文件
#宏函数’my-dir’,由编译系统提供,用于返回当前路径(包含c/c++文件)
LOCAL_PATH := $(call my-dir)
#清除除LOCAL_PATH之外的LOCAL_XXX变量
#CLEAR_VARS由编译系统提供
include $(CLEAR_VARS)
#以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的
#编译会产生的链接库文件(lib+名称+.so): libtest2-jni.so
LOCAL_MODULE := test2-jni
#指定将要编译打包进模块中的C或C++源代码文件
#如果有多个, 以空格隔开
LOCAL_SRC_FILES := test2.c
#编译生成动态库(也就是.so文件)
include $(BUILD_SHARED_LIBRARY)
#编译生成静态库(也就是.a文件)
#include $(BUILD_STATIC_LIBRARY)
(4)重要配置
1.编写Android.mk
2.配置关联jni.h文件
3.编写Application.mk
三、NDK集成开发流程(Android Studio)
1. 安装配置NDK
1). 解压NDK的zip包到非中文目录
2). 配置path : 解压后NDK的根目录----->ndk-build
2. 给AS配置关联NDK
1). local.properties中添加配置
ndk.dir=G\:\\android-ndk-r10
2). gradle.properties中添加配置
android.useDeprecatedNdk=true
3. 编写native方法:
public class JNIS {
public native String helloJNI();
}
4. 定义对应的JNI
1). 在main下创建jni文件夹
2). 生成native方法对应的JNI函数声明头文件: 命令窗口中, 进入java文件夹
执行命令: javah com.atguigu.jnitests2.JNIS
生成头文件: com_atguigu_jnitests2_JNIS.h
函数声明: JNIEXPORT jstring JNICALL Java_com_atguigu_jnitests2_JNIS_helloJNI(JNIEnv *, jobject);
3). 将生成的头文件转移到jni文件夹下
4). 在jni下定义对应的函数文件: test.c
#include "com_atguigu_jnitests2_JNIS.h"
JNIEXPORT jstring JNICALL Java_com_atguigu_jnitests2_JNIS_helloJNI
(JNIEnv * env, jobject jobj) {
return (*env)->NewStringUTF(env, "Hello from C");
}
5). 在jni文件夹下创建一个空的C文件: empty.c
说明: 这是AS的bug, 必须至少2个C文件才能通过编译
5. 指定编译的不同CPU
defaultConfig {
ndk{
moduleName "HelloJni" //so文件: lib+moduleName+.so
abiFilters "armeabi", "armeabi-v7a", "x86" //cpu的类型
}
}
6. 编译生成不同平台下的动态链接文件
1). 执行rebuild, 生成so文件
2). so文件目录: build\intermediates\ndk\debug\lib\.....
7. 调用native方法:
1). 在native方法所在的类中加载so文件
static {
System.loadLibrary("HelloJni");
}
2). 在Activity中调用native方法:
String result = new JNIS().helloJNI();
Log.e("TAG", "result="+result);