本文已授权微信公众号:鸿洋(hongyangAndroid)在微信公众号平台原创首发。
这一篇文章主要介绍在AndroidStudio环境如何搭建JNI开发环境,并通过一个helloword的方式了解进行JNI开发的步骤。
开发编译环境
- AndroidStudio 2.1.2
- SDK 23.0.3
- NDK 12.1.2977051
NDK安装与配置
- 首先创建一个Android项目工程,File-->New-->New Project,一路下一步就好,最后finish创建完成项目.
- 打开Project Structure,默认Android NDK location是没有的,这时候如果已经下载有了NDK,那你就可以直接选择下载好的NDK路径设置到输入框,否则点击download进行下载,下载完成后默认安装在sdk根目录,命名为ndk-bundle。 // 我的SDK地址为
D:\android-sdk
.

- 添加系统环境变量,新建变量名
ANDROID_NDK_HOME
,对应变量值为ndk根目录地址 ,如D:\android-sdk\ndk-bundle
,然后将ANDROID_NDK_HOME
添加到Path中去(%ANDROID_NDK_HOME%;)
,确定OK. - 至此,会在项目的
local.properties
文件下添加ndk的目录地址,如果没有自动添加,可以收到加上一行:ndk.dir=D\:\\android-sdk\\ndk-bundle
,由于ndk版本和IDE的版本可能存在不一致性,所以编译时会检查ndk的过时性,这个时候如果报警了,可以在gradle.properties
文件下添加一行:android.useDeprecatedNdk=true
.到此,NDK的安装和配置就完成.
HelloWord
- 在main下创建jni目录,该目录用于存放jni文件,主要包含c文件以及头文件等等。
- 在MainActivity中创建native方法,遗憾的是当前版本AndroidStudio暂不支持c文件的连接和很好的根据提示自动创建c方法,所以只好手动添加模板。

- 在jni目录下创建c文件
hello.c
,并创建MainActivity中的sayHello方法:

- 首先,添加头文件,类似java中的导包,这里首先必加的是jni.h,这是java与c/c++之间语言转换的核心文件,具体可以查看ndk目录下
D:\android-sdk\ndk-bundle\platforms\android-23\arch-arm\usr\include\jni.h
,另一个这里需要处理字符串,所以还需要包含string.h的头文件,同样可以在上面目录include中找到. - 然后,添加java中native方法的实现。
jstring
:返回值类型,Java_com_lzj_demojni_MainActivity_sayHello(JNIEnv *env, jobject jobj)
:实现的方法名,固定格式,Java_所要实现的方法名所在java类用下划线替代点的引用地址_方法名(JNI环境变量 env,JNI环境对象 jobj)
;其中env和jobj方法中可能用不到,但也必须申明,源码中是这样说明的,大概作用就是env作为了一个JNINativeInterface指针,是java与c/c++之间的一个功能环境变量中间桥梁。

- 具体实现,
(*env)->NewStringUTF(env, "Hello from JNI !");
该行代码返回字符串Hello from JNI !,NewStringUTF
方法可以查阅jni.h,可以看到具体的申明如下:


- Gradle配置,在build.gradle中加入你ndk moduleName

这里的moduleName是在代码中loadLibrary所填写的名称,也是生成so包的lib后面的名称,与jni目录下的c文件名称没有关系,
- 代码中调用,首先需要在静态代码块中loadLibrary,然后可以调用申明的native方法.

结束语
到这里,就完成了JNI编程的HelloWord,使用项目内部文件的方式进行JNI编程的基本步骤大致就是这样,下一篇文章将介绍如何编译成so包以及编译过程中的一些配置和常见的坑。
网友评论
> Error: Your project contains C++ files but it is not using a supported native build system.
Consider using CMake or ndk-build integration with the stable Android Gradle plugin:
https://developer.android.com/studio/projects/add-native-code.html
or use the experimental plugin:
http://tools.android.com/tech-docs/new-build-system/gradle-experimental.
请问那Jni目录怎么还能放在main目录下呢
> com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command 'D:\ProgramTools\Package\ndk\android-ndk-r10b\ndk-build.cmd'' finished with non-zero exit value 2
这里手动添加模板是怎样的操作呢,现在虽然可以正常编译,但是红色看着不是很爽,求科普下
Error:Execution failed for task ':app:compileDebugNdk'.
> Error: NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin. For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental. Set "$USE_DEPRECATED_NDK=true" in gradle.properties to continue using the current NDK integration.
// sourceSets {
// main {
// jniLibs.srcDirs = ['libs']
// }
// }
MainActivity 里面 sayHello() connot resolve corresponding JNI finction
不管他运行时Native method not found