10.1 Android NDK開發(fā) 一

標注:本文為個人學習使用斤儿,僅做自己學習參考使用裹虫,請勿轉(zhuǎn)載和轉(zhuǎn)發(fā)
2018-08-14: 初稿,參考SvenWang_
2018-08-24: 二稿娄琉,更新舊項目添加JNI使用CMake編譯的方法

0. 引言

  • 在網(wǎng)上找了好幾篇關(guān)于ndk開發(fā)的文章次乓,一直沒有成功,最近關(guān)于android的so的開發(fā)相關(guān)的嘗試孽水,也就是c/c++等的開發(fā)票腰,所以準備從android的jni開始入手,以上是背景女气。
  • 由于as不斷完善的ndk的開發(fā)杏慰,所以網(wǎng)上的博客就有了很多都已經(jīng)過時了,這個文章是從兩種方式講解as3.0 上面進行的ndk的配置炼鞠。
  • 主要內(nèi)容
    1.創(chuàng)建新的項目就開始進行ndk開發(fā)
    2.在原有的項目的基礎(chǔ)上進行ndk開發(fā)
    3.為什么生成的jni文件關(guān)聯(lián)不上
    4.生成so各類庫
  • 參考文獻
    AndroidStudio3.0 NDK開發(fā)- 如何在已有項目中進行NDK開發(fā)
    AndroidStudio3.0開發(fā)調(diào)試安卓NDK的C++代碼

1. 準備工作

首先需要下載關(guān)于ndk的相關(guān)工具


2. 創(chuàng)建新項目直接進行ndk開發(fā)

  • 這種指的是直接在創(chuàng)建新的項目的時候缘滥,在向?qū)onfigure your new project 部分,選中 Include C++ Support 復選框谒主;
  • 然后next朝扼;
  • 正常填寫然后next;
  • 在向?qū)У?Customize C++ Support 部分霎肯,您可以使用下列選項自定義項目:
    1.C++ Standard:使用下拉列表選擇您希望使用哪種 C++ 標準擎颖。選擇 Toolchain Default 會使用默認的 CMake 設(shè)置榛斯。
    2.Exceptions Support:如果您希望啟用對 C++ 異常處理的支持肠仪,請選中此復選框肖抱。如果啟用此復選框,Android Studio 會將 -fexceptions 標志添加到模塊級 build.gradle 文件的 cppFlags 中异旧,Gradle 會將其傳遞到 CMake意述。
    3.Runtime Type Information Support:如果您希望支持 RTTI,請選中此復選框吮蛹。如果啟用此復選框荤崇,Android Studio 會將 -frtti 標志添加到模塊級 build.gradle 文件的 cppFlags 中,Gradle 會將其傳遞到 CMake潮针。
  • 點擊 Finish术荤。

上面的操作比較簡單,在配置之后每篷,直接得到如下的界面


  • 在cpp的包下瓣戚,可以找到屬于項目的所有的原生文件、.h文件焦读、預構(gòu)建庫子库。對于新的項目,Android Studio 會創(chuàng)建一個示例 C++ 源文件 native-lib.cpp矗晃,并將其置于應(yīng)用模塊的 src/main/cpp/ 目錄中仑嗅。本示例代碼提供了一個簡單的 C++ 函數(shù) stringFromJNI(),此函數(shù)可以返回字符串“Hello from C++”张症。
  • 在 External Build Files 組中仓技,您可以找到 CMake 或 ndk-build 的構(gòu)建腳本。與 build.gradle 文件指示 Gradle 如何構(gòu)建應(yīng)用一樣俗他,CMake 和 ndk-build 需要一個構(gòu)建腳本來了解如何構(gòu)建您的原生庫脖捻。對于新項目,Android Studio 會創(chuàng)建一個 CMake 構(gòu)建腳本 CMakeLists.txt兆衅,并將其置于模塊的根目錄中郭变。

下面是關(guān)于CMakeLists.txt文件

# 有關(guān)使用CMake在Android Studio的更多信息,請閱讀文檔:https://d.android.com/studio/projects/add-native-code.html

# 設(shè)置CMake的最低版本構(gòu)建本機所需庫
cmake_minimum_required(VERSION 3.4.1)

# 創(chuàng)建并命名庫,將其設(shè)置為靜態(tài)的
# 或共享涯保,并提供其源代碼的相對路徑诉濒。
# 你可以定義多個library庫,并使用CMake來構(gòu)建夕春。
# Gradle會自動將包共享庫關(guān)聯(lián)到你的apk程序未荒。

add_library( # 設(shè)置庫的名稱
             native-lib     #這個根據(jù)庫名更改
             # 將庫設(shè)置為共享庫。
             SHARED
             # 為源文件提供一個相對路徑及志。
             src/main/cpp/native-lib.cpp )      #路徑下的庫名根據(jù)上面的庫名更改
# 搜索指定預先構(gòu)建的庫和存儲路徑變量片排。因為CMake包括系統(tǒng)庫搜索路徑中默認情況下,只需要指定想添加公共NDK庫的名稱寨腔,在CMake驗證庫之前存在完成構(gòu)建
find_library( # 設(shè)置path變量的名稱
              log-lib
              # 在CMake定位前指定的NDK庫名稱
              log )
# 指定庫CMake應(yīng)該鏈接到目標庫中,可以鏈接多個庫率寡,比如定義庫迫卢,構(gòu)建腳本,預先構(gòu)建的第三方庫或者系統(tǒng)庫
target_link_libraries( # 指定目標庫
                       native-lib        #根據(jù)上面更改庫名的更改
                       # 目標庫到日志庫的鏈接 包含在NDK
                       ${log-lib} )

3. 在已有的項目的基礎(chǔ)上進行ndk開發(fā)

  • 關(guān)于項目什么情況下是沒有引進c++庫呢冶共,就是在創(chuàng)建項目的情況下沒有勾選 Include C++ support乾蛤。
  • 還有就是老項目沒有NDK,然后準備集成NDK開發(fā)捅僵,NDK開發(fā)主要有兩種編譯形式家卖,一種是原來的android.mk,也就是ndk-build庙楚,另一種是CMake上荡,CMake需要添加一個CMakeList.txt。
  • 本文主要講解對CMake編譯方式進行依賴的方法馒闷。
  • 舉個例子酪捡,創(chuàng)建一個沒有C++庫的demo
  • 然后對這個項目進行一路的next,就是正常的as項目纳账,沒有ndk的相關(guān)文件沛善。


  • 在MainActivity 中寫上 native的代碼,也可以單獨建立一個類塞祈,專門用來調(diào)用底層函數(shù)的util類

public class JavaNativeUtil {

    static {
        // 設(shè)置依賴庫,native-lib為依賴庫的名稱帅涂,可以自行修改 
        System.loadLibrary("native-lib");
    }

    public static native String hello();

}
  • 之所以用static修飾了hello方法议薪,是準備將該方法直接在MainActivity中調(diào)用,然后發(fā)現(xiàn)hello方法是紅色報錯的媳友,暫時先不用處理斯议。
  • 在main文件夾下建立一個cpp的文件夾,然后在cpp文件夾下創(chuàng)建一個native-lib的cpp文件醇锚,這個文件就是Java2C的橋梁
  • 編寫c++實現(xiàn)方法
  • 編寫native-lib.cpp文件時哼御,首先要包括頭文件jni.h,其次是包含extern “C”焊唬,注意extern “C”的{}一定要將下面的方法包裹起來恋昼,extern “C”主要就是為了兼容Java2C的JNI特殊書寫格式的方法。
  • 編寫方法的的路徑一定不能寫錯赶促。
  • 本方法和自動添加C++的Android項目一樣液肌,直接返回了一個字符串。
#include <jni.h>

extern "C" {
// 這個路徑參照上面創(chuàng)建的JavaNativeUtil的路徑進行編寫
JNIEXPORT jstring JNICALL Java_net_ankie_italker_jnitestdemo_JavaNativeUtil_hello(JNIEnv *env, jobject obj) {
    // 返回字符串
    return env->NewStringUTF("hello ndk");
}
}
  • 創(chuàng)建一個CMakeLists.txt文件



  • 這里的創(chuàng)建的名字必須是 CMakeLists.txt 然后把下面這些代碼復制進去
cmake_minimum_required(VERSION 3.4.1)


add_library( # Specifies the name of the library.
# 這里是你so的名字鸥滨∴露撸可以自己定義谤祖,但是在LoadLibrary的時候要對應(yīng)上
             native-lib  

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
              #這里是剛才 創(chuàng)建的c++ 代碼的名字
             src/main/cpp/Hello.cpp )

find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

target_link_libraries( # Specifies the target library.
# 這里是你so的名字。和上面的一樣
                       native-lib

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )
  • 在配置完CMakeList.txt之后老速,可以配置gradle了粥喜,配置gradle時候有兩種方法,一種是點擊要配置的model右鍵橘券,添加Link C++ Project with Gradle额湘,然后添加對應(yīng)剛才創(chuàng)建的CMakeList.txt,右鍵項目選擇菜單:Link C++ Project with Gradle
  • 另一種方法是直接添加在Gradle中下面增加的externalNativeBuild選項约郁,然后更新下gradle即可缩挑。
  • 然后選擇我們使用的編譯模式CMake進行添加CMakeList.txt文件


  • 添加之后會發(fā)現(xiàn)Gradle文件會增加externalNativeBuild選項,這樣我們就可以愉快的使用JNI了
apply plugin: 'com.android.application'

android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "net.ankie.italker.jnitestdemo"
        minSdkVersion 19
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {    // 這個就是剛才添加的新的關(guān)于CMakeList.txt的添加
        cmake {
            path 'CMakeLists.txt'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
  • 然后編譯一下就可以了鬓梅,編譯的時候最好的方式是先clean build供置,然后再編譯下
  • 然后會發(fā)現(xiàn)hello方法不紅了,可以執(zhí)行了绽快,能跳轉(zhuǎn)了芥丧,方法名之前可以跳轉(zhuǎn)到JavaNativeUtil方法里面了!
  • 這樣就可以調(diào)用方法進行編譯調(diào)用了坊罢,本文直接調(diào)用的JNI的hello方法续担,然后在MainActivity中打印的Log
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.e(TAG, "onCreate:  " +  JavaNativeUtil.hello());
    }
}

4. 生成so文件

  • build之前應(yīng)該clean build,要不不能make Module ‘a(chǎn)pp’


  • 然后就會生成so文件


5. 備注

  • 本文主要講解的是關(guān)于AS中創(chuàng)建新的項目和在舊項目中添加NDK的CMake的編譯方式的方法活孩。
  • 其中舊項目添加NDK有兩種方式物遇,網(wǎng)上主要介紹的是添加 .mk文件,然后使用ndk-build的方式憾儒,本文主要介紹的是添加CMakeList.txt文件CMake的編譯方式询兴。
  • 主要講述了搭建JNI的形式,其中native-lib.cpp文件和native-lib庫的名稱可以自行根據(jù)需求定義起趾。
  • 生成的so庫可以根據(jù)需要添加到不同的平臺下的AS中進行依賴诗舰。
  • 其中JNI關(guān)聯(lián)不上的主要原因有native-lib.cpp文件中的方法的與在Java中的路徑的名不對稱,或者是CMakeList.txt沒有添加到Gradle中训裆,然后更新Gradle眶根。
  • 還有可能就是沒有添加extern ”C“ {},或者其作用域沒有包含其他的JNI方法边琉。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末属百,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子变姨,更是在濱河造成了極大的恐慌诸老,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異别伏,居然都是意外死亡蹄衷,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門厘肮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來愧口,“玉大人,你說我怎么就攤上這事类茂∷J簦” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵巩检,是天一觀的道長厚骗。 經(jīng)常有香客問我,道長兢哭,這世上最難降的妖魔是什么领舰? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮迟螺,結(jié)果婚禮上冲秽,老公的妹妹穿的比我還像新娘。我一直安慰自己矩父,他們只是感情好锉桑,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著窍株,像睡著了一般民轴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上球订,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天后裸,我揣著相機與錄音,去河邊找鬼辙售。 笑死,一個胖子當著我的面吹牛飞涂,可吹牛的內(nèi)容都是我干的旦部。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼较店,長吁一口氣:“原來是場噩夢啊……” “哼士八!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起梁呈,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤婚度,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后官卡,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蝗茁,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡醋虏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了哮翘。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片颈嚼。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖饭寺,靈堂內(nèi)的尸體忽然破棺而出阻课,到底是詐尸還是另有隱情,我是刑警寧澤艰匙,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布限煞,位于F島的核電站,受9級特大地震影響员凝,放射性物質(zhì)發(fā)生泄漏署驻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一绊序、第九天 我趴在偏房一處隱蔽的房頂上張望硕舆。 院中可真熱鬧,春花似錦骤公、人聲如沸抚官。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽凌节。三九已至,卻和暖如春洒试,著一層夾襖步出監(jiān)牢的瞬間倍奢,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工垒棋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留卒煞,地道東北人。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓叼架,卻偏偏與公主長得像畔裕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子乖订,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

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