TinkerTest
演示如何使用騰訊的熱修復框架-Tinker
Tinker熱更新演示(請star支持)
演示demo下載
Tinker簡介
Tinker是微信官方的Android熱補丁解決方案,它支持動態下發代碼、So庫以及資源,讓應用能夠在不需要重新安裝的情況下實現更新。當然,你也可以使用Tinker來更新你的插件。
相關鏈接
Tinker已知問題
由於原理與系統限制,Tinker有以下已知問題:
- Tinker不支持修改AndroidManifest.xml,Tinker不支持新增四大組件(1.9.0支持新增非export的Activity);
- 由於Google Play的開發者條款限制,不建議在GP渠道動態更新代碼;
- 在Android N上,補丁對應用啟動時間有輕微的影響;
- 不支持部分三星android-21機型,加載補丁時會主動拋出”TinkerRuntimeException:checkDexInstall failed”;
- 對於資源替換,不支持修改remoteView。例如transition動畫,notification icon以及桌面圖標。
官方說明請點擊查看.
Tinker接入
添加依賴
- 在Project的根目錄的build.gradle下添加
tinkerpatch
插件:
buildscript {
... dependencies { ... classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:1.2.8" } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 在module的build.gradle下增加
Tinker
的依賴。
dependencies {
implementation 'com.android.support:multidex:1.0.3' //若使用annotation需要單獨引用,對於tinker的其他庫都無需再引用 annotationProcessor 'com.tinkerpatch.tinker:tinker-android-anno:1.9.8' compileOnly 'com.tinkerpatch.tinker:tinker-android-anno:1.9.8' implementation 'com.tinkerpatch.sdk:tinkerpatch-android-sdk:1.2.8' }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 配置代碼混淆和打包配置。其中tinkerMultidexKeep.pro和proguardRules.pro可參考我的demo工程。
android {
compileSdkVersion 27 defaultConfig { applicationId "com.xuexiang.tinkertest" minSdkVersion 14 targetSdkVersion 27 versionCode 1 versionName "1.0" multiDexEnabled true multiDexKeepProguard file("tinkerMultidexKeep.pro") //keep specific classes using proguard syntax } signingConfigs { release { //配置你的storekey storeFile file(app_release.storeFile) storePassword app_release.storePassword keyAlias app_release.keyAlias keyPassword app_release.keyPassword } } buildTypes { release { minifyEnabled true shrinkResources true signingConfig signingConfigs.release proguardFiles 'proguardRules.pro', getDefaultProguardFile('proguard-android.txt') } debug { debuggable true minifyEnabled false } } sourceSets { main { jniLibs.srcDirs = ['libs'] } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 引用
tinkerpatch.gradle
執行腳本.
apply from: 'tinkerpatch.gradle'
- 1
- 配置
tinkerpatch.gradle
執行腳本.對於腳本的詳細說明請參考官方文檔。
這里我只想說幾個比較關鍵的配置:
-
bakPath: 這里存放的是每次我們打包生成的apk目錄,作為生成補丁包的參考包路徑。(一般配置了就不用動了)
-
baseInfo: 這里設置的是,本次打補丁包參照的apk包所在文件夾路徑,也就是舊APK的目錄。(每次打補丁包的時候,都需要手動去更新)
-
variantName: 設置打補丁包的類型是release還是debug。
-
AppKey: 這是從Tinker Platform上注冊獲得的應用的appkey。
-
AppVersion: 這也是在Tinker Platform上,每次上傳補丁包時都需要填寫的應用版本,並且必須是唯一的。
【注意】:AppKey和AppVersion都是用於Tinker Platform自定發布補丁包所需要的。如果你不使用Tinker Platform來管理你的熱更新的話,可以隨便設置。
以下是tinkerpatch.gradle
的配置樣例:
apply plugin: 'tinkerpatch-support' /** * TODO: 請按自己的需求修改為適應自己工程的參數 */ def bakPath = file("${buildDir}/bakApk/") /** 每次在打補丁包的時候,需要更新這里的舊包的位置 **/ def baseInfo = "app-1.0.0-0810-17-28-31" def variantName = "release" def AppKey = "4c118de195c79b14" def AppVersion = "1.0.0" /** * 對於插件各參數的詳細解析請參考 * http://tinkerpatch.com/Docs/SDK */ tinkerpatchSupport { /** 可以在debug的時候關閉 tinkerPatch **/ /** 當disable tinker的時候需要添加multiDexKeepProguard和proguardFiles, 這些配置文件本身由tinkerPatch的插件自動添加,當你disable后需要手動添加 你可以copy本示例中的proguardRules.pro和tinkerMultidexKeep.pro, 需要你手動修改'tinker.sample.android.app'本示例的包名為你自己的包名, com.xxx前綴的包名不用修改 **/ tinkerEnable = true /** 是否使用一鍵接入功能 **/ reflectApplication = true /** * 是否開啟加固模式,只能在APK將要進行加固時使用,否則會patch失敗。 * 如果只在某個渠道使用了加固,可使用多flavors配置 **/ protectedApp = false /** * 實驗功能 * 補丁是否支持新增 Activity (新增Activity的exported屬性必須為false) **/ supportComponent = true /** 在tinkerpatch.com得到的appKey,改成你的應用appKey **/ appKey = "${AppKey}" /** 注意: 若發布新的全量包, appVersion一定要更新 **/ appVersion = "${AppVersion}" autoBackupApkPath = "${bakPath}" def pathPrefix = "${bakPath}/${baseInfo}/${variantName}/" def name = "${project.name}-${variantName}" baseApkFile = "${pathPrefix}/${name}.apk" baseProguardMappingFile = "${pathPrefix}/${name}-mapping.txt" baseResourceRFile = "${pathPrefix}/${name}-R.txt" /** * 若有編譯多flavors需求, 可以參照: https://github.com/TinkerPatch/tinkerpatch-flavors-sample * 注意: 除非你不同的flavor代碼是不一樣的,不然建議采用zip comment或者文件方式生成渠道信息(相關工具:walle 或者 packer-ng) **/ } /** * 用於用戶在代碼中判斷tinkerPatch是否被使能 */ android { defaultConfig { buildConfigField "boolean", "TINKER_ENABLE", "${tinkerpatchSupport.tinkerEnable}" } } /** * 一般來說,我們無需對下面的參數做任何的修改 * 對於各參數的詳細介紹請參考: * https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97 */ tinkerPatch { ignoreWarning = false useSign = true dex { dexMode = "jar" pattern = ["classes*.dex"] loader = [] } lib { pattern = ["lib/*/*.so"] } res { pattern = ["res/*", "r/*", "assets/*", "resources.arsc", "AndroidManifest.xml"] ignoreChange = [] largeModSize = 100 } packageConfig { } sevenZip { zipArtifact = "com.tencent.mm:SevenZip:1.1.10" // path = "/usr/local/bin/7za" } buildConfig { keepDexApply = false } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 最后就是配置Application了。因為我在上面設置
reflectApplication = true
使用了一鍵接入功能,所以就不需要進行復雜的配置了,如下:
public class App extends Application { @Override public void onCreate() { super.onCreate(); // 我們可以從這里獲得Tinker加載過程的信息 ApplicationLike tinkerApplicationLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike(); // 初始化TinkerPatch SDK, 更多配置可參照API章節中的,初始化SDK TinkerPatch.init(tinkerApplicationLike) .reflectPatchLibrary() .setPatchRollbackOnScreenOff(true) .setPatchRestartOnSrceenOff(true) .setPatchResultCallback(new ResultCallBack() { @Override public void onPatchResult(PatchResult patchResult) { ToastUtils.toast("補丁修復:" + (patchResult.isSuccess ? "成功" : "失敗")); } }) .setFetchPatchIntervalByHours(3); // 每隔3個小時(通過setFetchPatchIntervalByHours設置)去訪問后台時候有更新,通過handler實現輪訓的效果 TinkerPatch.with().fetchPatchUpdateAndPollWithInterval(); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
更多復雜的配置和高端自定義操作可參見官方文檔。
以上就完成了Tinker的接入工作。
如何使用Tinker進行熱修復
- 先隨便在程序中寫一個bug,然后執行
./gradlew assembleRelease
進行打包。當然你也可以直接在AS右側的Gradle
中找到你的應用,並在Tasks->build->assembleRelease
找到assembleRelease的任務,雙擊執行任務。
執行完成后,你會在你模塊的build->bakApk
下看到你打的apk包。
-
你將剛才生成apk的那個文件夾的名稱設置在之前說的
tinkerpatch.gradle
中的baseInfo
。 -
將bug修復后,執行
./gradlew tinkerPatchRelease
打補丁包。當然你也可以直接在AS右側的Gradle
中找到你的應用,並在Tasks->tinker->tinkerPatchRelease
找到tinkerPatchRelease的任務,雙擊執行任務。
執行完成后,你會在你模塊的build->outputs->apk->tinkerPatch->release
下看到你需要的補丁包patch_signed_7zip.apk
。
- 最后調用
TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(), path);
, path傳入你補丁包的所在的路徑即可完成熱更新。
需要注意的是,執行熱更新后,需要重啟程序才能生效!