Android Studio上使用JNI
题记
做了一个C程序,需要移植到安卓上,移植到安卓上就需要使用JNI(Java Native Interface),这里做一个Android Studio(AS)上使用JNI的记录。版本和环境信息如下,不同版本的AS操作有较大区别,也只能踩坑试试才知道行不行:
步骤
Step 1. 下载NDK
NDK(Native Developer Kit)是谷歌给开发人员的工具包,感觉主要功能就是能够更容易使用JNI的工具。
下载之后解压,并将解压后的目录加入环境变量,我的路径是G:\android-ndk-r21
。
在终端输入 ndk-build 验证一下配置是否成功:
Step 2. 新建项目
新建一个项目,不需要勾选Include C++ support
.,新建之后调整成Project
视图。
Step 3. AS环境配置
配置NDK路径
Ctrl+Alt+Shift+S
打开配置,设定NDK路径:
配置build.gradle文件
打开app文件夹中的build.gradle文件,在defaultConfig中输入以下代码,其中moduleName
与最后生成的.so文件的文件名有关,即lib[moduleName].so
,且Java源文件中loadLibrary方法的参数就是这个moduleName的名字。abiFilters
表示CPU的型号,不过好像可以删掉,不删的话反而在调试的时候可能手机型号不支持。
|
|
同样在这个build.gradle文件中,在buildTypes下输入以下代码。
|
|
ref. Error: Your project contains C++ files but it is not using a supported native build system.
新建Android.mk和Application.mk
跳过这步在后续步骤中报的错(图示第一次输入命令ndk-build
是没有这两个.mk文件的情况):
在jni目录下新建Android.mk和Application.mk,输入内容如下:
Android.mk:
|
|
Application.mk:
|
|
Step 4. 编写JNI文件,并生成.so文件
1. 创建JAVA源文件,编写 native 方法
如图示创建一个java文件,写入代码(注意修改代码中package的名称),然后复制这个文件的路径,命令行切换到main/java目录中.
输入命令javah -d ../jni com.xxx.xxx.JNI
,其中com.xxx.xxx.JNI
需要替换成你复制的路径。
p.s. 新版本的jdk没有javah的命令,有资料说可以用javac -h这种命令,但是我尝试之后并没有解决,所以我的建议是直接换成jdk8,而且安装也很简单
命令执行完之后,就会生成一个.h文件,在同级目录创建一个名字相同的.c文件,输入以下代码用于测试,注意函数名要和.h文件的函数名一致:
|
|
2. 生成.so文件
方法一. 在jni目录中,执行ndk-build
命令。
执行结束后会生成libs
和obj
文件夹,里面就是.so文件,需要创建一个名为jniLibs
的文件夹,然后把libs中的内容全部复制进这个文件夹里面,才能使用.so文件。
方法二. AS菜单栏Build->Rebuild Project
Rebuild这个方法好像不太行,不确定问题在哪里,可能与build.gradle文件jniLibs.srcDirs或者jni.srcDirs的配置有关。
对build.gradle文件进行修改:
|
|
然后rebuild,生成.so文件在app/build/intermediates/ndkBuild/debug/obj/local(实际上还有其他2个目录也生成了.so文件"D:\AndroidStudioProjects\JNIProj\app\build\intermediates\transforms\stripDebugSymbol\debug\0\lib\x86\libmyNDK.so"和"D:\AndroidStudioProjects\JNIProj\app\build\intermediates\transforms\mergeJniLibs\debug\0\lib\x86\libmyNDK.so”)路径中(看参考资料,可能有的在intermediates/ndk路径里面,我这里没有ndk文件夹生成)。
与方法一不同,使用这个方式不需要复制.so的位置,可能默认的jnilib就是这个路径。
Step 5. 修改MainActivity并执行程序
|
|
结果
参考资料
- JNI 开发详细初体验(Mac Android Studio 3.1+) - 掘金 https://juejin.im/post/5b90a7c1e51d450e697311de
- 尚硅谷Android视频教程《JNI》【注:AS版本很老】 https://www.bilibili.com/video/BV1qW411L7oY?p=35
- Android+真机调试 https://www.cnblogs.com/xqz0618/p/12725515.html
- Android之JNI实现函数中LOG打印 【注:LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog要写在include $(CLEAR_VARS)的后面】https://blog.csdn.net/jjunjoe/article/details/7020236
其他事项
Android.mk添加目录中所有源文件
ref. Android.mk添加目录中所有源文件
使用场景:com_whu_jniproj_JNI.c中include了cljtest.h,并且使用了cljtest中的函数。
报错:
- 如果Android.mk为 LOCAL_SRC_FILES := com_whu_jniproj_JNI.c时,Build就会报错:
|
|
- 如果Android.mk为 LOCAL_SRC_FILES := cljtest.c时,Build通过,报错:
- 如果Android.mk为 LOCAL_SRC_FILES := cljtest.c com_whu_jniproj_JNI.c时,不报错。
调试方法,在android.mk中使用下列代码,然后在终端中使用ndk-build编译:
|
|
由于ref中的其他方案都报错,只能使用下面这种,注意这个方法不会递归找.c文件,是单目录的,不过也比一个一个加方便多了:
|
|