开头
The Android NDK is a toolset that lets you implement parts of your app using native-code languages such as C and C++. For certain types of apps, this can help you reuse code libraries written in those languages.
实现在你的Android应用中调用C程序实现一些功能。那为什么要在Java开发中使用C语言呢?
代码的保护。由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大。
可以方便地使用现存的开源库。大部分现存的开源库都是用C/C++代码编写的。
提高程序的执行效率。将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率。
便于移植。用C/C++写得库可以方便在其他的嵌入式平台上再次使用。
PS:资料来源
虽然关于NDK开发的学习资料不多,Google官方并很多关于NDK开发文档,但竟然NDK开发包那必然有它的意义。所以我们有必要对NDK开发有个初步认识。这节主要搭建NDK开发环境并在应用中调用native函数方法。
开发环境搭建
从ndk-7后,谷歌已经改良了ndk的操作,不需用使用cygwin来交叉编译,所以这里就不再讲cygwin的配置。所搭建的开发环境是Android Studio
1.在官方下载Android NDK开发包 下载地址目前最新的版本为r12b
2.添加java系统环境变量(如果Android Studio的terminal中无法使用javah指令的时候需要做此步操作)
变量 | 值 |
---|---|
CLASSPATH | .;%JAVA_HOME%lib; |
JAVA_HOME | X:XXJavajdk1.8.0_05 |
PATH | %JAVA_HOME%bin; |
3.新建Android工程,添加项目构建NDK本地路径
4.local.propertices中添加ndk.dir=c:\Android-ndk
5.gradle.properties文件中添加android.useDeprecatedNdk=true
趁热打铁,写demo实践一下
1.新建类JniFunction,实现两个native方法
public class JniFunction {
static public native String getJniString();//获取字符串
static public native int addNumber(int a,int b);//获取两个整数相加值
}
2.rebuild Project,在工程目录下app/intermediates/classes/debug下查找到JniFunction.class
3.在main目录下创建一个jni文件夹
4.打开Android Studio的terminal,使用cd定位在Android工程的app目录下输入
javah -d jni -classpath ..\..\build\intermediates\classes\debug com.xxxxxxx.xxx.JniFunction
//切记debug和com之间有空格
5.在jni文件夹中就生成了com_learnncode_learnndk_JniFunction.h的头文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_learnncode_learnndk_JniFunction */
#ifndef _Included_com_learnncode_learnndk_JniFunction
#define _Included_com_learnncode_learnndk_JniFunction
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_learnncode_learnndk_JniFunction
* Method: getJniString
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_learnncode_learnndk_JniFunction_getJniString
(JNIEnv *, jclass);
/*
* Class: com_learnncode_learnndk_JniFunction
* Method: addNumber
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_learnncode_learnndk_JniFunction_addNumber
(JNIEnv *, jclass, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
6.在jni文件夹下新建C/C++ Source File,复制h头文件中定义的函数实现函数内容。需要注意的是选择新建.c文件而不是.cpp,另外记得多添加一个无用的c文件,不然编译可能会出错。
#include "com_learnncode_learnndk_JniFunction.h"
/*
* Class: com_learnncode_learnndk_JniFunction
* Method: getJniString
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_learnncode_learnndk_JniFunction_getJniString
(JNIEnv * env, jclass obj){
return (*env)->NewStringUTF(env,"Hello Android NDK");
}
/*
* Class: com_learnncode_learnndk_JniFunction
* Method: addNumber
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_learnncode_learnndk_JniFunction_addNumber
(JNIEnv * env, jclass obj, jint a, jint b){
return a + b;
}
7.在app build.gradle添加ndk配置
defaultConfig {
applicationId "com.learnncode.learnndk"
minSdkVersion 14
targetSdkVersion 24
versionCode 1
versionName "1.0"
ndk{
moduleName "JniFunction" //设置库(so)文件名称
}
}
8.在jni调用的地方添加以下内容
static {
System.loadLibrary("JniFunction");
}
//JniFunction就是build.gradle中NDK的文件名
新增内容补充16.10.21
-
1.so文件的生成
在app build.gradle中设置ndk生成so文件库文件名ndk{ moduleName "JniFunction" //设置库(so)文件名称 abiFilters "armeabi","armeabi-v7a","x86" }
编译项目后在项目目录下ndk文件中就能看到生成的so文件
ABI:指应用基于哪种指令集来进行编译,ABI总共有四种,分别是armeabi、armeabi-v7a、mips、x86,它们都是表示cpu的类型。
安卓支持三类处理器(CPU):ARM、Intel和MIPS。ARM无疑被使用得最为广泛。Intel因为普及于台式机和服务器而被人们所熟知,然而对移动行业影响力相对较小。MIPS在32位和64位嵌入式领域中历史悠久,获得了不少的成功,可目前Android的采用率在三者中最低。
2.Android studio2.2环境下目录变化
更新了Android Studio之后发现加载目录发现了变化,原来的Jni文件放置在了单独的文件目录下
Project
Android
新增内容补充16.11.09
Android项目调用.so文件方法:在src/main/目录下新建jniLibs文件夹把ndk abiFilters生成的so文件拷贝在此目录下,再在build.gradle defultConfig中配置jniLibs路径,看过其他人写的默认写的是libs好像也是可运行的,这里我还是填上正式新建时的路径
sourceSets.main{
jniLibs.srcDirs "src/main/jniLibs"
}
结尾及成果展示
NDK开发环境的搭建算不上特别难,就是麻烦了些。之前看别人的教程说NDK r10b版本是比较稳定的,我使用的是r12b也能编译成功,目前看来还是可以使用的。这节先为NDK开发开一个头,其中也没详细讲解关于NDK开发的语法等内容。学习NDK的道路还是任重而道远啊。附上google官方的NDK开发Demo实例
本节Demo项目地址
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。