個人博客地址 http://dandanlove.com/
記得前年開始自己在項目中使用第三方so庫的時候就接觸NDK編程開發(fā)了,只不過哪個時候自己是輸出了"Hello Wrold~!"。如今一年多的時間過去了,回頭拾起之前的代碼再次翻看。
概念
在閱讀文章之前我們首先了解幾個概念
JNI
JNI是Java語言提供的Java和C/C++相互溝通的機制,Java可以通過JNI調(diào)用本地的C/C++代碼,本地的C/C++的代碼也可以調(diào)用java代碼。JNI 是本地編程接口,Java和C/C++互相通過的接口。Java通過C/C++使用本地的代碼的一個關(guān)鍵性原因在于C/C++代碼的高效性。
NDK
NDK是一系列工具的集合。它提供了一系列的工具,幫助開發(fā)者快速開發(fā)C(或C++)的動態(tài)庫,并能自動將so和java應(yīng)用一起打包成apk。這些工具對開發(fā)者的幫助是巨大的。它集成了交叉編譯器,并提供了相應(yīng)的mk文件隔離CPU、平臺、ABI等差異,開發(fā)人員只需要簡單修改mk文件(指出“哪些文件需要編譯”、“編譯特性要求”等),就可以創(chuàng)建出so。它可以自動地將so和Java應(yīng)用一起打包,極大地減輕了開發(fā)人員的打包工作。
ARM
早起Android只支持ARMv5的CPU架構(gòu),而發(fā)展到現(xiàn)在,支持一下7種架構(gòu):
arm.jpg
世界在進步,cup在arm基礎(chǔ)上不斷升級優(yōu)化。每種架構(gòu)關(guān)聯(lián)著一種ABI(application binary interface應(yīng)用程序二進制接口),所以每一種架構(gòu)都對應(yīng)一個.so文件,但都兼容arm。對于我們Android開發(fā)者來說,我們的app需要能在大多數(shù)手機上運行。所以要么我們所有arm類型都兼容,要么只兼容armeabi。兼容所有CPU架構(gòu)類型是在性能上比較好,但是同時它也造成了apk體積的劇增(PS:我們之前的項目因為接入so庫后導(dǎo)致apk體積劇增,最后只支持armeabi一種類型了)。
搭建環(huán)境
Java環(huán)境配置(略)
AndroidSDK環(huán)境配置(略)
NDK環(huán)境配置
本文主要講述NDK環(huán)境配置:
- 下載對應(yīng)操作系統(tǒng)的NDK
- 解壓文件(windows隨意解壓,Ubuntu解壓在bin目錄下)
-
windows環(huán)境下配置
windows-ndk.jpg - Ubuntu環(huán)境下配置
修改系統(tǒng)環(huán)境變量
sudo gedit /etc/profile
在profile文件下面添加,保存并退出
export ANDROID_NDK= ndk路徑
export PATH=$ANDROID_NDK:$PATH
source /etc/profile
查看是否配置成功
im@58user:~/StudioProjects/NDKDemo/app/src/main/java$ ndk-build -v
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
該程序為自由軟件,詳情可參閱版權(quán)條款。在法律允許的范圍內(nèi)
我們不作任何擔保,這包含但不限于任何商業(yè)適售性以及針對特
定目的的適用性的擔保。
這個程序創(chuàng)建為 x86_64-pc-linux-gnu
Android studio環(huán)境配置

以上是下邊使用Android studio 進行NDK開發(fā)的基礎(chǔ),下邊我們進入真正的開發(fā)環(huán)節(jié)。
NDK開發(fā)環(huán)節(jié)
native方法的定義
為了方便,我直接將native方法定義在了Activity當中
public class MainActivity extends AppCompatActivity {
//加載so庫,libjnilib.so文件
static {
System.loadLibrary("jnilib");
}
//定義native方法
private native String getStringForNative();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((TextView) findViewById(R.id.text)).setText(getStringForNative());
}
}
gradle配置
android {
/**略**/
defaultConfig {
applicationId "ndk.tzx.com.ndkdemo"
minSdkVersion 19
targetSdkVersion 23
versionCode 1
versionName "1.0"
ndk {
//定義生成的mk文件中的model名稱
moduleName "jnilib"
}
}
sourceSets {
main {
//引入so路徑
jni.srcDirs = ['src/main/jni']
}
}
/**略**/
}
創(chuàng)建jni目錄

生成C++head文件

執(zhí)行完改命令會在main/jni目錄下生成對應(yīng)的頭文件

native方法的實現(xiàn)
然后我們在main/jni目錄下創(chuàng)建cpp文件并進行native方法的實現(xiàn)
- include頭問件
- 實現(xiàn)方法
這一步經(jīng)常有好多人會遇到錯誤,只因方法名寫錯!!

構(gòu)建并運行出結(jié)果

上圖是項目build后的結(jié)果,在app/build/intermediates/ndk/debug目錄下有l(wèi)ib文件夾,obj文件夾和Android.mk文件。
在Android.mk這個文件當中我們定義生成so的名稱,生成so對應(yīng)cpp文件的路徑和so輸出的路徑。
lib目錄下我們可以看到各種類型的CPU架構(gòu)下的so文件。
如果以上過程都沒有問題的話,那么恭喜你整個項目就可以直接運行了。
踩坑需要一步一步來
build項目的時候遇到下邊問題:
Android.mk生成問題

直接在gradle.properties文件尾部添加
android.useDeprecatedNdk=true
so生成問題
Error:Execution failed for task ':app:compileDebugNdk'.
> com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command '/bin/android-ndk-r13b/ndk-build.cmd'' finished with non-zero exit value 2
使用Android.md文件生成so的時候可能會遇到這樣的問題:
解決辦法1:
將Android.mk文件copy到j(luò)ni目錄下和.h與.cpp文件放在同一級目錄,然后在該目錄下執(zhí)行
ndk-build。
ndk-build.jpg
這種方法也肯能報錯:
Error:(15) *** Android NDK: Aborting. . Stop.
Android NDK: /home/im/StudioProjects/NDKDemo/app/src/main/jni/Android.mk: Cannot find module with tag 'core' in import path
Android NDK: Are you sure your NDK_MODULE_PATH variable is properly defined ?
Android NDK: The following directories were searched:
Android NDK:
make: Entering directory `/home/im/StudioProjects/NDKDemo/app/src/main/jni'
make: Leaving directory `/home/im/StudioProjects/NDKDemo/app/src/main/jni'
:app:buildNative FAILED
Error:Execution failed for task ':app:buildNative'.
> Process 'command '/bin/android-ndk-r13b/ndk-build'' finished with non-zero exit value 2
遇到這種情況,偶查了很多資料最后才解決(參見解決方法2)
解決方法2:
安裝最新的ndk(_)
運行問題
整個項目可以運行安裝的時候是不是很爽,但是還可能遇到下邊的問題:
$ adb shell am start -n "ndk.tzx.com.ndkdemo/ndk.tzx.com.ndkdemo.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Error while executing: am start -n "ndk.tzx.com.ndkdemo/ndk.tzx.com.ndkdemo.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=ndk.tzx.com.ndkdemo/.MainActivity }
Error type 3
Error: Activity class {ndk.tzx.com.ndkdemo/ndk.tzx.com.ndkdemo.MainActivity} does not exist.
Error while Launching activity
這問題偶也整了好久,網(wǎng)上大多數(shù)解釋為native方法名不匹配,最后重新寫cpp文件也成功解決。
心好累!!~!復(fù)習之前的東西還是要當初做好筆記啊。
想閱讀作者的更多文章,可以查看我 個人博客 和公共號:



