NDK简介
Android NDK全称native Development Kit,它跟SDK差不多,也是一个开发工具包,所不同的就是NDK是一种基于原生程序接口的开发工具,通过NDK我们可以在Android开发中调用c/c++代码。
那什么情况下要用到NDK呢?
- 对速度要求高的应用程序,用c/c++写的代码在执行效率上肯定要比java要高的。
- 对安全性要求高的程序,apk中的java代码很容易被反编译,而c/c++的代码反编译的难度较大。
所谓事物都是有两面性的,NDK开发也有它的缺点,就是开发效率问题,这个问题也是c/c++语言相对java语言的缺点。
NDK在 Android Studio中的配置
Android Studio 1.3之后已经初步开始支持NDK的开发了,目前我使用的版本是Android Studio 1.5.1。首先打开File->Setting然后搜索Android SDK
选择SDK Tools把最后两个打上勾(Android NDK和LLDB),点击OK。
下载完成后会在你原来的SDK目录下多出一个ndk-bundle目录,下面我们就用NDK写一个hello world程序。
新建一个工程,我这取名叫FirstJni。
2.右键工程名字->Open Module Setting,在Android NDK Location那把ndk-bundle的路径设置上去。
- 在最外层的build.gradle文件中加上一个插件
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.5.0'
classpath 'com.android.tools.build:gradle-experimental:0.4.0'
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
接下来要修改内层的gradle文件了,内层gradle文件相对改动较大,语言的描述方式都发生了改变,首先就是将第一行的插件修改一下。
apply plugin: 'com.android.application'
替换为
apply plugin: 'com.android.model.application'
然后用model标签把原来的代码包裹住,这里需要注意的是dependencies标签要放到model外面,否则就会出错。
model {
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "com.example.hao.firstjni"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
}
下面就是一些细节的东西了,
- 在原来的gradle文件都是用空格来区分变量和值,现在要全部换成等号。
- defaultConfig替换成defaultConfig.with。
- minSdkVersion替换成minSdkVersion.apiLevel,targetSdkVersion替换成targetSdkVersion.apiLevel。
- buildTypes替换成android.buildTypes同时要把buildTypes标签放到android标签外面。
最后还要在model里面增加一个ndk的标签 ,在这个标签下主要设置一些ndk的配置信息,这里我只设置了一个名字。
android.ndk {
moduleName = "libHelloJni"
/*
* Other ndk flags configurable here are
* cppFlags.add("-fno-rtti")
* cppFlags.add("-fno-exceptions")
* ldLibs.addAll(["android", "log"])
* stl = "system"
*/
}
这里写代码片
这样就基本改完了,下面是改完后的gradle文件,
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion = 23
buildToolsVersion = "23.0.2"
defaultConfig.with {
applicationId = "com.example.hao.blur"
minSdkVersion.apiLevel = 15
targetSdkVersion.apiLevel = 23
}
}
/*
* native build settings
*/
android.ndk {
moduleName = "libHelloJni"
/*
* Other ndk flags configurable here are
* cppFlags.add("-fno-rtti")
* cppFlags.add("-fno-exceptions")
* ldLibs.addAll(["android", "log"])
* stl = "system"
*/
}
android.buildTypes {
release {
minifyEnabled=false
proguardFiles.add(file('proguard-rules.txt'))
}
}
android.productFlavors {
// for detailed abiFilter descriptions, refer to "Supported ABIs" @
// https://developer.android.com/ndk/guides/abis.html#sa
create("arm") {
ndk.abiFilters.add("armeabi")
}
create("arm7") {
ndk.abiFilters.add("armeabi-v7a")
}
create("arm8") {
ndk.abiFilters.add("arm64-v8a")
}
create("x86") {
ndk.abiFilters.add("x86")
}
create("x86-64") {
ndk.abiFilters.add("x86_64")
}
create("mips") {
ndk.abiFilters.add("mips")
}
create("mips-64") {
ndk.abiFilters.add("mips64")
}
// To include all cpu architectures, leaves abiFilters empty
create("all")
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
}
下面我要新建一个目录,这个目录用来存放jni的代码,
接下来我们新建一个类Test,正式开始调用jni,
public class Test {
public static native String getString();
}
我们可以将返回值用Textview展示出来
public class MainActivity extends AppCompatActivity {
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView= (TextView) findViewById(R.id.text);
textView.setText(Test.getString());
}
}
native方法本来就是调用本地的c/c++方法的,所以现在我们就开始写c/c++代码,实际上Android studio是可以自己生成的,
然后我们看一下jni目录,发现多了一个c文件
#include <jni.h>
JNIEXPORT jstring JNICALL
Java_com_example_hao_firstjni_Test_getString(JNIEnv *env, jclass type) {
// TODO
return (*env)->NewStringUTF(env, returnValue);
}
我们稍微修改一下返回值
#include <jni.h>
JNIEXPORT jstring JNICALL
Java_com_example_hao_firstjni_Test_getString(JNIEnv *env, jclass type) {
// TODO
return (*env)->NewStringUTF(env, "Hello World");
}
接下来就是最后一步了,在调用jni的地方加载library,在我们的代码中是在Test类中调用的,所以就在Test中加载
public class Test {
static {
System.loadLibrary("libHelloJni");
}
public static native String getString();
}
下面是运行效果图了,
大功告成,这里我们主要介绍了配置环境的过程和一个简单的jni调用,如果你想深入了解NDK的内容了,可以参考官方sample,当然还要学好c/c++啦。