來源博客:Wang Jie's Blog
本文鏈接:http://blog.wangjiegulu.com/2018/02/05/Android端生成META-INF信息文件的Gradle插件 RapidMetaInfPlugin/
版權聲明:本博客所有文章除特別聲明外,均采用 CC BY 4.0 CN協議 許可協議。轉載請注明出處。
Android端生成META-INF信息文件的Gradle插件 RapidMetaInfPlugin
1. 需求背景
最近新遇到了一個需求,想在自己的一些庫中寫入版本信息,在別人使用了我的庫后,我可以通過apk文件檢測出依賴了我的哪個版本的庫。感覺這個需求有點多余?那就舉個例子吧。
比如,我編寫了一個開源庫:RapidORM,並上傳到了Maven中心庫 ,假設一個我不認識的開發者(暫且稱它為X
)在編寫app,這個app中的代碼對我來說是完全未知的,但是他通過在build.gradle
中添加了如下依賴:
compile "com.github.wangjiegulu:rapidorm:1.0.0"
compile "com.github.wangjiegulu:rapidorm-api:1.0.0"
apt "com.github.wangjiegulu:rapidorm-compiler:1.0.0"
很明顯,X
依賴了我寫的RapidORM
庫。並且打包成了Apk文件然后發布。這時我下載了這個apk,並且希望得到這個apk中依賴的RapidORM
版本是多少?這個RapidORM
在構建這個aar時的開發環境是怎么樣的?反編譯可能有希望能拿到RapidORM
具體的版本號,但是aar當時的構建環境就無法得知了。
這時,我就希望在我發布RapidORM
的Release版本的時候能夠在aar中攜帶好一些自定義的參數,並且這些信息會在依賴了這個庫的開發者X
構建apk的時候跟隨保存到apk文件中。
比較典型的一個例子當你依賴了RxJava
這個庫,我們構建apk完成之后,會發現在我們的apk文件中的META-INF
文件夾下面會有一個rxjava.properties
文件,打開這個文件就會發現如下內容:
Manifest-Version=1.0
Implementation-Title=io.reactivex.rxjava2#rxjava;2.1.2
Implementation-Version=2.1.2
Built-Status=integration
Built-By=travis
Built-OS=Linux
Build-Date=2017-07-23_08:21:58
Gradle-Version=2.14
Module-Owner=benjchristensen@netflix.com
Module-Email=benjchristensen@netflix.com
Module-Source=
Module-Origin=https://github.com/ReactiveX/RxJava.git
Change=e4fbe4c
Branch=e4fbe4cfcb3c240d14a42a586eecbbd74cb379d2
Build-Host=testing-gce-361876de-b66f-4569-b841-e037b0fee9af
Build-Job=LOCAL
Build-Number=LOCAL
Build-Id=LOCAL
Created-By=1.7.0_80-b15 (Oracle Corporation)
Build-Java-Version=1.7.0_80
X-Compile-Target-JDK=1.6
X-Compile-Source-JDK=1.6
很顯然,這個文件中包含了:RxJava版本號
, 構建的CI信息
,構建時間
, Gradle版本
, 模塊負責人信息
, git分支
, JDK版本
等等。
通過這個方式,我可以在任意的apk中拿到它依賴的RxJava
的信息。
當然,你可以通過在build.gradle
進行如下配置來過排除這個rxjava.properties
文件(但是不建議這么做,這個文件也許能在你遇到問題時給你幫助):
android {
...
packagingOptions {
exclude 'META-INF/rxjava.properties'
}
}
2. RapidMetaInfPlugin Gradle 插件
RapidMetaInfPlugin: https://github.com/wangjiegulu/RapidMetaInfPlugin
因此,寫了 RapidMetaInfPlugin 這個 Gradle 插件。
這次先說說怎么使用這個插件,以后抽時間再寫一篇 Gradle 插件編寫教程。之前也寫過一個Gradle插件(詳情見Android Gradle 插件 DiscardFilePlugin(清空類和方法))也挺實用的。
2.1 最終效果
通過這個插件,我們可以在apk
或者aar
(app
依賴后合並到apk
)中寫入任意信息。

以上在這個apk
的META-INF
中生成了一個名為DAL_REQUEST.properties
的文件,內容中包含了dal_request
這個庫的名字、版本號和url。
2.2 如何使用
在你的buildscript
的dependencies
中添加classpath
依賴(點擊這里獲取最新版本):
buildscript {
repositories {
jcenter()
google()
}
dependencies {
// ...
classpath ('com.github.wangjiegulu:rapidmetainf:x.x.x'){
exclude group: 'com.android.tools.build', module: 'gradle'
}
}
}
然后在你的apk或者aar的build.gradle
文件的頂部寫入以下代碼來使用插件:
apply plugin: 'com.github.wangjiegulu.plg.rapidmetainf'
然后通過如下方式填寫你需要寫進META-INF
目錄中的文件信息:
rapidmetainf {
metaInfName 'DAL_REQUEST.properties'
metaInfProperties "archiveName=$dbarchiveName",
"archiveVersion=$dbarchiveVersion",
"archiveUrl=$dbarchiveUrl"
}
如上,metaInfName
表示在META-INF
目錄中生成的文件名稱(文件名任意取,但是不能以"."開頭),metaInfProperties
表示要寫入文件的數據,這個變量為數組類型,可通過Groovy語法來編寫,比如通過$符號來引用ext
,通過如下命令參數的方式等等:
rapidmetainf {
metaInfName 'DAL_REQUEST_DEMO.properties'
String[] infArray = new String[10]
// ./gradlew clean build -PcommandKey=commandValue
infArray[0] = "propertyFromCommand=${getParameter('commandKey')}"
for(int i = 1; i < infArray.length; i++){
infArray[i] = "array_item_key_$i=array_item_value_$i"
}
metaInfProperties infArray
}
def getParameter(String key) {
// -D
String value = System.getProperty(key)
if (null != value && value.length() > 0) {
return value
}
// -P
if (hasProperty(key)) {
return getProperty(key)
}
return null
}
以上,CI構建時就可使用命令./gradlew clean build -PcommandKey=commandValue
來把commandValue
寫入到文件中。