盡管Android Studio已經(jīng)越來越流行了,但很多人還是習(xí)慣于Eclipse或源碼環(huán)境下開發(fā)JNI應(yīng)用。個人認為使用Android Studio作NDK開發(fā)是必然趨勢,所以本文將簡單介紹如何在Android Studio上實現(xiàn)NDK開發(fā)。
簡介
JNI
JNI 是Java Native Inteface的縮寫,是Java中定義的一種用于連接Java和C/C++接口的一種實現(xiàn)方式。
NDK
NDK 是 Native Developmentit的縮寫,是Google在Android開發(fā)中提供的一套用于快速創(chuàng)建native工程的一個工具。
使用這個工具可以很方便的編寫和調(diào)試JNI的代碼。
NDK可從官網(wǎng)或AndroidDevTools(個人網(wǎng)站)下載。
Gradle
Gradle 是一個基于Apache Ant和Apache Maven概念的項目自動化建構(gòu)工具。它使用一種基于Groovy的特定領(lǐng)域語言(DSL)來聲明項目設(shè)置。
以往Android NDK開發(fā)需要在Eclipse或源碼環(huán)境下,建立并配置Android.mk和Application.mk,且還要通過java命令生成.h頭文件,才能編譯生成so庫。但在Android Studio中這些步驟都不需要,因為Gradle足夠強大,只需配置Gradle即可編譯生成so庫。
gradle-experimental插件
在2015年5月的Google I/O大會上, Google宣布Android Studio開始支持NDK開發(fā),通過和JetBrains的合作,將Clion整合進了Android Studio 1.3,并免費支持NDK C++開發(fā)。
同年7月,在Android Studio 1.3版本上添加了gradle-experimental
插件,該插件支持NDK開發(fā)和調(diào)試,且?guī)в写a不全和重構(gòu)等高級功能。
CAVEAT: Note that this plugin is a preview of the plugin for feedback on performance and NDK integration. The Gradle API for the new component model is not final, which means each plugin will only work with a specific version of Gradle.
Additionally, the DSL may also change.
目前這個插件是預(yù)覽插件,并不是正式的。意味著插件只能運行在特定的Gradle版本上。并且DSL(領(lǐng)域特定語言)也要改變。
使用Experimental插件進行NDK開發(fā)
使用Experimental插件的必要條件
1、Gradle-2.5或更高版本
2、Android Studio 1.3 RC1或更高版本
3、Android NDK r10e 或更高版本
4、Build Tools 19.0.0 或更高版本
每個版本的experimental插件需要特定的Gradle版本
Plugin Version | Gradle Version |
---|---|
0.1.0 | 2.5 |
0.2.0 | 2.5 |
0.3.0-alpha3 | 2.6 |
0.4.0 | 2.8 |
0.6.0-alpha1 | 2.8 |
0.6.0-alpha5 | 2.10 |
0.7.0-alpha1 | 2.10 |
NDK開發(fā)步驟
1、新建一個Android標準工程
2、按F4打開工程配置
3、使用experimental插件需要對以下三個文件做修改:
./build.gradle
./app/build.gradle
./gradle/wrapper/gradle-wrapper.properties
./gradle/wrapper/gradle-wrapper.properties
將distributionUrl改用gradle-2.10版本
distributionUrl=https\\://services.gradle.org/distributions/gradle-2.10-all.zip
./build.gradle
使用com.android.tools.build:gradle-experimental
代替 com.android.tools.build:gradle
buildscript {
repositories {
jcenter()
}
dependencies {
//classpath 'com.android.tools.build:gradle:2.0.0'
classpath "com.android.tools.build:gradle-experimental:0.7.0-alpha4"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
./app/build.gradle
這部分改動比較大,修改及注釋如下:
// 用com.android.model.application 代替 com.android.application
apply plugin: 'com.android.model.application'
// 將原來的配置用 model{}包起來
model {
android {
// 取值必須使用 “=” 形式
// 否則會報 “Error:Cause: org.gradle.api.internal.ExtensibleDynamicObject” 錯誤
compileSdkVersion = 23
buildToolsVersion = '23.0.2'
defaultConfig {
// 取值必須使用 “=” 形式
applicationId = "com.connorlin.jnitest"
//這里要注意是 xxSdkVersion.apiLevel
// 否則會報 “Unable to load class com.android.build.gradle.managed.ProductFlavor_Impl”錯誤
minSdkVersion.apiLevel = 15
targetSdkVersion.apiLevel = 23
versionCode = 1
versionName = "1.0"
}
// 配置NDK
ndk {
// 生成so的名字,是必須的
moduleName ="JNITest"
toolchain = 'clang'
CFlags.add('-std=c99')
// 添加依賴庫
ldLibs.addAll(['android','OpenSLES', 'log'])
// 生成不同abi體系的so庫
abiFilters.addAll(['armeabi', 'armeabi-v7a', 'arm64-v8a',
'x86', 'x86_64',
'mips', 'mips64'])
}
buildTypes {
release {
minifyEnabled = false
// 這里注意:使用proguardFiles.add()方法
proguardFiles.add(file('proguard-rules.txt'))
}
}
}
}
4、在Java文件(這里以JNIActivity為例)中添加代碼
static {
System.loadLibrary("JNITest");
}
public native String testJni();
此時,native方法標紅,提示如下:
在testJni()
方法上按快捷鍵Alt + Enter
,出現(xiàn)如下提示
按回車,會自動在main目錄下生成jni文件夾,內(nèi)含JniDemo.c:
#include <jni.h>
JNIEXPORT jstring JNICALL
Java_com_connorlin_jnitest_MainActivity_testJni(JNIEnv *env, jobject instance) {
// TODO
return (*env)->NewStringUTF(env, "returnValue");
}
你會發(fā)現(xiàn),Android Studio已經(jīng)為我們自動生成JNI方法了,你只需要再寫實現(xiàn)就可以了。
至此,最簡單的NDK開發(fā)配置完畢。
換種方式進行NDK開發(fā)
既然預(yù)覽版com.android.tools.build:gradle-experimental
支持NDK,
那么正式版com.android.tools.build:gradle
是否也可以實現(xiàn)NDK開發(fā)呢?
經(jīng)過實驗,答案是可以的!
步驟
1、新建一個Android標準工程,并在工程設(shè)置中配置NDK路徑。
2、打開 app level 的 build.gradle, 配置NDK
ndk {
moduleName "NdkJniDemo" //生成的so名字
abiFilters "armeabi", "armeabi-v7a", "x86" //輸出指定三種abi體系結(jié)構(gòu)下的so庫,可忽略
}
然后點擊右上角Sync Now, 會有如下錯誤提示:
按提示,在 gradl.properties 文件里加上android.useDeprecatedNdk=true
即可。
3、在Java文件(這里以JNIActivity為例)中添加代碼
static {
System.loadLibrary("JNITest");
}
public native String testJni();
接著在testJni()
方法上按快捷鍵Alt + Enter
并回車,
同樣,會自動在main目錄下生成jni文件夾,內(nèi)含JniDemo.c:
#include <jni.h>
但是,你會發(fā)現(xiàn)并不會自動生成JNI方法,這是因為使用experimental插件才會自動生成代碼。
那自動生成代碼該如何實現(xiàn)呢?
方法依然是使用gradle-experimental
插件,但是不同的是,在app level的build.gradle中添加com.android.tools.build:gradle-experimental
依賴。
4、在./app/build.gradle中添加gradle-experimental
依賴
dependencies {
compile 'com.android.tools.build:gradle-experimental:0.7.0'
}
再次在testJni()
方法上按快捷鍵Alt + Enter
并回車
#include <jni.h>
JNIEXPORT jstring JNICALL
Java_com_connorlin_jnitest_MainActivity_testJni(JNIEnv *env, jobject instance) {
// TODO
return (*env)->NewStringUTF(env, "returnValue");
}
你會發(fā)現(xiàn)成功自動生成JNI方法了。
副作用
這種方式有個副作用是 Run app 時可能會報錯:
此時,只要將gradle-experimental
依賴注釋掉即可正常運行,同時會保持自動生成代碼的功能,直到關(guān)閉工程。
這樣我們在需要自動生成代碼的時候,將gradle-experimental依賴再次打開即可。
NDK調(diào)試
默認情況下是不支持NDK調(diào)試的,但要支持NDK調(diào)試也很簡單,只要做些簡單配置即可。
1、打開JNI調(diào)試
2、配置Android Native - Debugger
3、下載LLDB 2.0
首次底部會報錯
點擊 Fix,提示下載LLDB 2.0,照做,下載安裝即可。
4、完成NDK調(diào)試配置,可以正常調(diào)試了。
That's all!