前言:第一次写JNI,由于搜索到的教程很多都比较旧,有些配置在新版的Android Studio 3.1+ 有点变化,因此,这里写一篇用截止2018年9月开学季最新版的Android Studio 3.1+ 版本的JNI入门教程。
1、配置环境变量
在 .bash_profile 配置文件增加以下配置:
export PATH=${PATH}:/Users/hebin.yang/Library/Android/sdk/ndk-bundle
注:以上的 ndk 路径可直接在 Android Studio -- Open module setting 打开 Module 设置页面,复制 ndk 安装路径,如图:
然后输入以下命令使修改生效:
source .bash_profile
如果报 command not found, 需要在配置文件里增加以下配置(该配置和本文的 ndk 开发无关,这是使用Mac命令行所需的配置)
export PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
到此,配置结束。可以在终端输入 ndk-build
验证一下配置是否成功,如果成功,显示如下图:
2、JNI 文件编写
(1)、 创建JAVA源文件,编写 native 方法
package com.ben.ndk.jni;
public class Encrypt {
public static native String encrypt(String source);
}
(2)、 通过 javah 命令生成 .h 文件
首先得cd 进入当前module 的 java 路径:cd ndklib/src/main/java
javah -d ../jni com.ben.ndk.jni.Encrypt
生成.h文件如图所示(jni 路径也是自动生成的)
这个自动生成的 .h 文件内容如下图所示:
其中红圈里的方法和JAVA 文件里写的 native 方法相对应,下一步需要用到。
(3)、 创建 .c 文件
直接复制黏贴一份 .h 文件副本,后缀改为 .c 即可(将.c 内容清空),如下图所示:
在 .c 文件中实现c函数:导包,并将 .h 文件里圈圈的代码复制黏贴进来,记得增加一下参数名JNIEnv * enc, jclass cls, jstring inputStr
,.c 文件的全部代码如下:
#include "com_ben_ndk_jni_Encrypt.h"
JNIEXPORT jstring JNICALL Java_com_ben_ndk_jni_Encrypt_encrypt
(JNIEnv * enc, jclass cls, jstring inputStr) {
return inputStr; //For 演示,此处忽略具体逻辑,直接返回输入的字符串
}
(4)、 在jni目录下创建 Android.mk 文件
写入以下配置:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := NDKTest
LOCAL_SRC_FILES := com_ben_ndk_jni_Encrypt.c
include $(BUILD_SHARED_LIBRARY)
注:其中需要改动的有两点
a. LOCAL_MODULE := NDKTest
这里的 NDKTest 自己命名,这是将要生成的 .so库的名字,会自动加上 lib前缀,最终生成库文件:libNDKTest.so
引用该库的代码:System.loadLibrary("NDKTest");//这里用到的就是 NDKTest
b. LOCAL_SRC_FILES := com_ben_ndk_jni_Encrypt.c
这里也要替换为你自己的 .c 文件名。
(5)、 在jni目录下创建 Application.mk 文件
写入以下配置:
APP_ABI := all
这个配置会生成所有主流 ABI 类型的 .so 库。
至此,所有 ndk 相关的文件创建完毕,如下图所示:
(6)、 在当前 Module 下的 build.gradle 文件配置
a. 在 defaultConfig{} 下增加以下配置:
ndk {
moduleName "NDKTest" //System.loadLibrary("NDKTest");
}
b. 备注一下
很多教程比较旧,都说需要在 gradle.properties 文件里加上下面的配置:
android.useDeprecatedNdk=true
以上配置在Android Studio 3 之后就废弃了(不需要加上)。
(7)、 最后一步
a. 在终端cd 进入前面生成的jni路径 cd ndkhelloworld/src/main/jni
,即我们上面写的 c 源文件的目录
b. 输入以下命令,生成 .so 库:
ndk-build
如果成功,打印如图所示:
同时,生成的 .so 库如下图所示(生成会稍微延迟一下,1分钟内):
备注:会同时生成 libs 和 obj 两个带有 .so 库的目录,只需要保存 libs 目录即可。
3、调用 .so 库
这里为了更详细的演示,我们直接创建一个新module来演示 .so 库的调用。
(1)、 创建jniLibs 目录,复制以上生成的整个 libs 目录下的.so文件到该目录下,如图:
(2)、 在 java 源文件下创建一个和上一步骤写的 Encrypt native 方法类所在包名 一致的包名和 java 文件,如图:
注意:这个路径必须一致,否则报错,编译器是根据这个路径去调用 .so 库的 c 代码。
在创建的 Encrypt.java 中,加载 .so 库,代码如下:
package com.ben.nkd.jni; //包名要和创建 .so 库所写的Encrypt.java 类所在包名一致。
//类名也要一致
public class Encrypt {
static {
System.loadLibrary("NDKTest");
}
public static native String encrypt(String source); //这个方法和创建 .so 库所写的 native 代码一致。
}
(3)、 测试
结果如图: