有效果的Android編譯so文件及使用

0.前言

根據(jù)不成文的規(guī)則溉仑,這里還是要廢話幾句的挖函。
看標(biāo)題,我特意加上了“有效果”三字浊竟,沒錯(cuò)怨喘,今天我來給大伙填坑了。
因公司業(yè)務(wù)需求振定,與第三方商家合作必怜,需要調(diào)用商家提供的so庫,對(duì)此知識(shí)一無所知的我踏上了一條踩坑之路后频。

1.導(dǎo)入so庫

廢話不多說梳庆,直接切入正題。
網(wǎng)上的方法卑惜,只要新建jni包然后將so庫放入其中即可使用膏执。但是,本文說的是編譯露久,如果你要編譯一個(gè)so庫更米,這個(gè)庫又需要引用本地so庫,這個(gè)方法是不行的

2.編譯so庫

編譯so庫的方法主要分為mk編譯和cmake編譯這兩種方式抱环。

(1)mk方式編譯獨(dú)立的so庫

先來看看mk編譯的方式壳快。
首先要在gradle.properties文件里面添加

android.useDeprecatedNdk=true

然后在build之中添加代碼:

android{
` ` `
sourceSets {
        main{
            jni.srcDirs=[]; //禁用as自動(dòng)生成mk
            jniLibs.srcDirs = ['src/main/jniLibs']//設(shè)置目標(biāo)的so存放路徑
        }
    }
 //設(shè)置編譯任務(wù)纸巷,編譯ndkBuild
    tasks.withType(JavaCompile) {
        compileTask -> compileTask.dependsOn 'ndkBuild'
    }
` ` `
}
task ndkBuild(type: Exec, description: 'Compile JNI source via NDK') {
    //ndk路徑镇草,一定要加上這部分
    commandLine "C:\\Users\\Administrator\\AppData\\Local\\Android\\Sdk\\ndk-bundle\\ndk-build.cmd",
            'NDK_PROJECT_PATH=build/intermediates/ndk',
            'NDK_LIBS_OUT=src/main/jniLibs',
            'APP_BUILD_SCRIPT=src/main/jni/Android.mk',
            'NDK_APPLICATION_MK=src/main/jni/Application.mk'
}

然后新建一個(gè)jni目錄(相信大伙都懂,這里就不羅嗦怎么建立)瘤旨,在jni目錄下添加Android.mk和Application.mk這兩個(gè)文件梯啤,編寫代碼如下

  • Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := dp
LOCAL_SRC_FILES := dp.cpp
LOCAL_LDLIBS :=-llog
include $(BUILD_SHARED_LIBRARY)

dp即自己編寫的cpp文件,位于jni目錄下存哲,名字可以隨意取因宇,但要對(duì)得上。
然在Application.mk文件里寫明要編譯的平臺(tái)祟偷。比如

#模擬器是 x86_64 的
APP_ABI := x86_64

這里的x86_64指編譯出x86_64平臺(tái)的so庫察滑,如果選擇all,即編譯出所有的平臺(tái)的so庫修肠。
然后運(yùn)行一下贺辰,即可編譯出對(duì)應(yīng)的libdp.so庫文件,放在['src/main/jniLibs']目錄下。
這里特別指出重點(diǎn):

task ndkBuild(type: Exec, description: 'Compile JNI source via NDK') {
    //ndk路徑饲化,一定要加上這部分
    commandLine "C:\\Users\\Administrator\\AppData\\Local\\Android\\Sdk\\ndk-bundle\\ndk-build.cmd",
            'NDK_PROJECT_PATH=build/intermediates/ndk',
            'NDK_LIBS_OUT=src/main/jniLibs',
            'APP_BUILD_SCRIPT=src/main/jni/Android.mk',
            'NDK_APPLICATION_MK=src/main/jni/Application.mk'
}

這段代碼一定要加上去莽鸭,不如編譯不過。博主曾在網(wǎng)上搜到過片段代碼與此相似吃靠,奈何其博主沒有詳細(xì)說明也沒有完整說明硫眨,無法理解。此處給出完整例子希望有所幫助巢块。(至于dp.cpp的代碼礁阁,先不給出,這不是本文重點(diǎn))

(2)mk方式引入第三方so庫

為了便于說明族奢,這里給第三方庫取個(gè)名氮兵,就叫sb庫好了,完整名是libsb.so
歹鱼。
導(dǎo)入第三方so庫泣栈,必須要注意他支持的平臺(tái),需要與你的Application.mk中設(shè)置的相對(duì)應(yīng)(如果對(duì)不上弥姻,改為相對(duì)應(yīng)的)南片,否則會(huì)編譯不通過的(重點(diǎn),小編在這問題上被坑得死死的庭敦,希望讀者能吸取小編的教訓(xùn))疼进。
接下來講重點(diǎn):

  • 1.將libsb.so庫放在jni目錄下,然后重新編寫Android.mk文件代碼:
LOCAL_PATH := $(call my-dir)
#引入第三方 so
include $(CLEAR_VARS)
LOCAL_MODULE    := sb
LOCAL_SRC_FILES := sb.so
LOCAL_EXPORT_C_INCLUDES := include
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE    := dp
LOCAL_SRC_FILES := dp.cpp
LOCAL_LDLIBS :=-llog

#引入第三方編譯模塊
LOCAL_SHARED_LIBRARIES := \sb
include $(BUILD_SHARED_LIBRARY)

這樣一來(只有這樣)秧廉,你就可以在dp.cpp代碼里面編寫調(diào)用libsb.so庫里面的方法了伞广。如果你只是單純把它放到j(luò)niLibs目錄下,那是不行的疼电。

  • 2.你還是得老老實(shí)實(shí)的把它放到j(luò)niLibs目錄下嚼锄,因?yàn)槟愕臉I(yè)務(wù)代碼里面要用到它必然需要把它導(dǎo)進(jìn)去,需要用到哪些庫就放到j(luò)niLibs目錄下蔽豺,別忘了在這些so的上一層加上他的平臺(tái)文件包区丑。
    如此一來,再run一下就沒問題了修陡。
(3)cmake方式編譯

使用cmake方式編譯沧侥,那就真的是太即便簡便太簡單了。我這么說讀者可能會(huì)不服氣魄鸦,眼見為實(shí)吧宴杀。

  • 1.編寫cpp文件
    正常操作,編寫cpp文件拾因,相信這一步不是問題旺罢,這里就取名為mb.cpp吧斯棒,此處就放在main/cpp/目錄下好了。然后再編寫cmake的代碼(語法在你新建支持c++文件的項(xiàng)目時(shí)產(chǎn)生的cmakeLists.txt中有介紹)
    這里直接給出代碼:
add_library(mb SHARED src/main/cpp/mb.cpp)
target_link_libraries( # Specifies the target library
                        mb                  
                       ${log-lib} )

先用add_library將mb添加進(jìn)去主经,再在target_link_libraries里關(guān)聯(lián)即可荣暮。
如果你的mb.cpp文件里面include了其他頭文件,你還需加上

include_directories(scr/main/cpp/include/ )

聲明頭文件的部分罩驻,否則會(huì)編譯失敗找不到頭文件的(坑)穗酥。
注意:習(xí)慣使用mk編譯的童鞋這里注意了,使用cmake的方式編譯是不會(huì)生成so文件的(坑)惠遏,所以你不用去找libmb.so文件了=-=砾跃。
但是你還是要在你的代碼里面導(dǎo)入庫時(shí)把它倒進(jìn)去:

System.loadLibrary("mb");
(4)cmake引入第三方so庫

這里就給第三方so取名為nb好了(具體的當(dāng)然要與讀者的相同啦),完整名字libnb.so节吮。
不廢話抽高,上代碼:

#導(dǎo)入第三方so包
#IMPORTED 指只是把 so 導(dǎo)入到項(xiàng)目中
add_library( nb
             SHARED
             IMPORTED )
#指明 so 庫的路徑
set_target_properties( # Specifies the target library.
            nb
            # Specifies the parameter you want to define.
            PROPERTIES IMPORTED_LOCATION
            # Provides the path to the library you want to import.
       ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libvvw.so )

#頭文件路徑
include_directories(scr/main/cpp/include/ )
add_library(mb SHARED src/main/cpp/mb.cpp)
target_link_libraries( # Specifies the target library.
                        mb
                        #關(guān)聯(lián)第三方 so
                        nb
                       ${log-lib} )

ANDROID_ABI指平臺(tái),同樣透绩,你需要將你的第三方so庫放入到可識(shí)別的路徑文件下(這里放在jniLibs目錄下)翘骂,上一層需加上平臺(tái)的文件夾,比如/jniLibs/x86/libnb.so這樣子帚豪,如果你這里選ANDROID_ABI碳竟,則會(huì)默認(rèn)編譯你在build中設(shè)定的平臺(tái),比如在build中加入:

android {
    compileSdkVersion 26
    buildToolsVersion "26.0.2"
    defaultConfig {
        applicationId "com.zhengsr.jnidemo_camke"
        minSdkVersion 19
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags "-frtti -fexceptions"
            }
        }
        ndk{
            abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a'//重點(diǎn)
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }

}

重點(diǎn)看:

ndk{
            abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a'//重點(diǎn)
        }

那他就會(huì)默認(rèn)編譯 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a'平臺(tái)的第三方so狸臣,如果你在這里使用了ANDROID_ABI莹桅,而你的jniLibs路徑下恰好沒有以上全部平臺(tái)的libnb.so庫,則會(huì)編譯失敗烛亦,這時(shí)你就需要將ANDROID_ABI改為你所擁有的平臺(tái)或補(bǔ)充相應(yīng)的so文件诈泼。

說到底,這一步煤禽,路徑很重要铐达,必須配置正確,否則會(huì)有一堆問題呜师,然后網(wǎng)上一堆無關(guān)說法娶桦、解決方法等你去踩坑.

通過以上配置贾节,就可以愉快的引用你的so庫了汁汗,想怎么用就怎么用,不怕報(bào)在cpp文件里面找不到庫里面的方法(某方法未聲明)的錯(cuò)誤

總結(jié)還是得要有的

3.總結(jié)

不管是mk編譯方法還是cmake編譯方法栗涂,都是可取的方法知牌。但是相較而言,cmake編譯的方法明顯勝于mk編譯的方法斤程,不用生成so庫文件即可使用角寸。
二者的使用方法上有共通之處菩混,需要注意的是路徑一定要配置正確
由于cpp的文件書寫以及utils的代碼相關(guān)部分本文并不給出扁藕,需要讀者自行搜索了沮峡。希望此文對(duì)你有所幫助。
如有問題和錯(cuò)誤的地方亿柑,歡迎留言提出邢疙!
原創(chuàng)文章,轉(zhuǎn)載請(qǐng)附上

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末望薄,一起剝皮案震驚了整個(gè)濱河市疟游,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌痕支,老刑警劉巖颁虐,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件智末,死亡現(xiàn)場離奇詭異虾标,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)南吮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門花嘶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來板熊,“玉大人,你說我怎么就攤上這事察绷「汕” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵拆撼,是天一觀的道長容劳。 經(jīng)常有香客問我,道長闸度,這世上最難降的妖魔是什么竭贩? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮莺禁,結(jié)果婚禮上留量,老公的妹妹穿的比我還像新娘。我一直安慰自己哟冬,他們只是感情好楼熄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著浩峡,像睡著了一般可岂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上翰灾,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天缕粹,我揣著相機(jī)與錄音稚茅,去河邊找鬼。 笑死平斩,一個(gè)胖子當(dāng)著我的面吹牛亚享,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播绘面,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼虹蒋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了飒货?” 一聲冷哼從身側(cè)響起魄衅,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎塘辅,沒想到半個(gè)月后晃虫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扣墩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年哲银,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呻惕。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡荆责,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出亚脆,到底是詐尸還是另有隱情做院,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布濒持,位于F島的核電站键耕,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏柑营。R本人自食惡果不足惜屈雄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望官套。 院中可真熱鬧酒奶,春花似錦、人聲如沸奶赔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纺阔。三九已至瘸彤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間笛钝,已是汗流浹背质况。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留玻靡,地道東北人结榄。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像囤捻,于是被迫代替她去往敵國和親臼朗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354