实现:点击按钮,实现java与Native方法互调
1)
编写JNI测试代码
public class JNITest {
static {
System.loadLibrary("Hello");
}
public native String test();
}
2)生成JNITest对应的c文件,实现交互
A:生成.c文件
javah -jni 包名.类名
把生成的.h文件重命名并改后缀为.c,这里名称要和JNITest类中的System.loadLibrary("Hello");
参数命名一致,故改名为Hello.c
B:创建jni目录,创建必要文件
main
目录下新建jni文件,创建Adnroid.mk和Application.mk,刚才生成的Hello.c也移动至jni目录下
Android.mk文件是有语法的,详情自行查阅Android.mk语法,
Android.mk文件内容如下:固定写法
# 号为注释
#定义必须以LOCAL_PATH为开始,my-dir 则由Build System提供,固定写法
LOCAL_PATH := $(call my-dir)
#CLEAR_VARS 变量由Build System提供。并指向一个指定的GNU Makefile,负责清理工作
include $(CLEAR_VARS)
#LOCAL_MODULE模块必须定义,以表示Android.mk中的每一个模块。名字必须唯一且不包含空格
LOCAL_MODULE := Hello
#LOCAL_SRC_FILES变量必须包含将要打包如模块的C/C++ 源码。
LOCAL_SRC_FILES := Hello.c
# 注明是动态编译,静态编译为BUILD_STATIC_LIBRARY
include $(BUILD_SHARED_LIBRARY)
Application.mk内容:
# 支持的CPU架构,也可以指定生成的架构,指定则使用下面注释的代码
APP_ABI :=all
# APP_ABI :=armeabi-v7a x86 arm64-v8a
注意,生成的Hello.c需要更改,这里贴出对应方法生成的代码,改造如下
JNIEXPORT jstring JNICALL Java_zz_hao_jni_JNITest_test
(JNIEnv* env, jobject jobj){
char* text = "hello,调用JNI成功~";
return (*env)-> NewStringUTF(env,text);
};
C:build.gradle文件中增加配置
android{
.....
//每次编译中执行Android.mk并使用ndk编译生成so文件并打入APK包,本地必须要下载ndk
//如果自己生成so文件,则不需要一下代码
externalNativeBuild {
ndkBuild {
path file('src/main/jni/Android.mk')
}
}
}
至此,jni相关配置已完成
3)
MainActivity中调用测试
findViewById(R.id.btn_jni).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, new JNITest().test(), Toast.LENGTH_SHORT).show();
}
});
生成so文件,根据已经编写好的jni文件来生成
可能有的小伙伴会有疑问,上面的jni代码,对我们来讲,多少有些陌生,平时项目中也没有见到有jni文件夹、Android.mark、xxxx.c…等等一些c代码。确实,项目中一般不会出现这些文件,取而代之的是so文件,大家对so文件一定不陌生,引入一些三方库,比如百度地图、音乐播放器、等等一些,这些三方库在lib文件夹下,会有不同架构的so文件。
那么这些so文件是怎么产生的呢,就是根据上面编写的jni,生成的so文件
so文件打包的都是C代码,jar包则是.class文件,怎么理解jni,so库,ndk呢,下面举例说明,促进我们的理解
jni代码好比是小麦,so文件是面粉,NDK则是加工面粉的机器。
中午想吃顿面条,去超市买点面粉回来自己做。这个时候自然超市给的是面粉,不会给点小麦,在给个磨面的机器,让我们回家自己磨面吧。所以一般我们使用的时候,也都是用的so文件,第三方已经用NDK工具把jni代码加工成了so文件,提供给我们。
接下来我们要自己用磨面机来把小麦加工成面粉
正文:生成so文件
1) 首先我们要下载NDK(磨面之前必须得有磨面机嘛),并配置好环境变量,在黑窗口运行命令ndk-build
来验证是否配置正确
2)在jni目录下运行黑窗口,执行ndk-build
命令,这里会执行Android.mk文件。执行完成,会自动生成lib文件和相应的so文件
正文:生成jar包
我们可以把本示例中的JNITest类生成jar包
首先,对应一下目录结构,该jni相关代码都是在一个Library中,如果要单独类生成jar包,则需要新建一个Library,在该Library的build.gradle下配置以下代码
android{
//生成jar包
task makeJar(type: Copy) {
delete 'build/outputs/test.jar'
from('build/intermediates/packaged-classes/release/') //jar文件来源
into('build/libs/') //生成路径
include('classes.jar')
rename('classes.jar', 'test.jar') //命名为network.jar
}
makeJar.dependsOn(build)
}
执行命令 gradlew makeJar
编译完成后在build-libs目录下,可以看到我们生成的jar包
报错:
ERROR: ABIs [armeabi] are not supported for platform. Supported ABIs are [armeabi-v7a, arm64-v8a, x86, x86_64].
配置了armeabi架构,ndk在编译的时候不支持,只支持 [armeabi-v7a, arm64-v8a, x86, x86_64].这四种的哪个架构。
很有可能A电脑没有报错,B电脑报这个错,(NDK版本不一致导致)因为从NDK r17版本开始,已经不再支持armeabi、mips、mips64这三种ABI了。如果要用armeabi,需要下载小于r17的ndk版本