背景
最近在封裝一個分享功能庫,因為沒有自己的騰訊\微信\微博開放平臺賬號,所以使用了公司項目的api_key和keystore,于是帶來了一個問題,這些信息是絕對不能提交到github上去的,所以每次提交代碼時,都需要把相關的代碼刪除。某次,提交代碼時忘了這一步操作,誤將這些敏感的信息push到了github上,急忙使用git命令來挽救這次失誤:
git reset --hard <commit_id>
git push origin HEAD --force
在挽救回這次操作之后,我開始反思、尋找更好的解決方法,最終目標是讓 代碼脫敏 ,即無論怎么迭代代碼,push時都不用再擔心會把敏感信息誤提交了。
配置文件
首先,我們先來回顧一下Android Studio里的Project板塊,當展示模式切換成Android之后,我們會看到有一個Gradle Scripts的集合,今天的主角都在這里面,讓我們暫時先忘記日常寫代碼的module,把全部的注意力放在Gradle Scripts部分。
在圖中,我們可以看到gradle.properties(Global Properties)、gradle.prooperties(Project Properties)、local.properties(SDK Location)等三個配置文件,而它們就是我們的武器。
gradle.properties(Global Properties)
從文件名后的注釋我們可以知道,它是Gradle全局性的配置文件,在Linux、Mac中,它位于/Users/{YOUR_NAME}/.gradle/,windows用戶請自行google確定它的位置。也有部分用戶可能會沒有這個文件,此時應該自己創建一個,它會在我們日常工作中提供非常大的幫助。
打開這個文件,我們可以看到,里面默認配置了gradle的JVM最大可用內存、持久代可用大小、以及一些gradle的優化參數,這些配置是所有項目共享的。
跟隨這一思路,當我們有某些配置是所有項目都會用到的,那么就可以把它配置在這個文件中,這樣就不必每次新建、clone一個項目之后,還要去一一配置。比如bintray、nexus的賬號信息。
由于這個文件并不在項目下,所以我們可以大膽的把敏感信息配置在里面,而不用擔心會push到git上。
gradle.properties(Project Properties)
顧名思義,這個文件是項目級的配置文件,由于它會被提交到git上,所以不適合配置敏感信息,此處就不多做介紹。一般這個配置文件中會配置項目級的功能開關,比如android.useAndroidX、android.enableJetifier等。
在現在比較流行的組件化開發中,module是application還是library的開關通常也會配置在這里。
local.properties(SDK Location)
這個文件中默認配置了本地的sdk、ndk路徑。該文件的header中寫到:
This file must NOT be checked into Version Control Systems
然而,這個文件很多時候并不會被VCS忽略,所以需要手動將它排除。因此,在把敏感信息配置在這個文件中時,我們要確保它沒有被VCS收錄。
系統環境變量
除了上述3種配置文件之外,某些情況下,我們還可以使用系統環境變量來配置敏感信息。但是由于它是系統級的,某些情況下可能會無法正常讀取,甚至極端情況下會因為配置錯誤,導致系統宕機。所以,除非不得不配置在系統環境變量中,否則建議不要配置成系統環境變量。
讀取上述配置文件
在上一部分,我們了解了在一個 Android 項目中可以使用到的配置文件類型,現在來看一下,當配置完成之后,我們怎么讀取使用這些配置。
gradle.properties(Global AND Project)
- 在任意.gradle文件中,我們可以通過getProperties().get("KEY_NAME")方式來讀取參數值
def getRepositoryUsername() {
return getProperties().get('bintray.user')
}
def getRepositoryPassphrase() {
return getProperties().get('bintray.gpg.password')
}
def getApiKey() {
return getProperties().get("bintray.apikey")
}
- 在Android項目的build.gradle中,可以直接用KEY來獲取參數值
signingConfigs {
sign {
storeFile file(ANDROID_STORE_FILE)
storePassword ANDROID_STORE_PASSWORD
keyAlias ANDROID_KEY_ALIAS
keyPassword ANDROID_KEY_PASSWORD
}
}
local.properties
由于這個配置文件只供gradle程序使用,所以無法像gradle.properties那樣直接讀取。我們需要通過JDK的Properties類去手動加載它,然后讀取其中的參數
Properties properties = new Properties()
properties.load project.rootProject.file('local.properties').newDataInputStream()
def APP_ID = properties.getProperty("APP_ID")
def WB_ID = properties.getProperty("WB_ID")
def WX_ID = properties.getProperty("WX_ID")
def QQ_ID = properties.getProperty("QQ_ID")
系統環境變量
雖然不建議這種配置方式,但是還是簡單地介紹下讀取方法,由于它是系統級參數,所以在gradle文件中,我們可以通過System.getenv來讀取
def env = { System.getenv it }
signingConfigs {
sign {
storeFile file(env("ANDROID_STORE_FILE"))
storePassword env("ANDROID_STORE_PASSWORD")
keyAlias env("ANDROID_KEY_ALIAS")
keyPassword env("ANDROID_KEY_PASSWORD")
}
}
最佳實踐
在上文中介紹了不同的配置文件以及它的讀取方法。最后,我想介紹一下在這次封裝分享庫時的一些最佳實踐
- 不同項目間通用的配置建議放在Global Properties中,如Bintray、Nexus賬號信息
- 項目專有的敏感信息,如微信\騰訊\微博開放平臺的KEY建議放在local.properties中
- Project Properties中只存放不敏感的參數
- 除非必須,否則不要使用系統環境變量
末尾
安利一下使用kotlin語言封裝的分享庫RxShare,使用RxJava實現一行代碼完成分享。