本篇文章介紹瞭如何利用指令碼自動替換ApplicationId和PackageName
1 前言
平時如果想要替換包名一般是在AS中右鍵Rename進行操作。但是如果遇到一份程式碼希望匯出幾種不同的包名(不是ApplicationId),並且程式碼還會持續更新,這時候就需要使用指令碼在打包時自動匯出成不同包名的apk。
有的人會說直接可以在build.gradle裡面的productFlavors裡面設定,然後用placeHolder填充包名就行啦。 注意,這時候就要區分ApplicationId和PackageName了。
ApplicationId,是在手機中標識唯一應用的id。(看起來就是包名)
defaultConfig {
applicationId "com.tsy.xxx"
minSdkVersion 9
targetSdkVersion 23
versionCode 1
versionName "1.0"
multiDexEnabled true // Enabling multidex support.
}複製程式碼
PackageName,AndroidManifest裡面標明的package和每個java檔案裡面的package頭的包名。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tsy.xxx">複製程式碼
package com.tsy.xxx.xxx;
import xxx
public class MainActivity {
...
}複製程式碼
平時使用productFlavors+PlaceHolder匯出不同包只能匯出ApplicationId不同的包,的確可以匯出2個同時在手機安裝的包,但是其實package並沒有改變。當遇到以下情況時就會出現問題。
- 微信第三方接入時回撥要求在包名路徑下的.wxapi.WXCallBackxxx 固定寫死這個檔案才能回撥。就是說如果你修改了ApplicationId沒有修改PackageName是無法收到微信回撥的。
- 動態獲取資源的時候。經常會動態根據包名和資源名獲取資源,這時候由於PackageName沒有修改,也是會出錯。
2 怎麼修改PackageName
當我們瞭解了ApplicationId和PackageName的區別後,該怎麼修改PackageName呢。
正常情況下,修改PackageName可能是在以前的專案的基礎上開發新專案,這時候手動在AS裡面通過右鍵修改啪啪啪。即可搞定。
但是當出現以下需求呢,
- 希望一份程式碼可以匯出多個不同的包。
- 這份程式碼還可以持續迭代開發,並且每次釋出版本都希望匯出多個不同包。
這時候如果還使用手動修改包名明顯已經無法滿足。希望達到先用程式碼開發一個能執行的版本,每次釋出的時候用指令碼匯出多個不同包名的包。
3 匯出指令碼怎麼寫
好。前面介紹了那麼多前提,乾貨來了。使用指令碼釋出不同包名的包的步驟應該是以下的:
- 先從標準程式碼複製一份臨時程式碼出來
- 替換一些資原始檔或者string或者配置檔案。(需求是:不同的包希望圖示和app名不同)
- 使用gradle指令碼替換臨時程式碼裡的所有包名為目標包名
- clean & rebuild
3.1 複製臨時程式碼
這一步就是shell指令碼的執行復制,不再贅述。
3.2 替換資原始檔、配置資訊
這一步我使用php寫的,用shell指令碼呼叫執行php(如果只是替換資原始檔用shell指令碼複製就行),使用php寫主要考慮到修改string.xml中的某個值,比如修改app名。
修改string.xml部分程式碼如下:
$app_name = “指定的app_name”;
//讀取XML並解析
$string_doc = new DOMDocument();
$string_doc->load($temp_prj_dir . `app/src/main/res/values/strings.xml`);
$stringList = $string_doc->getElementsByTagName("string");
$len = $stringList->length;
for($i=0;$i<$len;$i++) {
$item = $stringList->item($i);//獲取列表中單條記錄
if($item->getAttribute(`name`) == "app_name") {
$item->nodeValue = $app_name;
break;
}
}
$string_doc->save($temp_prj_dir . `app/src/main/res/values/strings.xml`);
echo "修改app_name success
";複製程式碼
在這一步裡可以對其他一些配置資訊進行自定義和替換。用來區別不同的包。
3.3 替換包名
替換包名用gradle指令碼寫的。
task replacePackageName {
FileTree tree = fileTree(dir: `src/main`)
tree.include `**/*.java`
tree.include `**/*.xml`
tree.each {File mfile ->
fileReader(mfile.path, packageName)
}
fileReader("build.gradle", packageName)
}
def fileReader(path, target_package) {
def readerString = "";
def hasReplace = false
file(path).withReader(`UTF-8`) { reader ->
reader.eachLine {
if (it.find("com.tsy.xxx")) {
it = it.replace("com.tsy.xxx", target_package)
hasReplace = true
}
readerString <<= it
readerString << `
`
}
if(hasReplace) {
println(path + " has replace package.")
file(path).withWriter(`UTF-8`) {
within ->
within.append(readerString)
}
}
return readerString
}
}複製程式碼
可以看到,需要替換的檔案應該是所有的java檔案、xml檔案還有build.gradle檔案。其實就是讀取檔案樹,正則替換。php好的人直接php也可以替換成功。
3.4 clean & rebuild
替換成功後,用gradle命令執行下clean然後再匯出就OK拉。
4 結尾
最後給大家看下指令碼執行的最終效果。
結尾
更多文章關注我的公眾號