因爲官方的Android Gradle插件沒法解析在dependencies
中聲明的.so庫依賴,因此編譯時不會把.so文件自動拷貝到jniLibs
目錄下,這個插件主要就是爲了解決這個問題的,而且提供so文件重命名和abi過濾的實用功能.
另外若是你是使用maven和android-maven-plugin 構建Android項目,而且項目裏面有native依賴庫的,若是如今想轉移到Gradle構建系統上來,那麼這個插件正好合適. 開源項目地址:https://github.com/linsea/native-dependencies-pluginhtml
##使用說明 1. 引入插件java
buildscript { repositories { maven { url "https://plugins.gradle.org/m2/" } } dependencies { classpath "gradle.plugin.com.github.linsea:native-dependencies-plugin:0.2.1" } } //在*主模塊*項目中(好比APP項目中)應用插件, //不然可能遇到Android官方插件中的這個BUG:https://code.google.com/p/android/issues/detail?id=158630 apply plugin: "com.github.linsea.native-dependencies"
2. 聲明Native依賴庫
Native依賴庫的聲明仍是像一般同樣寫在dependencies
裏面,但要加上classifier和ext,好比:android
dependencies { compile "org.ffmpeg:algorithm:1.2.3:armeabi-v7a@so" }
若是你以前使用maven,應該明白這對應maven裏面以下的聲明:git
<dependency> <groupId>org.ffmpeg</groupId> <artifactId>algorithm</artifactId> <version>1.2.3</version> <classifier>armeabi-v7a</classifier> <type>so</type> </dependency>
3. 配置so文件的過濾與重命名規則
3.1 soFilters
在主模塊的build.gradle文件中添加一個nativeso
塊,裏面必須有一個soFilters
屬性,表示項目支持的平臺架構種類, 經過這個屬性區分so文件的類別屬於哪一個平臺架構,以便拷貝時把相應類別的so文件放到jniLibs
下面的相應目錄中. 被依賴的so文件的文件名中必須包含這個類別標識符,好比全部armeabi-v7a
平臺的相應so文件,在倉庫中文件的命名 必須包含有armeabi-v7a
這個串,不然沒法區別這個so文件究竟是屬於哪一個平臺的,也就沒法拷貝.
3.2 renaming
一般Linux平臺的so庫文件有必定的命名規則,好比有lib前綴,可是有些開發者提供的庫並無按這些規則來命名,若是 命名與加載時沒有對應起來,Android是加載不到so庫的.若是APP中引用多個庫,而命名又五花八門,爲了能使咱們把so庫 拷貝到jniLibs
下後Android能夠加載到庫,有時咱們須要重命名so文件.
**renaming
**就是定義命名規則的,一條renaming
規則能夠對應一個或多個so文件的命名,regex
是以正則表達式的 方式匹配so文件名,若是匹配到任意一次,則so文件名不會再繼續匹配下一條renaming
規則. 重命名時能夠定義 replaceAll
或者replaceWith
的方式,二者同時定義時, 僅replaceAll
生效而忽略replaceWith
. 以replaceAll
方式重命名時,其實是在so filename上執行String.replaceAll(regex,replaceAll). 而以replaceWith
方式重命名時,則支持正則表達式的佔位符($+數字表示)替換,功能更增強大,幾乎能夠知足全部命名需求. 具體能夠參考Gradle文檔中Copy的重命名.好比:github
regex = '(.*)_OEM_BLUE_(.*)' replaceWith = '$1$2'
prefix
表示so文件重命名後加入的前綴,通常須要lib前綴時能夠配置這個.正則表達式
注意
文件的重命名時,從上到下依次匹配規則,若是有一個匹配到了,則下面的規則會忽略跳過,若是最終一個規則都沒有匹配到,則文件不會重命名.api
如下是一個nativeso
的配置示例及說明:數組
nativeso { //.so filename MUST contains 'armeabi-v7a' or 'x86' to identify abi types soFilters = ['armeabi-v7a'] //['armeabi-v7a','x86'] //rename .so file: textsearch-1.2.3-armeabi-v7a.so -> libtextsearch.so renaming { prefix = 'lib' regex = 'textsearch-1.2.3-armeabi-v7a.*' replaceAll = 'textsearch' //not include ext .so } //rename .so file: libhello-1.4.10-armeabi-v7a.so -> libhello.so renaming { regex = 'libhello(.*)' replaceWith = 'libhello' } //rename .so file: libmysdk2-v7.0-armeabi-v7a.so -> libmysdk2.so renaming { regex = 'libmysdk(\\d+)-v(.*)' replaceWith = 'liblocSDK$1' } //默認命名規則: name-version-armeabi-v7a.so -> libname.so renaming { prefix = 'lib' regex = '(.*)-([\\d\\.]+)-(.*)' replaceWith = '$1' } }
##注意事項 插件會把so文件拷貝到jniLibs下對應的目錄下,好比jniLibs/armeabi-v7a,並且會利用Gradle提供的緩存機制,提升編譯速度,可是當依賴更新而過時時,須要從新下載並拷貝,在拷貝以前,插件會清空jniLibs目錄.所以若是你的主模塊項目已經包含了一些native依賴,而且.so文件已經放到jniLibs下的對應目錄下,那麼插件會同時把這些so文件也刪除.爲了不這種狀況發生,須要增長一個單獨 的jniLibs目錄給插件使用,好比:緩存
android { sourceSets { main { //... jniLibs.srcDirs += 'src/main/nativeso' //必定要加在數組的最後 } }
##使用技巧 1.插件增長了一個名爲collectso
的Task,而且利用了gradle的增量編譯機制,若是文件是新的,Task不會重複執行.若是重命名時須要調試腳本,能夠運行如下命令:架構
./gradlew -q --rerun-tasks collectso --info
查看插件的輸出日誌和重命名後的文件名,以便幫助定義重命名規則.
2.一般,若是你的APP僅支持有限的幾種ABI,則其餘全部不支持的ABI的so文件應該在APK打包中排除掉,不然在某些機型中沒法加載 對應ABI上缺失的so,在android plugin 2.2及以上版本能夠經過以下配置達到效果:
android { packagingOptions { //假設你的APP僅支持armeabi-v7a架構,則其餘的全部架構的so須要排除之 exclude '/lib/armeabi/**' exclude '/lib/arm64-v8a/**' exclude '/lib/x86/**' exclude '/lib/x86_64/**' exclude '/lib/mips/**' exclude '/lib/mips64/**' } }