AS2.2使用CMake方式進(jìn)行JNI/NDK開發(fā)

之前寫過一篇比較水的文章Android手機(jī)控制電腦擼出HelloWorld
里面用到了JNI/NDK技術(shù)。

這篇文章給大家介紹下JNI/NDK開發(fā)哮笆。采用的是Android Studio2.2開發(fā)環(huán)境叹誉,使用CMake方式進(jìn)行開發(fā)弱贼。

JNI(Java Native Interface)是java與C/C++進(jìn)行通信的一種技術(shù)融求,使用JNI技術(shù),可以java調(diào)用C/C++的函數(shù)對(duì)象等等沮峡,Android中的Framework層與Native層就是采用的JNI技術(shù)疚脐。

我們知道,Android系統(tǒng)是基于linux開發(fā)邢疙,采用的是linux內(nèi)核 棍弄,Android APP開發(fā)大部分也要和系統(tǒng)打交道,只是Android FrameWork 幫我們處理了和系統(tǒng)相關(guān)的操作疟游, 我們從Android 系統(tǒng)的分成結(jié)構(gòu)可以看出呼畸,Android FrameWork是通過JNI與底層的C/C++庫交互,例如:FreeType颁虐,OpenGL蛮原,SQLite,音視頻等等聪廉。


如果我們程序也需要調(diào)用自己的C/C++函數(shù)庫瞬痘,就必須用到JNI/NDK開發(fā)。

NDK配置(最新的CMake方式)

Android Studio2.2版本已經(jīng)完全支持ndk開發(fā)了板熊。而且默認(rèn)采用CMake方式框全。(傳統(tǒng)方式不過多介紹了)

CMake的優(yōu)勢(shì)

  1. 可以直接的在C/C++代碼中加入斷點(diǎn),進(jìn)行調(diào)試
  2. java引用的C/C++中的方法干签,可以直接ctrl+左鍵進(jìn)入
  3. 對(duì)于include的頭文件津辩,或者庫,也可以直接的進(jìn)入
  4. 不需要配置命令行操作,手動(dòng)的生成頭文件,不需要配置android.useDeprecatedNdk=true 屬性

下載

首先需要下載NDK容劳,來到設(shè)置界面點(diǎn)擊下載NDK


安裝完NDK喘沿,還可以選擇配置一些工具。

  1. CMake: 外部構(gòu)建工具竭贩。如果你準(zhǔn)備只使用 ndk-build 的話蚜印,可以不使用它。(Android Studio2.2默認(rèn)采用CMake)
  2. LLDB: Android Studio上面調(diào)試本地代碼的工具留量。

創(chuàng)建項(xiàng)目

Android Studio升級(jí)到2.2版本之后窄赋,在創(chuàng)建新的project時(shí),界面上多了一個(gè)Include C++ Support的選項(xiàng)楼熄。勾選它之后將會(huì)創(chuàng)建一個(gè)默認(rèn)的C++與JAVA混編的Demo程序忆绰。



然后一路 Next,直到 Finish 為止即可可岂。


上面圖的這三個(gè)文件都是默認(rèn)生成的NDK項(xiàng)目的一部分:

  1. .externalNativeBuild文件夾:cmake編譯好的文件, 顯示支持的各種硬件等信息错敢。系統(tǒng)生成。
  2. cpp文件夾:存放C/C++代碼文件缕粹,native-lib.cpp文件是默認(rèn)生成的稚茅,可更改纸淮。需要自己編寫。
  3. CMakeLists.txt文件:CMake腳本配置的文件峰锁。需要自己配置編寫萎馅。

app/build.gradle也有所不同


如果你在創(chuàng)建工程選擇C++11的標(biāo)準(zhǔn),則使用cppFlags "-std=c++11"

externalNativeBuild {
     cmake {
         cppFlags "-std=c++11"
     }
 }

來看一下双戳,CMakeLists.txt文件中的具體配置

這個(gè)文件#開頭的全是注釋虹蒋,里面不是注釋的只有下面的內(nèi)容。

cmake_minimum_required(VERSION 3.4.1) #指定cmake版本
          
          
add_library( #生成函數(shù)庫的名字
             native-lib  
             SHARED  #生成動(dòng)態(tài)函數(shù)看
             src/main/cpp/native-lib.cpp ) #依賴的cpp文件
                       
find_library( #設(shè)置path變量的名稱
              log-lib
              #指定要查詢庫的名字
              log ) #在ndk開發(fā)包中查詢liblog.so函數(shù)庫(默認(rèn)省略lib和.so),路徑賦值給log-lib
                   
target_link_libraries( #目標(biāo)庫,和上面生成的函數(shù)庫名字一至
                       native-lib
             #連接的庫,根據(jù)log-lib變量對(duì)應(yīng)liblog.so函數(shù)庫
                       ${log-lib} )

java代碼

public class MainActivity extends AppCompatActivity {
   
    // 加載函數(shù)庫
    static {
        System.loadLibrary("native-lib");
    }
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
   
        // Example of a call to a native method
        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }
   
    /**本地方法, 當(dāng)前方法是通過C/C++代碼實(shí)現(xiàn)*/
    public native String stringFromJNI();
}

上面java代碼中的 stringFromJNI()方法用native關(guān)鍵字修飾飒货,這個(gè)方法是通過C/C++代碼實(shí)現(xiàn)的魄衅。

native-lib.cpp 代碼

#include <jni.h>  
#include <string>
  
extern "C"
jstring
Java_com_a520wcf_jniproject_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

上面的C++代碼,定義的函數(shù)名是固定寫法塘辅,Java_包名_類名_Java中方法名 晃虫,通過這種命名方式就可以唯一對(duì)應(yīng)到j(luò)ava中具體的方法,從而具體實(shí)現(xiàn)java中的native方法扣墩。

運(yùn)行項(xiàng)目

修改完C/C++代碼需要點(diǎn)擊“錘子”圖標(biāo)進(jìn)行編譯哲银,然后運(yùn)行項(xiàng)目。



運(yùn)行代碼呻惕,就能看到效果荆责,調(diào)用了C++方法在界面上顯示了Hello from C++字符串。

如果你不是使用CMake而是使用傳統(tǒng)方式進(jìn)行開發(fā)亚脆,這時(shí)候就會(huì)使用了ndk -build來編譯C/C++文件為so文件做院。

那么,我們安裝運(yùn)行的apk中濒持,有對(duì)應(yīng)的so文件嗎键耕?

如果想驗(yàn)證一下apk是否有so文件,我們可以使用 APK Analyzer查看柑营。
選擇 Build > Analyze APK屈雄。

選擇 apk,并點(diǎn)擊 OK官套。
當(dāng)前項(xiàng)目debug階段的apk默認(rèn)路徑為 app/build/outputs/apk/app-debug.apk



如下圖酒奶,在 APK Analyzer 窗口中,選擇 lib/x86/虏杰,可以看見 libnative-lib.so 讥蟆。

.so文件是動(dòng)態(tài)函數(shù)庫,寫好的c/c++代碼默認(rèn)打包成函數(shù)庫纺阔,就沒法看到代碼瘸彤,只能使用了。

如果我們想在工程中使用其他人編譯好的函數(shù)庫笛钝,只需要根據(jù)不同的cpu架構(gòu)把函數(shù)庫在src/main/jniLibs目錄下质况。



在java代碼中也需要引入相應(yīng)的函數(shù)庫愕宋,編寫一樣的native方法。

手動(dòng)添加native方法

上面我們主要介紹程序自動(dòng)生成的代碼结榄,接下來我們自己動(dòng)手寫寫中贝。
我們也可以在MainActivity中寫一個(gè)native方法。



有紅色警告臼朗,因?yàn)楫?dāng)前方法并沒有找到對(duì)應(yīng)的底層代碼的實(shí)現(xiàn)邻寿。我們可以在報(bào)錯(cuò)的地方按下萬能的快捷鍵alt+回車。



選擇第一項(xiàng)视哑,就會(huì)自動(dòng)生成對(duì)應(yīng)的底層方法绣否。

參考之前的方法,照著葫蘆畫瓢挡毅,把錯(cuò)誤先修復(fù)下蒜撮。

修改MainActivity代碼,調(diào)用我們寫的native方法跪呈。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  
    TextView tv = (TextView) findViewById(R.id.sample_text);
    tv.setText(stringFromJNI2());//調(diào)用新寫的native方法
}

編譯運(yùn)行當(dāng)前程序段磨。
運(yùn)行結(jié)果:



可以看到我們成功調(diào)用了我們自己創(chuàng)建的native方法。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末耗绿,一起剝皮案震驚了整個(gè)濱河市苹支,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缭乘,老刑警劉巖沐序,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異堕绩,居然都是意外死亡策幼,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門奴紧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來特姐,“玉大人,你說我怎么就攤上這事黍氮√坪” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵沫浆,是天一觀的道長捷枯。 經(jīng)常有香客問我,道長专执,這世上最難降的妖魔是什么淮捆? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上攀痊,老公的妹妹穿的比我還像新娘桐腌。我一直安慰自己,他們只是感情好苟径,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布案站。 她就那樣靜靜地躺著,像睡著了一般棘街。 火紅的嫁衣襯著肌膚如雪蟆盐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天蹬碧,我揣著相機(jī)與錄音舱禽,去河邊找鬼。 笑死恩沽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的翔始。 我是一名探鬼主播罗心,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼城瞎!你這毒婦竟也來了渤闷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤脖镀,失蹤者是張志新(化名)和其女友劉穎飒箭,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蜒灰,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡弦蹂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了强窖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凸椿。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖翅溺,靈堂內(nèi)的尸體忽然破棺而出脑漫,到底是詐尸還是另有隱情,我是刑警寧澤咙崎,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布优幸,位于F島的核電站,受9級(jí)特大地震影響褪猛,放射性物質(zhì)發(fā)生泄漏网杆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望跛璧。 院中可真熱鬧严里,春花似錦、人聲如沸追城。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽座柱。三九已至迷帜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間色洞,已是汗流浹背戏锹。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留火诸,地道東北人锦针。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像置蜀,于是被迫代替她去往敵國和親奈搜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容