Android原生庫構(gòu)建的三種姿態(tài)

前言

自Android Studio 2.2發(fā)布之后梢莽,AS開始支持CMake構(gòu)建工具編譯構(gòu)建原生代碼庫,谷歌推薦使用CMake來構(gòu)建新建的原生庫奸披,不過為了兼顧老項(xiàng)目昏名,AS還是支持ndk-build構(gòu)建,除此之外源内,谷歌還推出了實(shí)驗(yàn)性Gradle插件來構(gòu)建原生庫葡粒,至此AS工具支持3種方式來構(gòu)建原生庫。
實(shí)驗(yàn)性Gradle插件由于依賴開發(fā)中的Gradle API膜钓,所以它是不穩(wěn)定的嗽交,不過谷歌稱Android Studio團(tuán)隊(duì)會繼續(xù)支持實(shí)驗(yàn)性Gradle插件,谷歌希望將來該插件能取代當(dāng)前的Gradle插件颂斜,因?yàn)槠渚o密集成的特性對于C/C++開發(fā)者更為便利夫壁,例如,更靈活的依賴管理沃疮。因此盒让,對于想在IDE與構(gòu)建系統(tǒng)之間建立最靈活的接口的開發(fā)者,可以嘗試使用實(shí)驗(yàn)性Gradle插件司蔬。

這里主要介紹下谷歌推薦的方式—Cmake邑茄。

PS:以下內(nèi)容主要來自谷歌官方文檔。

1俊啼、CMake

1.1肺缕、構(gòu)建工具準(zhǔn)備

  • 下載NDK:Android C/C++代碼工具集
  • 下載Cmake:外部構(gòu)建工具
  • 下載LLDB:Android Studio 上面調(diào)試本地代碼的工具

使用 SDK Manager 來安裝上述組件:

  1. 打開一個(gè)項(xiàng)目,從菜單欄中選擇 Tools > Android > SDK Manager。
  2. 點(diǎn)擊 SDK Tools 選項(xiàng)卡同木。
  3. 勾選 LLDB浮梢,CMake 和 NDK。如圖:

1.2 創(chuàng)建 CMake 構(gòu)建腳本

創(chuàng)建一個(gè)CMakeList.txt構(gòu)建腳本文件彤路,然后用CMake命令來配置腳本文件秕硝。
為了讓 CMake 將源代碼(native source code)編譯成 native library。需要在編譯文件中添加 cmake_minimum_required() 和 add_library() 命令:

# Sets the minimum version of CMake required to build your native library.
# This ensures that a certain set of CMake features is available to
# your build.

cmake_minimum_required(VERSION 3.4.1)

# Specifies a library name, specifies whether the library is STATIC or
# SHARED, and provides relative paths to the source code. You can
# define multiple libraries by adding multiple add.library() commands,
# and CMake builds them for you. When you build your app, Gradle
# automatically packages shared libraries with your APK.

add_library( # Specifies the name of the library.
             native-lib

            # Sets the library as a shared library.
             SHARED

            # Provides a relative path to your source file(s).
            src/main/cpp/native-lib.cpp )

當(dāng)使用 add_library()洲尊,將一個(gè)源文件(source file)或庫添加到 CMake 構(gòu)建腳本远豺,同步項(xiàng)目,然后 Android studio 將關(guān)聯(lián)的頭文件也顯示了颊郎。然而憋飞,為了讓 CMake 在編譯時(shí)期能定位到頭文件,需要在 CMake 構(gòu)建腳本中添加 include_directories() 命令姆吭,并指定頭文件路徑:

add_library(...)

# Specifies a path to native header files.
include_directories(src/main/cpp/include/)

1.3榛做、添加 NDK APIs

Android NDK 提供了一些有用的 native APIs。將 NDK librarys 添加到 CMakeLists.txt 腳本文件中内狸,就可以使用這些 API 了检眯。

預(yù)編譯的 NDK librarys 已經(jīng)存在在 Android 平臺中了,所以你不需要編譯它們昆淡,或者是將其打包到你的 APK 中锰瘸。因?yàn)檫@些 NDK librarys 已經(jīng)是 CMake 搜索路徑的一部分,你甚至不需要提供你本地安裝的 NDK 路徑昂灵。你只需要向 CMake 提供你想使用的 library 名字避凝。

將 find_library() 命令添加到你的 CMake 構(gòu)建腳本中,這樣就可以定位 NDK library 的位置眨补,并將其位置存儲在一個(gè)變量之中管削。你可以在構(gòu)建腳本的其他地方使用這個(gè)變量,來代指 NDK library撑螺。下面的示例代碼將 Android-specific log support library 的位置存儲到變量 log-lib 中:

find_library( # Defines the name of the path variable that stores the
              # location of the NDK library.
              log-lib

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

NDK 同樣也包含一些只包含源碼的 library含思,這些就需要你去編譯,然后鏈接到你的本地庫(native library)甘晤。你可以在 CMake 構(gòu)建腳本中使用 add_library() 命令將源碼編譯進(jìn)本地庫含潘。這時(shí)就需要提供你的本地 NDK 安裝路徑,通常將該路徑保存在 ANDROID_NDK 變量中线婚,這樣 Android Studio 可以自動為你識別

下面的命令告訴 CMake 去構(gòu)建 android_native_app_glue.c遏弱,這個(gè)命令可以管理 NativeActivity 的生命周期以及點(diǎn)擊輸入,并將其導(dǎo)入靜態(tài)庫中塞弊,然后將其鏈接至 native-lib:

add_library( app-glue
             STATIC
             ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c )

# You need to link static libraries against your shared native library.
target_link_libraries( native-lib app-glue ${log-lib} )

1.4腾窝、添加其他的預(yù)編譯庫

添加預(yù)編譯庫和添加本地庫(native library)類似缀踪。由于預(yù)編譯庫是已經(jīng)構(gòu)建好的,你想就要使用 IMPORTED 標(biāo)志去告訴 CMake 虹脯,你只需要將其導(dǎo)入到你的項(xiàng)目中即可:

add_library( imported-lib
             SHARED
             IMPORTED )

然后你需要使用 set_target_properties()
命令去指定庫的路徑,就像下面的代碼那樣奏候。
一些庫會根據(jù)不同的 CPU 使用不同的包循集,或者是 Application Binary Interfaces(ABI)
,并且將他們歸類到不同的目錄中蔗草。這樣做的好處是咒彤,可以充分發(fā)揮特定的 CPU 架構(gòu)。你可以使用 ANDROID_ABI
路徑變量咒精,將多個(gè) ABI 版本的庫添加到你的 CMake 構(gòu)建腳本中镶柱。這個(gè)變量使用了一些 NDK 默認(rèn)支持的 ABI,以及一些需要手動配置到 Gradle 的 ABI模叙,比如:

add_library(...)
set_target_properties( # Specifies the target library.
                       imported-lib

                       # Specifies the parameter you want to define.
                       PROPERTIES IMPORTED_LOCATION

                       # Provides the path to the library you want to import.
                       imported-lib/src/${ANDROID_ABI}/libimported-lib.so )

為了讓 CMake 在編譯時(shí)期能找到你的頭文件歇拆,你需要使用 include_directories() 命令,并且將你的頭文件地址傳進(jìn)去:

nclude_directories( imported-lib/include/ )

在 CMake 構(gòu)建腳本中使用 target_link_libraries() 命令范咨,將預(yù)構(gòu)建庫與你本地庫相關(guān)聯(lián):

target_link_libraries( native-lib imported-lib app-glue ${log-lib} )

當(dāng)你構(gòu)建你的 APP 的時(shí)候故觅,Gradle 會自動將導(dǎo)入的庫打包到你的 APK 中。你可以使用 APK Analyzer 來檢查渠啊。

1.5输吏、關(guān)聯(lián)本地庫與 Gradle

為了將本地庫與 Gradle 相關(guān)聯(lián),你需要在 CMake 或 ndk-build 構(gòu)建腳本中提供一個(gè)路徑地址替蛉。當(dāng)你構(gòu)建你的 APP 時(shí)贯溅,Gradle 會將 CMake 或 ndk-build 作為一個(gè)依賴運(yùn)行,然后將共享庫(.so 文件)打包到你的 APK 中躲查。

1.5.1它浅、使用 Android Studio 圖形化界面

  1. 打開 IDE 左邊的 Project 面板,選擇 Android 視圖熙含。
  2. 右鍵點(diǎn)擊你想鏈接本地庫的 module罚缕,比如 app module,然后從菜單中選擇 Link C++ Project with Gradle怎静。你應(yīng)該能看見一個(gè)和下圖很像的對話框邮弹。
  3. 在下拉菜單中,選擇 CMake 或者 ndk-build蚓聘。
    a. 如果你選擇 CMake腌乡,需要在 Project Path 中指定 CMakeLists.txt 腳本文件的路徑。
    b. 如果你選擇 ndk-build夜牡,你需要在 Project Path 中指定 Android.mk 腳本文件的路徑与纽。

1.6侣签、手動配置 Gradle

如果要手動將 Gradle 與你的本地庫相關(guān)聯(lián),你需要在 module 層級的 build.gradle 文件中添加 externalNativeBuild {} 代碼塊急迂,并且在該代碼塊中配置 cmake {} 或 ndkBuild {}:

android {
  ...
  defaultConfig {...}
  buildTypes {...}

  // Encapsulates your external native build configurations.
  externalNativeBuild {

    // Encapsulates your CMake build configurations.
    cmake {

      // Provides a relative path to your CMake build script.
      path "CMakeLists.txt"
    }
  }
}

1.6.1影所、可選配置

你可以在你的 module 層級的 build.gradle 文件中的 defaultConfig {} 代碼塊中,添加 externalNativeBuild {} 代碼塊僚碎,為 CMake 或 ndk-build 配置一些額外參數(shù)猴娩。當(dāng)然,你也可以在你的構(gòu)建配置中勺阐,為其他每一個(gè)生產(chǎn)渠道重寫這些屬性卷中。

比如,如果你的 CMake 或者 ndk-build 項(xiàng)目中定義了多個(gè)本地庫渊抽,你想在某個(gè)生產(chǎn)渠道使用這些本地庫中的幾個(gè)蟆豫,你就可以使用 targets 屬性來構(gòu)建和打包。下面的代碼展示了一些你可能會用到的屬性:

android {
  ...
  defaultConfig {
    ...
    // This block is different from the one you use to link Gradle
    // to your CMake or ndk-build script.
    externalNativeBuild {

      // For ndk-build, instead use ndkBuild {}
      cmake {

        // Passes optional arguments to CMake.
        arguments "-DCMAKE_VERBOSE_MAKEFILE=TRUE"

        // Sets optional flags for the C compiler.
        cFlags "-D_EXAMPLE_C_FLAG1", "-D_EXAMPLE_C_FLAG2"

        // Sets a flag to enable format macro constants for the C++ compiler.
        cppFlags "-D__STDC_FORMAT_MACROS"
      }
    }
  }

  buildTypes {...}

  productFlavors {
    ...
    demo {
      ...
      externalNativeBuild {
        cmake {
          ...
          // Specifies which native libraries to build and package for this
          // product flavor. If you don't configure this property, Gradle
          // builds and packages all shared object libraries that you define
          // in your CMake or ndk-build project.
          targets "native-lib-demo"
        }
      }
    }

    paid {
      ...
      externalNativeBuild {
        cmake {
          ...
          targets "native-lib-paid"
        }
      }
    }
  }

  // You use this block to link Gradle to your CMake or ndk-build script.
  externalNativeBuild {
    cmake {...}
    // or ndkBuild {...}
  }
}

1.6.2懒闷、指定 ABI

如果你想 Gradle 構(gòu)建并打包某個(gè)特定的 ABI 十减。你可以在你的 module 層級的 build.gradle 文件中使用 ndk.abiFilters 標(biāo)簽來指定他們:

android {
  ...
  defaultConfig {
    ...
    externalNativeBuild {
      cmake {...}
      // or ndkBuild {...}
    }

    ndk {
      // Specifies the ABI configurations of your native
      // libraries Gradle should build and package with your APK.
      abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a'
    }
  }
  buildTypes {...}
  externalNativeBuild {...}
}

大多數(shù)情況,你只需要像上面的代碼那樣毛雇,在 ndk {} 代碼塊中指定 abiFilters 即可嫉称。如果你想控制 Gradle 構(gòu)建、依賴你希望的東西灵疮,你就需要在 defaultConfig.externalNativeBuild.cmake {} 代碼塊或 defaultConfig.externalNativeBuild.ndkBuild {} 代碼塊中织阅,配置其他的 abiFilters 標(biāo)簽。Gradle 會構(gòu)建這些 ABI 配置震捣,但是只會將 defaultConfig.ndk {} 代碼塊中指定的東西打包到 APK中荔棉。

官方文檔:
https://developer.android.com/studio/projects/add-native-code.html#create-cmake-script

推薦一篇不錯(cuò)的相關(guān)文章:
http://blog.csdn.net/mabeijianxi/article/details/68525164

2、ndk-build

ndk-build這里不做詳細(xì)介紹蒿赢,請自行查看官方文檔:
https://developer.android.com/ndk/guides/ndk-build.html

3润樱、experimental-gradle-plugin

experimental-gradle-plugin這里不做詳細(xì)介紹,請自行查看官方文檔:
http://tools.android.com/tech-docs/new-build-system/gradle-experimental
官方網(wǎng)址可能打不開羡棵,可查看轉(zhuǎn)載網(wǎng)址:
http://www.cnblogs.com/tanlon/p/4731283.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末壹若,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子皂冰,更是在濱河造成了極大的恐慌店展,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秃流,死亡現(xiàn)場離奇詭異赂蕴,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)舶胀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門概说,熙熙樓的掌柜王于貴愁眉苦臉地迎上來碧注,“玉大人,你說我怎么就攤上這事糖赔∑钾ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵放典,是天一觀的道長碉纺。 經(jīng)常有香客問我,道長刻撒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任耿导,我火速辦了婚禮声怔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘舱呻。我一直安慰自己醋火,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布箱吕。 她就那樣靜靜地躺著芥驳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪茬高。 梳的紋絲不亂的頭發(fā)上兆旬,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機(jī)與錄音怎栽,去河邊找鬼丽猬。 笑死,一個(gè)胖子當(dāng)著我的面吹牛熏瞄,可吹牛的內(nèi)容都是我干的脚祟。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼强饮,長吁一口氣:“原來是場噩夢啊……” “哼由桌!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起邮丰,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤行您,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后柠座,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體邑雅,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年妈经,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了淮野。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捧书。...
    茶點(diǎn)故事閱讀 39,841評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖骤星,靈堂內(nèi)的尸體忽然破棺而出经瓷,到底是詐尸還是另有隱情,我是刑警寧澤洞难,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布舆吮,位于F島的核電站,受9級特大地震影響队贱,放射性物質(zhì)發(fā)生泄漏色冀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一柱嫌、第九天 我趴在偏房一處隱蔽的房頂上張望锋恬。 院中可真熱鬧,春花似錦编丘、人聲如沸与学。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽索守。三九已至,卻和暖如春抑片,著一層夾襖步出監(jiān)牢的瞬間卵佛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工蓝丙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留级遭,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓渺尘,卻偏偏與公主長得像挫鸽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子鸥跟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評論 2 354

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