Android 原生庫依賴解析Gradle插件

因爲官方的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/**'
    }
}
相關文章
相關標籤/搜索