Tinker 接入指南

Tinker 接入指南

gradle接入

gradle是推薦的接入方式,在gradle插件tinker-patch-gradle-plugin中我們幫你完成proguard、multiDex以及Manifest處理等工作。

添加gradle依賴

在項目的build.gradle中,添加tinker-patch-gradle-plugin的依賴

buildscript {
    dependencies {
        classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.7.5')
    }
}

然後在app的gradle文件app/build.gradle,我們需要添加tinker的庫依賴以及apply tinker的gradle插件.

dependencies {
    //可選,用於生成application類 
    provided('com.tencent.tinker:tinker-android-anno:1.7.5')
    //tinker的核心庫
    compile('com.tencent.tinker:tinker-android-lib:1.7.5') 
}
...
...
//apply tinker插件
apply plugin: 'com.tencent.tinker.patch'

gradle參數詳解

我們將原apk包稱爲基準apk包,tinkerPatch直接使用基準apk包與新編譯出來的apk包做差異,得到最終的補丁包。gradle配置的參數詳細解釋如下:

參數 默認值 描述
tinkerPatch   全局信息相關的配置項
oldApk null 基準apk包的路徑,必須輸入,否則會報錯。
ignoreWarning false 如果出現以下的情況,並且ignoreWarning爲false,我們將中斷編譯。因爲這些情況可能會導致編譯出來的patch包帶來風險:
1. minSdkVersion小於14,但是dexMode的值爲"raw";
2. 新編譯的安裝包出現新增的四大組件(Activity, BroadcastReceiver...);
3. 定義在dex.loader用於加載補丁的類不在main dex中;
4. 定義在dex.loader用於加載補丁的類出現修改;
5. resources.arsc改變,但沒有使用applyResourceMapping編譯。
useSign true 在運行過程中,我們需要驗證基準apk包與補丁包的簽名是否一致,我們是否需要爲你簽名。
buildConfig   編譯相關的配置項
applyMapping null 可選參數;在編譯新的apk時候,我們希望通過保持舊apk的proguard混淆方式,從而減少補丁包的大小。這個只是推薦的,但設置applyMapping會影響任何的assemble編譯
applyResourceMapping null 可選參數;在編譯新的apk時候,我們希望通過舊apk的R.txt文件保持ResId的分配,這樣不僅可以減少補丁包的大小,同時也避免由於ResId改變導致remote view異常
tinkerId null 在運行過程中,我們需要驗證基準apk包的tinkerId是否等於補丁包的tinkerId。這個是決定補丁包能運行在哪些基準包上面,一般來說我們可以使用git版本號、versionName等等。
dex   dex相關的配置項
dexMode jar 只能是'raw'或者'jar'。 
對於'raw'模式,我們將會保持輸入dex的格式。
對於'jar'模式,我們將會把輸入dex重新壓縮封裝到jar。如果你的minSdkVersion小於14,你必須選擇‘jar’模式,而且它更省存儲空間,但是驗證md5時比'raw'模式耗時()。
usePreGeneratedPatchDex flase 是否提前生成dex,而非合成的方式。這套方案即回退成Qzone的方案,對於需要使用加固或者多flavor打包(建議使用其他方式生成渠道包)的用戶可使用。但是這套方案需要插樁,會造成Dalvik下性能損耗以及Art補丁包可能過大的問題,務必謹慎使用。另外一方面,這種方案在Android N之後可能會產生問題,建議過濾N之後的用戶。
pattern [] 需要處理dex路徑,支持*、?通配符,必須使用'/'分割。路徑是相對安裝包的,例如/assets/...
loader [] 這一項非常重要,它定義了哪些類在加載補丁包的時候會用到。這些類是通過Tinker無法修改的類,也是一定要放在main dex的類。
這裏需要定義的類有:
1. 你自己定義的Application類;
2. Tinker庫中用於加載補丁包的部分類,即com.tencent.tinker.loader.*; 
3. 如果你自定義了TinkerLoader,需要將它以及它引用的所有類也加入loader中;
4. 其他一些你不希望被更改的類,例如Sample中的BaseBuildInfo類。這裏需要注意的是,這些類的直接引用類也需要加入到loader中。或者你需要將這個類變成非preverify。
lib   lib相關的配置項
pattern [] 需要處理lib路徑,支持*、?通配符,必須使用'/'分割。與dex.pattern一致, 路徑是相對安裝包的,例如/assets/...
res   res相關的配置項
pattern [] 需要處理res路徑,支持*、?通配符,必須使用'/'分割。與dex.pattern一致, 路徑是相對安裝包的,例如/assets/...,務必注意的是,只有滿足pattern的資源纔會放到合成後的資源包。
ignoreChange [] 支持*、?通配符,必須使用'/'分割。若滿足ignoreChange的pattern,在編譯時會忽略該文件的新增、刪除與修改。 最極端的情況,ignoreChange與上面的pattern一致,即會完全忽略所有資源的修改。
largeModSize 100 對於修改的資源,如果大於largeModSize,我們將使用bsdiff算法。這可以降低補丁包的大小,但是會增加合成時的複雜度。默認大小爲100kb
packageConfig   用於生成補丁包中的'package_meta.txt'文件
configField TINKER_ID, NEW_TINKER_ID configField("key", "value"), 默認我們自動從基準安裝包與新安裝包的Manifest中讀取tinkerId,並自動寫入configField。在這裏,你可以定義其他的信息,在運行時可以通過TinkerLoadResult.getPackageConfigByName得到相應的數值。但是建議直接通過修改代碼來實現,例如BuildConfig。
sevenZip   7zip路徑配置項,執行前提是useSign爲true
zipArtifact null 例如"com.tencent.mm:SevenZip:1.1.10",將自動根據機器屬性獲得對應的7za運行文件,推薦使用。
path 7za 系統中的7za路徑,例如"/usr/local/bin/7za"。path設置會覆蓋zipArtifact,若都不設置,將直接使用7za去嘗試。

具體的參數設置事例可參考sample中的app/build.gradle

tinkerPatch task詳解

直接使用task:tinkerPatchVariantName(例如tinkerPatchDebug、tinkerPatchRelease)即可自動根據Variant選擇相應的編譯類型,同時它還貼心的爲我們完成以下幾個操作:

  1. 將TINKER_ID自動插入AndroidManifest的meta項,輸出路徑爲build/intermediates/tinker_intermediates/AndroidManifest.xml;

  2. 如果minifyEnabled爲true,將自動將Tinker的proguard規則添加到proguardFiles中,輸出路徑爲build/intermediates/tinker_intermediates/tinker_proguard.pro,這裏你不需要將它們拷貝到自己的proguard配置文件中;

  3. 如果multiDexEnabled爲true,將自動生成Tinker需要放在主dex的keep規則,你需要手動將生成規則拷貝到自己的multiDexKeepProguard文件中。這是因爲它是一個單獨的文件,而proguardFiles是一個list。例如Sample中的multiDexKeepProguard file("keep_in_main_dex.txt")

  4. 把dexOptions的jumboMode打開。

輸出路徑爲:build/intermediates/tinker_intermediates/tinker_multidexkeep.pro。 後你可以在build/outputs/tinkerPatch中找到輸出的文件。

多Flavor打包

有的時候我們希望通過flavor方式打包,在sample中提供了簡單的用法事例:

1.通過flavor編譯,這個時候我們可以看到bakApk路徑是一個按照flavor名稱區分的目錄;

2.將編譯目錄路徑填寫到sample中tinkerBuildFlavorDirectory,其他的幾個字段不需要填寫,這裏會自動根據路徑拼接;

ext {
    tinkerBuildFlavorDirectory = "${bakPath}/app-1014-13-35-12"
}

3.運行tinkerPatchAllFlavorDebug或者tinkerPatchAllFlavorRelease即可得到所有flavor的補丁包。

輸出文件詳解

在tinkerPatch輸出目錄build/outputs/tinkerPatch中,我們關心的文件有:

文件名 描述
patch_unsigned.apk 沒有簽名的補丁包
patch_signed.apk 簽名後的補丁包
patch_signed_7zip.apk 簽名後並使用7zip壓縮的補丁包,也是我們通常使用的補丁包。但正式發佈的時候,最好不要以.apk結尾,防止被運營商挾持。
log.txt 在編譯補丁包過程的控制檯日誌
dex_log.txt 在編譯補丁包過程關於dex的日誌
so_log.txt 在編譯補丁包過程關於lib的日誌
tinker_result 最終在補丁包的內容,包括diff的dex、lib以及assets下面的meta文件
resources_out.zip 最終在手機上合成的全量資源apk,你可以在這裏查看是否有文件遺漏
resources_out_7z.zip 根據7zip最終在手機上合成的全量資源apk
tempPatchedDexes 在Dalvik與Art平臺,最終在手機上合成的完整Dex,我們可以在這裏查看dex合成的產物。

每次編譯結束,我們都應該查看相關日誌,清楚最終在補丁包中的文件。尤其是dex的補丁文件,即使是1k的dex補丁文件,也會帶來合成時的時間損耗以及合成完整dex文件ROM空間體積這兩部分影響!

命令行接入

命令行工具tinker-patch-cli.jar提供了基準包與新安裝包做差異,生成補丁包的功能。具體的命令參數如下:

java -jar tinker-patch-cli.jar -old old.apk -new new.apk -config tinker_config.xml -out output_path

參數與gradle基本一致,新增的sign參數,我們需要輸入簽名路徑與簽名信息。

與gradle不同的是,在編譯時我們需要將TINKER_ID插入到AndroidManifest.xml中。例如

<meta-data android:name="TINKER_ID" android:value="tinker_id_b168b32"/>

同時,我們需要自己保證proguard文件以及main dex類是正確的。具體配置可參考以下幾個文件:

如何快速獲得依賴包

使用tinker-git:buildSdk任務即可在根目錄的buildSdk文件夾中獲得所有需要的文件。

其中包括:

  1. build; 編譯時用到的工具,主要是tinker-patch-cli.jar以及一些可能用到的配置信息;
  2. android;需要放到手機端的依賴庫,其中tinker-android-anno.jar爲可選庫,只有用到Tinker的annotation的才需要引入。

使用步驟詳解

Sample的使用方法

Demo請參考tinker-sample-android, 它的使用方法如下:

  1. 調用assembleDebug編譯,我們會將編譯過的包保存在build/bakApk中。然後我們將它安裝到手機,點擊SHOW INFO按鈕,可以看到補丁並沒有加載.

    請在這裏輸入圖片描述

  2. 修改代碼,例如將MainActivityI am on patch onCreate的Log打開。然後我們需要修改build.gradle中的參數,將步驟一編譯保存的安裝包路徑拷貝到tinkerPatch中的oldApk參數中。

    請在這裏輸入圖片描述

  3. 調用tinkerPatchDebug, 補丁包與相關日誌會保存在/build/outputs/tinkerPatch/。然後我們將patch_signed_7zip.apk推送到手機的sdcard中。

    adb push ./app/build/outputs/tinkerPatch/debug/patch_signed_7zip.apk /storage/sdcard0/
  4. 點擊LOAD PATCH按鈕, 如果看到patch success, please restart process的toast,即可鎖屏或者點擊KILL SELF按鈕

    請在這裏輸入圖片描述

  5. 我們可以看到的確出現了I am on patch onCreate日誌,同時點擊SHOW INFO按鈕,顯示補丁包的確已經加載成功了。

    請在這裏輸入圖片描述

Release的使用方法

Tinker的使用方式如下,以gradle接入的release包爲例:

  1. 每次編譯或發包將安裝包與mapping文件備份;
  2. 若有補丁包的需要,按自身需要修改你的代碼、庫文件等;
  3. 將備份的基準安裝包與mapping文件輸入到tinkerPatch的配置中;
  4. 運行tinkerPatchRelease,即可自動編譯最新的安裝包,並與輸入基準包作差異,得到最終的補丁包。

調試源碼

tinker調試源碼非常簡單,大家需要在tinker的主工程運行tinker group中buildAndPublishTinkerToLocalMaven任務即可。

此外由於localmaven無法傳遞依賴,需要在使用的地方再顯式引用以下庫:

compile("com.tencent.tinker:tinker-android-loader:${TINKER_VERSION}") { changing = true }
compile("com.tencent.tinker:aosp-dexutils:${TINKER_VERSION}") { changing = true }
compile("com.tencent.tinker:bsdiff-util:${TINKER_VERSION}") { changing = true }
compile("com.tencent.tinker:tinker-commons:${TINKER_VERSION}") { changing = true }

github/Tinker的默認分支爲master分支,幾個含義的含義分別是:

  1. master分支;最近一次release的穩定代碼,我們在master分支打tag;
  2. dev分支;開發分支,這裏會包含下一個版本的代碼,我們只能給dev分支提pr以及驗證部分已經修復的issue;
  3. hotfix分支;爲了修復tinker緊急bug的分支。

關於tinker分支管理、issue以及pr規範,請閱讀Tinker Contributing Guide

TinkerPatch補丁管理後臺

www.tinkerpatch.com 是第三方開發基於CDN分發的補丁管理後臺。它提供了腳本後臺託管,版本管理,保證傳輸安全等功能,讓你無需搭建一個後臺,無需關心部署操作,只需引入一個 SDK 即可立即使用 Tinker。TinkerPatch平臺的SDK也是開源的,它的地址爲tinker_server_client

總的來說,我們更推薦使用gradle作爲接入方式。然後我們繼續學習如何Tinker 自定義擴展

發佈了34 篇原創文章 · 獲贊 78 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章