前言
希望通過(guò)本文能夠幫助之前沒(méi)有接觸過(guò) Tinker 的同學(xué)邢笙,快速了解利用 Tinker 生成及使用補(bǔ)丁包的過(guò)程。
Tinker 版本:1.8.1
Tinker 官方文檔:https://github.com/Tencent/tinker/wiki
gradle 接入
我沒(méi)有 clone 官方的例子,也沒(méi)有在現(xiàn)有項(xiàng)目上直接接入,而是創(chuàng)建了一個(gè)新的項(xiàng)目。
在項(xiàng)目的 build.gradle 中憨愉,添加tinker-patch-gradle-plugin
依賴:
buildscript {
dependencies {
classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.8.1')
}
}
然后在 app 的 gradle 文件 app/build.gradle,添加 tinker 的庫(kù)依賴以及 apply tinker 的 gradle 插件:
dependencies {
provided('com.tencent.tinker:tinker-android-anno:1.8.1')
compile('com.tencent.tinker:tinker-android-lib:1.8.1')
}
...
apply plugin: 'com.tencent.tinker.patch'
在這一步不用著急編譯卿捎,下面還有 gradle 的詳細(xì)配置配紫。
生成 Application
tinker 建議編寫(xiě)一個(gè) DefaultApplicationLike 的子類,并使用@DefaultLifeCycle
注解生成 Application.
@DefaultLifeCycle(application = ".MyApplication", //要生成的application名稱
flags = ShareConstants.TINKER_ENABLE_ALL)
public class MyApplicationLike extends DefaultApplicationLike {
public MyApplicationLike(Application application, int tinkerFlags, boolean tinkerLoadVerifyFlag,
long applicationStartElapsedTime, long applicationStartMillisTime, Intent tinkerResultIntent) {
super(application, tinkerFlags, tinkerLoadVerifyFlag,
applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent);
}
@Override
public void onBaseContextAttached(Context base) {
super.onBaseContextAttached(base);
TinkerInstaller.install(this);
}
}
注意 application 名稱為.MyApplication
午阵,我創(chuàng)建的 MyApplicationLike 所在的包為tech.gujin.tinkersample.application
躺孝,生成的 MyApplication 也在這個(gè)包下〉坠穑或者將包名寫(xiě)全:application = "tech.gujin.tinkersample.application.MyApplication"
植袍,生成的文件都是一樣的。
之后注冊(cè) Application 到 AndroidManifest 中:
<application
android:name="tech.gujin.tinkersample.application.MyApplication"
...
</application>
如果報(bào)錯(cuò)現(xiàn)在不用處理籽懦,編譯后會(huì)自動(dòng)生成的于个。
gradle 配置
我直接拷貝了官方例子,修改了其中獲取 tinkerId 的方法暮顺,bakPath 的路徑厅篓,移除了多渠道部分。
def bakPath = file("./tinker-old/") //可自行定義文件路徑
ext {
tinkerId = "tinker_id_" + android.defaultConfig.versionName + "_" + android.defaultConfig.versionCode
tinkerEnabled = true
tinkerOldApkPath = "${bakPath}/app-release-1.0-1.apk" //可自行修改文件名
tinkerApplyMappingPath = "${bakPath}/app-release-1.0-1-mapping.txt"
tinkerApplyResourcePath = "${bakPath}/app-release-1.0-1-R.txt"
}
因?yàn)橐裳a(bǔ)丁捶码,tinker 需要上一個(gè)版本的安裝包用來(lái)比較差異羽氮。
我創(chuàng)建了tinker-old
文件夾,放入上一個(gè)版本名為app-release-1.0-1.apk
的安裝包惫恼,并將路徑設(shè)置給 tinkerOldApkPath.
為了減少補(bǔ)丁包的大小档押,還可以繼續(xù)設(shè)置 tinkerApplyMappingPath 和 tinkerApplyResourcePath.
其余地方并無(wú)太大變化,更多可以看修改后的gradle祈纯。
首次接入沒(méi)有舊的安裝包也不用擔(dān)心令宿,如果指定文件不存在 tinker 會(huì)自動(dòng)忽略。
使用前的準(zhǔn)備
創(chuàng)建一個(gè)很簡(jiǎn)單的 Activity:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((TextView) findViewById(R.id.tv_msg)).setText("此版本存在BUG");
File file = new File(getExternalCacheDir(), "/patch_signed_7zip.apk");
if (file.exists()) {
TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(), file.getAbsolutePath());
}
}
}
這里省去了訪問(wèn)服務(wù)器判斷有沒(méi)有補(bǔ)丁包和下載的邏輯盆繁,簡(jiǎn)化為如果/storage/emulated/0/Android/data/tech.gujin.tinkersample/cache
目錄下有patch_signed_7zip.apk
補(bǔ)丁包就進(jìn)行更新掀淘。
然后編譯一個(gè) release 包旬蟋,安裝到手機(jī)上:
制作補(bǔ)丁包
修改 TextView 的文字油昂,然后升級(jí)下 versionCode 和 versionName,就當(dāng)是 1.1 版本修復(fù)了 1.0 版本的 Bug.
剛才的打包過(guò)程會(huì)自動(dòng)將 apk,mapping 和 R 文件復(fù)制到tinker-old
文件夾中冕碟,根據(jù)文件名配置下 tinkerOldApkPath拦惋、tinkerApplyMappingPath 和 tinkerApplyResourcePath.
然后在 Terminal 輸入 gradlew tinkerPatchRelease
,或者在 Gradle projects 中找到相應(yīng)的 project 運(yùn)行即可安寺。
等運(yùn)行結(jié)束后厕妖,補(bǔ)丁包生成在/build/outputs/tinkerPatch
目錄下,使用patch_signed_7zip.apk
挑庶,它是簽名后并使用 7zip 壓縮的補(bǔ)丁包言秸。
到此為止,補(bǔ)丁包就制作好了迎捺。
使用補(bǔ)丁
本例中簡(jiǎn)化了流程举畸,我直接將補(bǔ)丁放到 /storage/emulated/0/Android/data/tech.gujin.tinkersample/cache
目錄。
殺死進(jìn)程重新打開(kāi)應(yīng)用凳枝,可以看到打印出 log:
I/Tinker.DefaultTinkerResultService: DefaultTinkerResultService received a result:
PatchResult:
isSuccess:true
rawPatchFilePath:/storage/emulated/0/Android/data/tech.gujin.tinkersample/cache/patch_signed_7zip.apk
costTime:530
patchVersion:a5c8417e691fd9cffe83c11cd0d37eff
然后應(yīng)用直接退出了抄沮,這是因?yàn)?tinker 提供的 DefaultTinkerResultService 中,補(bǔ)丁升級(jí)成功后會(huì)殺死當(dāng)前進(jìn)程岖瑰,可以繼承 DefaultTinkerResultService 實(shí)現(xiàn)自己的回調(diào)叛买。
再次打開(kāi)應(yīng)用可以看到補(bǔ)丁已經(jīng)生效了:
至此,tinker 生成及更新補(bǔ)丁包的過(guò)程就已經(jīng)介紹完畢了蹋订。
代碼已托管至 Github:GuJin/TinkerSample
謝謝大家率挣。