[Android騷操作] NDK編譯多架構(gòu)SO引用

1530.jpg

前言

在我們開發(fā)當(dāng)中命贴,總有那么一些奇葩的需求要用奇葩的騷操作來實現(xiàn)梢莽,好了囤捻,話不多說臼朗,直接進(jìn)入主題

打開方式

簡單來說,當(dāng)我們需要使用多個架構(gòu)的SO庫編譯出多個SO的時候蝎土,怎么去配置NDK的編譯腳本呢视哑?
我個人比較喜歡使用原始的Android.mk編譯,本文也以Android.mk為例誊涯,好像CMake更簡單一些挡毅,不過,我不喜歡

Gradle中配置NDK自動編譯

我們使用的是Android.mk文件暴构,那么怎么讓Gradle識別并自動編譯呢跪呈?其實很簡單,只需要在項目的gradle.build文件的 android 節(jié)點下添加這么一段

externalNativeBuild {
        ndkBuild {
            path 'src/main/cpp/Android.mk'
        }
    }

其中的 path 表示你的Android.mk所在的絕對路徑取逾,這樣一來耗绿,就實現(xiàn)了NDK自動編譯了

在Android.mk中配置引用多個SO

一般情況,我們在進(jìn)行NDK開發(fā)的時候菌赖,目錄結(jié)構(gòu)大概是這樣的

2018-10-09 17-18-36 的屏幕截圖.png

cpp 目錄下包含C/C++的源文件
jniLibs 目錄下是引用的對應(yīng)架構(gòu)的庫文件

當(dāng)你的項目需要編譯引用多個SO來的時候缭乘,怎么去配置呢?其實也很簡單的琉用,這里以Android中使用FFmpeg為例

  • 打開你的Android.mk文件堕绩,設(shè)置工作目錄

正常情況一個合格的Android.mk文件應(yīng)該是這樣子的

## 選擇需要編譯的目標(biāo)架構(gòu),如果全部架構(gòu)都需要則把 APP_ABI 的值設(shè)置為 all 即可
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := native-lib
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
LOCAL_SRC_FILES := native-lib.c native-lib.h
include $(BUILD_SHARED_LIBRARY)
  • 聲名SO庫的名稱及位置

我們在 LOCAL_PATH := $(call my-dir) 后邊添加聲名邑时,添加完成過后大概是這個樣子的

APP_ABI := armeabi-v7a arm64-v8a x86 x86_64

LOCAL_PATH := $(call my-dir)

## libavcodec.so
include $(CLEAR_VARS)
LOCAL_MODULE := avcodec
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/armeabi-v7a/libavcodec.so
include $(PREBUILT_SHARED_LIBRARY)

## libavdevice.so
include $(CLEAR_VARS)
LOCAL_MODULE := avdevice
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/armeabi-v7a/libavdevice.so
include $(PREBUILT_SHARED_LIBRARY)

## libavfilter.so
include $(CLEAR_VARS)
LOCAL_MODULE := avfilter
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/armeabi-v7a/libavfilter.so
include $(PREBUILT_SHARED_LIBRARY)

## libavformat.so
include $(CLEAR_VARS)
LOCAL_MODULE := avformat
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/armeabi-v7a/libavformat.so
include $(PREBUILT_SHARED_LIBRARY)

## libavutil.so
include $(CLEAR_VARS)
LOCAL_MODULE := avutil
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/armeabi-v7a/libavutil.so
include $(PREBUILT_SHARED_LIBRARY)

## libswresample.so
include $(CLEAR_VARS)
LOCAL_MODULE := swresample
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/armeabi-v7a/libswresample.so
include $(PREBUILT_SHARED_LIBRARY)

## libswscale.so
include $(CLEAR_VARS)
LOCAL_MODULE := swscale
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/armeabi-v7a/libswscale.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := native-lib
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
LOCAL_SRC_FILES := native-lib.c native-lib.h
include $(BUILD_SHARED_LIBRARY)

這里需要注意的是奴紧,聲明的SO庫后邊的 include 應(yīng)該為 $(PREBUILT_SHARED_LIBRARY)
而你編譯的SO庫后邊的 include 應(yīng)該為 $(BUILD_SHARED_LIBRARY)

  • 引用SO庫

最后,在你的編譯腳本中加入 LOCAL_SHARED_LIBRARIES := avcodec avdevice avfilter avformat avutil swresample swscale 這后邊的值需要是你之前聲名的 LOCAL_MODULE 的名稱晶丘,多個引用中間用空格隔開黍氮,添加引用過后整個Android.mk大概就是這個樣子的

APP_ABI := armeabi-v7a arm64-v8a x86 x86_64

LOCAL_PATH := $(call my-dir)

## libavcodec.so
include $(CLEAR_VARS)
LOCAL_MODULE := avcodec
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/armeabi-v7a/libavcodec.so
include $(PREBUILT_SHARED_LIBRARY)

## libavdevice.so
include $(CLEAR_VARS)
LOCAL_MODULE := avdevice
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/armeabi-v7a/libavdevice.so
include $(PREBUILT_SHARED_LIBRARY)

## libavfilter.so
include $(CLEAR_VARS)
LOCAL_MODULE := avfilter
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/armeabi-v7a/libavfilter.so
include $(PREBUILT_SHARED_LIBRARY)

## libavformat.so
include $(CLEAR_VARS)
LOCAL_MODULE := avformat
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/armeabi-v7a/libavformat.so
include $(PREBUILT_SHARED_LIBRARY)

## libavutil.so
include $(CLEAR_VARS)
LOCAL_MODULE := avutil
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/armeabi-v7a/libavutil.so
include $(PREBUILT_SHARED_LIBRARY)

## libswresample.so
include $(CLEAR_VARS)
LOCAL_MODULE := swresample
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/armeabi-v7a/libswresample.so
include $(PREBUILT_SHARED_LIBRARY)

## libswscale.so
include $(CLEAR_VARS)
LOCAL_MODULE := swscale
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/armeabi-v7a/libswscale.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := native-lib
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
LOCAL_SHARED_LIBRARIES := avcodec avdevice avfilter avformat avutil swresample swscale
LOCAL_SRC_FILES := native-lib.c native-lib.h
include $(BUILD_SHARED_LIBRARY)

這樣,你就實現(xiàn)了多個SO的引用

多架構(gòu)SO引用編譯

相信你也發(fā)現(xiàn)了浅浮,上邊引用的SO全部是 armeabi-v7a 的沫浆,那我們需要引用 arm64-v8a 或者 x86x86_64 的架構(gòu)時滚秩,怎么操作呢专执?把 armeabi-v7a 換成 x86 或者其他的架構(gòu)在編譯一次?當(dāng)然不可能郁油,因為這太繁瑣了本股,其實攀痊,Android.mk有一些全局變量,而大多數(shù)是編譯的時候使用的拄显,我們并不知道苟径,那我怎么知道Android.mk當(dāng)前編譯的是那個架構(gòu)的呢?答案只有一個躬审,那就是 TARGET_ARCH_ABI 棘街,當(dāng)編譯的架構(gòu)為 armeabi-v7a 的時候,TARGET_ARCH_ABI 的值為 armeabi-v7a 盒件,那么這個時候蹬碧,我們只需要引用 TARGET_ARCH_ABI 的值替換目錄名稱就行了,修改后的整個Android.mk是這樣的

APP_ABI := armeabi-v7a arm64-v8a x86 x86_64

LOCAL_PATH := $(call my-dir)

## libavcodec.so
include $(CLEAR_VARS)
LOCAL_MODULE := avcodec
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/$(TARGET_ARCH_ABI)/libavcodec.so
include $(PREBUILT_SHARED_LIBRARY)

## libavdevice.so
include $(CLEAR_VARS)
LOCAL_MODULE := avdevice
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/$(TARGET_ARCH_ABI)/libavdevice.so
include $(PREBUILT_SHARED_LIBRARY)

## libavfilter.so
include $(CLEAR_VARS)
LOCAL_MODULE := avfilter
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/$(TARGET_ARCH_ABI)/libavfilter.so
include $(PREBUILT_SHARED_LIBRARY)

## libavformat.so
include $(CLEAR_VARS)
LOCAL_MODULE := avformat
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/$(TARGET_ARCH_ABI)/libavformat.so
include $(PREBUILT_SHARED_LIBRARY)

## libavutil.so
include $(CLEAR_VARS)
LOCAL_MODULE := avutil
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/$(TARGET_ARCH_ABI)/libavutil.so
include $(PREBUILT_SHARED_LIBRARY)

## libswresample.so
include $(CLEAR_VARS)
LOCAL_MODULE := swresample
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/$(TARGET_ARCH_ABI)/libswresample.so
include $(PREBUILT_SHARED_LIBRARY)

## libswscale.so
include $(CLEAR_VARS)
LOCAL_MODULE := swscale
LOCAL_SRC_FILES := $(LOCAL_PATH)/../jniLibs/$(TARGET_ARCH_ABI)/libswscale.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := native-lib
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
LOCAL_SHARED_LIBRARIES := avcodec avdevice avfilter avformat avutil swresample swscale
LOCAL_SRC_FILES := native-lib.c native-lib.h
include $(BUILD_SHARED_LIBRARY)

當(dāng)然炒刁,這還不夠恩沽,Android.mk算是完事了,但是呢翔始?你會發(fā)現(xiàn)在編譯的時候會有沖突罗心,因為編譯器不知道你的SO文件應(yīng)該放在那里,所以呢城瞎,需要我們告訴他渤闷,那怎么告訴他呢?其實也很簡單脖镀,就是在 build.gradle 文件的 android 節(jié)點中加入這一段

packagingOptions {

        pickFirst 'lib/armeabi-v7a/libavcodec.so'
        pickFirst 'lib/armeabi-v7a/libavdevice.so'
        pickFirst 'lib/armeabi-v7a/libavfilter.so'
        pickFirst 'lib/armeabi-v7a/libavformat.so'
        pickFirst 'lib/armeabi-v7a/libavutil.so'
        pickFirst 'lib/armeabi-v7a/libswresample.so'
        pickFirst 'lib/armeabi-v7a/libswscale.so'
        
        pickFirst 'lib/x86/libavcodec.so'
        pickFirst 'lib/x86/libavdevice.so'
        pickFirst 'lib/x86/libavfilter.so'
        pickFirst 'lib/x86/libavformat.so'
        pickFirst 'lib/x86/libavutil.so'
        pickFirst 'lib/x86/libswresample.so'
        pickFirst 'lib/x86/libswscale.so'
        
        pickFirst 'lib/arm64-v8a/libavcodec.so'
        pickFirst 'lib/arm64-v8a/libavdevice.so'
        pickFirst 'lib/arm64-v8a/libavfilter.so'
        pickFirst 'lib/arm64-v8a/libavformat.so'
        pickFirst 'lib/arm64-v8a/libavutil.so'
        pickFirst 'lib/arm64-v8a/libswresample.so'
        pickFirst 'lib/arm64-v8a/libswscale.so'
        
        pickFirst 'lib/x86_64/libavcodec.so'
        pickFirst 'lib/x86_64/libavdevice.so'
        pickFirst 'lib/x86_64/libavfilter.so'
        pickFirst 'lib/x86_64/libavformat.so'
        pickFirst 'lib/x86_64/libavutil.so'
        pickFirst 'lib/x86_64/libswresample.so'
        pickFirst 'lib/x86_64/libswscale.so'
    }

這表示飒箭,打包后的APK文件中的lib目錄下邊有幾種架構(gòu)的SO庫,并且每個架構(gòu)的文件夾里邊有多少SO蜒灰,名稱分別為什么

架構(gòu)打包過濾

如果在打包的時候弦蹂,不想把 x86,x86_64 這類打包到APK中强窖,這時應(yīng)該怎么操作呢凸椿?當(dāng)然你可能想的是,不編譯就行了翅溺,當(dāng)然這是最簡單粗暴的解決辦法脑漫,那么如何優(yōu)雅的處理這類問題呢?當(dāng)然是使用Gradle來進(jìn)行打包過濾啦咙崎,只需要在 build.gradle 文件中的 defaultConfig 節(jié)點下添加這么一段話就行了

ndk {
            abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
        }

abiFilters表示打包時需要打包哪些架構(gòu)的SO到APK中优幸,如果不需要的架構(gòu),直接注釋掉或者刪掉褪猛,如果有其他的架構(gòu)劈伴,自己添加上去即可,方便快捷,優(yōu)雅不單調(diào)跛璧,簡潔而大方

Android騷操作--簡單又實用的開發(fā)黑科技

2bda9ad633dfc754fbc51ff474bdfb0e_b.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市新啼,隨后出現(xiàn)的幾起案子追城,更是在濱河造成了極大的恐慌,老刑警劉巖燥撞,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件座柱,死亡現(xiàn)場離奇詭異,居然都是意外死亡物舒,警方通過查閱死者的電腦和手機色洞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冠胯,“玉大人火诸,你說我怎么就攤上這事≤欤” “怎么了置蜀?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長悉盆。 經(jīng)常有香客問我盯荤,道長,這世上最難降的妖魔是什么焕盟? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任秋秤,我火速辦了婚禮,結(jié)果婚禮上脚翘,老公的妹妹穿的比我還像新娘灼卢。我一直安慰自己,他們只是感情好堰怨,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布芥玉。 她就那樣靜靜地躺著,像睡著了一般备图。 火紅的嫁衣襯著肌膚如雪灿巧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天揽涮,我揣著相機與錄音抠藕,去河邊找鬼。 笑死蒋困,一個胖子當(dāng)著我的面吹牛盾似,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼零院,長吁一口氣:“原來是場噩夢啊……” “哼溉跃!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起告抄,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤撰茎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后打洼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體龄糊,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年募疮,在試婚紗的時候發(fā)現(xiàn)自己被綠了炫惩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡阿浓,死狀恐怖他嚷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情搔扁,我是刑警寧澤爸舒,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站稿蹲,受9級特大地震影響扭勉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜苛聘,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一涂炎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧设哗,春花似錦唱捣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至战虏,卻和暖如春拣宰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背烦感。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工巡社, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人手趣。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓晌该,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子朝群,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,077評論 25 707
  • 用兩張圖告訴你燕耿,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 12,714評論 2 59
  • 本人為初學(xué)者姜胖,文章寫得不好缸棵,如有錯誤,請大力懟我 或者看這里 如何使用jni進(jìn)行開發(fā) 本文主要針對Android環(huán)...
    AlbertHumbert閱讀 4,660評論 2 12
  • 一個人不寂寞谭期,想一個人才寂寞 思念是一種病,我以病入膏肓 你從我的世界悄然退場吧凉,我黯然神傷 凝視你離去的方向踽踽獨...
    vicky星兒閱讀 94評論 0 0