讀完本章喷面,你可以:
- 在Android Studio上輕松搭建NDK開(kāi)發(fā)環(huán)境。
- 掌握最快捷的JNI開(kāi)發(fā)方式。
- 掌握使用.so文件開(kāi)發(fā)Android程序的技巧昆著。
一、 NDK環(huán)境搭建
-
開(kāi)發(fā)工具準(zhǔn)備
要進(jìn)行Android NDK開(kāi)發(fā)术陶,首先要下載Android NDK開(kāi)發(fā)工具凑懂。可以在AndroidStudio上面下載梧宫,也可以自己下載好了接谨,然后將NDK的路徑設(shè)置為自己下載的Android NDK開(kāi)發(fā)工具的路徑。
- Gradle的相關(guān)配置
- 我們來(lái)配置Project的build.gradle塘匣。
/*gradle插件不支持NDK脓豪,我們需要使用gradle-experimental插件。 */
dependencies {
classpath 'com.android.tools.build:gradle-experimental:0.7.0'
}
- 我們來(lái)配置Module的build.gradle忌卤。
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion = 23
buildToolsVersion = "23.0.2"
defaultConfig {
applicationId "com.lavor.ndklearning"
minSdkVersion.apiLevel 15
targetSdkVersion.apiLevel 23
versionCode 4
versionName "1.0.1"
}
}
android.ndk {
moduleName "lavor"
ldLibs.addAll(['log'])
cppFlags.add("-std=c++11")
cppFlags.add("-fexceptions")
platformVersion 15
stl 'gnustl_shared'
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles.add(file("proguard-rules.txt"))
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:recyclerview-v7:23.1.1'
compile 'com.android.support:design:23.1.1'
}
小提示
- 首先扫夜,在apply的時(shí)候我們引入的插件名稱由'com.android.application'變成了'com.android.model.application'。
- 其次驰徊,在原來(lái)android的外層加入了一個(gè)model層次笤闯。
- 再次,原來(lái)在android的里面的塊棍厂,除了defaultConfig外颗味,全部移除android塊放入model塊中與android并列,并且前面的名字加上android.勋桶。
- 然后脱衙,compileSdkVersion 23與 buildToolsVersion "23.0.2"改成 compileSdkVersion = 23和 buildToolsVersion = "23.0.2"侥猬,中間加上了=。
- 其次捐韩,添加上android.ndk塊退唠,塊中的moduleName表示C/C++代碼打包成so文件的名字。
- 再次荤胁,android.buildTypes塊中的proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'改成proguardFiles.add(file("proguard-rules.txt"))瞧预。
- 最后,注意dependencies塊依然在最外層仅政,它不在model塊中垢油。
二、 使用NDK開(kāi)發(fā)第一個(gè)JNI程序
- 在Android程序中新建一個(gè)包含native(本地)方法的NDKTest類圆丹。
package com.lavor.ndklearning;
public class NDKTest {
static {
//加載.so庫(kù)文件
System.loadLibrary("lavor");
}
public native String getString();
}
小知識(shí)
- 程序中static{}稱為靜態(tài)代碼塊滩愁,它在類初始化的時(shí)候執(zhí)行。不懂請(qǐng)猛擊>>
-
將鼠標(biāo)移動(dòng)到方法名getString上辫封,然后按下Alt+Enter快捷鍵硝枉,彈出一些解決的方法建議,點(diǎn)擊第一個(gè)Create Function...
-
此時(shí)會(huì)自動(dòng)建立一個(gè)與java目錄同級(jí)的jni目錄倦微,在jni目錄自動(dòng)建立一個(gè)c文件妻味,在c文件中實(shí)現(xiàn)了剛才的native方法。
- 然后欣福,稍稍修改一下.c文件中實(shí)現(xiàn)的native方法责球。
JNIEXPORT jstring JNICALL
Java_com_lavor_ndklearning_NDKTest_getString(JNIEnv *env, jobject instance) {
// TODO
return (*env)->NewStringUTF(env, "AndroidStudio NDK開(kāi)發(fā)最佳入門實(shí)踐");
}
補(bǔ)充說(shuō)明
- 仔細(xì)觀察可以看到c文件的方法名是遵循“Java_包名類名本地方法名”來(lái)組織的(了解到這些后,我們就可以脫離編譯器的幫助拓劝,直接去寫.c文件啦)雏逾。
- 最后在Android程序中調(diào)用JNI接口。
public class MainActivity extends Activity {
private android.widget.TextView text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.text = (TextView) findViewById(R.id.text);
NDKTest NDK=new NDKTest();
text.setText(NDK.getString());
}
}
運(yùn)行程序后界面如下:
深度總結(jié)
- 講道理凿将,我們?cè)谡介_(kāi)發(fā)時(shí)校套,不會(huì)像這樣子去開(kāi)發(fā)。因?yàn)檫@樣的話就會(huì)把我們的c代碼也暴露了出來(lái)牧抵。這明顯與JNI的安全保密機(jī)制相違背,所以侨把,正式開(kāi)發(fā)的時(shí)候犀变,我們會(huì)使用.so文件進(jìn)行全保密式的開(kāi)發(fā)。
三秋柄、 使用.so文件開(kāi)發(fā)Android程序
不知道大家有沒(méi)有記得上一章說(shuō)過(guò)获枝,使用JNI有個(gè)好處就是安全性高,JNI部分的代碼很難被反編譯骇笔。這其實(shí)是要?dú)w功于.so文件省店。下圖為.so文件的生成位置嚣崭。
具體的使用步驟是怎樣的呢?
-
新建一個(gè)Android工程懦傍,命名為:AndroidApplication雹舀。(工程名、包名粗俱、組織名任意)
-
導(dǎo)入.so文件至app/libs中说榆。
- 為了能夠調(diào)用libs文件夾下的.so資源,需在app的build.gradle的android節(jié)點(diǎn)下設(shè)置寸认。
sourceSets{
main{
jniLibs.srcDirs = ['libs']
}
}
- 新建相關(guān)類結(jié)構(gòu)签财。
package com.lavor.ndklearning;
public class NDKTest {
static {
//加載.so庫(kù)文件
System.loadLibrary("lavor");
}
public native String getString();
}
補(bǔ)充說(shuō)明
- Android端聲明native code的代碼需要嚴(yán)格按照J(rèn)NI接口來(lái)組織。(也就是說(shuō)偏塞,包名唱蒸、類名都要和.so文件中JNI名稱一致)不懂就點(diǎn)擊這里吧>>
- 函數(shù)調(diào)用。
public class DemoActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
Log.d("NDK",new NDKTest().getString());
}
}
運(yùn)行結(jié)果如下:
注意啦灸叼!此文并非原創(chuàng)油宜,算是對(duì)一波優(yōu)秀文章的總結(jié)吧。筆者希望通過(guò)這種方式激勵(lì)自己學(xué)習(xí)怜姿,也期待可以幫到正在學(xué)習(xí)NDK的你慎冤。歡迎指出本文的BUG,共勉2茁R系獭!5痢披诗!
參考資料