1. 程式人生 > >熱更新Tinker的整合使用

熱更新Tinker的整合使用

請珍惜勞動者的汗水,一分耕耘一分收穫,轉載請註明出處,謝謝!

初衷:如今熱更新越來越火,各大廠也陸續開源自己的熱更新框架。目前主流的熱更新大概有以下一些,未統計到的望給予補充。

正好年底了有點時間,也總結一下。

1、Tinker 微信  2、QZone  QQ空間  3、阿里 AndFix  4、美團 Robust  5、Nuwa 俗稱女媧 。。。。。。

下面就本人用到的Tinker做個分析,以及具體的實現步驟。

傻瓜式SDK Tinker進入參考文件:http://tinkerpatch.com/Docs/intro

當然還要一種是原始碼直接接入,自己管理後臺服務,稍微複雜麻煩點,可參考github上Tinker的官方介紹:https://github.com/Tencent/tinker

具體的原理和差異演算法大家可以去參考下官方文件


差異演算法結構圖:


對比以上各優勢果斷選擇了Tinker,主要看中的是資原始檔的替換,當然有一點不滿意的就是無法及時生效,不過也不影響,還可以使用鎖屏自動生效的方式,這一點還是挺好的!

2、整合步驟:

新建專案成功後配置build.gradle,有三處的gradle需要配置。由於文件並未完全標明,其中一個gradle的配置還是費了點精力^_^。最後還是再同事的一句話點醒了。

2.1 至於我們的Application可以使用我們平常專案中正常的方式,只需稍加蓋上即可。

public class SampleApplication extends 
Application{ @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); TinkerPatch.init(TinkerPatchApplicationLike.getTinkerPatchApplicationLike()); TinkerPatch tinkerPatch = TinkerPatch.with(); tinkerPatch.fetchPatchUpdate(true); //向後臺請求補丁升級配置;true,即每次呼叫都會真正的訪問後臺是否有更新。} }

gradle結構:


都需要我們配置,其中tinkerpatch.gradle 需要手動建立,然後在 2 中進行引用

具體看下第1個 的內容:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.3'
// TinkerPatch 外掛
classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:1.0.1" }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

下面先看下 第3個 gradle的內容:

apply plugin: 'tinkerpatch-support'
def bakPath = file("${buildDir}/basekApk/")
def tempPath = "app-1.0.0-0113-10-26-03"
/**
 * 對於外掛各引數的詳細解析請參考
 * http://tinkerpatch.com/Docs/SDK
 */
tinkerpatchSupport {
    tinkerEnable = true
appKey = "你要去申請的appkey"
appVersion = "${APP_VERSIONNAME}"
reflectApplication = true
autoBackupApkPath = "${bakPath}"
baseApkFile = "${bakPath}/${tempPath}/app-release.apk"   //app-debug.apk
baseProguardMappingFile = "${bakPath}/${tempPath}/app-release-mapping.txt"   //app-debug-mapping.txt
baseResourceRFile = "${bakPath}/${tempPath}/app-release-R.txt"    //app-debug-R.txt
}


/**
 * 一般來說,我們無需對下面的引數做任何的修改
 * 對於各引數的詳細介紹請參考:
 * 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
}
}

很簡單

繼續第2點,也沒啥好將的,就是需要將第3個gradle進行apply 

apply from: 'tinkerpatch.gradle'
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
})
    compile 'com.android.support:appcompat-v7:25.0.0'
testCompile 'junit:junit:4.12'
compile "com.android.support:multidex:1.0.1"
//若使用annotation需要單獨引用,對於tinker的其他庫都無需再引用
provided("com.tencent.tinker:tinker-android-anno:1.7.6") { changing = true }
    compile("com.tinkerpatch.sdk:tinkerpatch-android-sdk:1.0.1"){ changing = true }
}

至此Tinker的整合已經搞定!!!下面就是打包,編譯差異包的過程了。下面還是列下官方的實現步驟吧,依葫蘆畫瓢,so sasy !

參考:http://tinkerpatch.com/Docs/SDK

整合完畢後將專案切換到Project模式下,可以看到這樣的結構


展開Gradle projects 編譯打包,其中tinker下是編譯產生差異包


第一步 新增 gradle 外掛依賴

gradle 遠端倉庫依賴 jcenter, 例如 TinkerPatch Sample 中的build.gradle.
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        // TinkerPatch 外掛
        classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:1.0.2"
    }
}
注意,在這裡SDK使用了fat打包的模式,我們不能再引入任何 Tinker 的相關依賴,否則會造成版本衝突。當前SDK是基於 tinker 1.7.6 核心開發的。

第二步 整合 TinkerPatch SDK

新增TinkerPatch SDK 庫的 denpendencies 依賴, 可參考 Sample 中的 app/build.gradle:

dependencies {
    //若使用annotation需要單獨引用,對於tinker的其他庫都無需再引用
    provided("com.tencent.tinker:tinker-android-anno:1.7.6")
    compile("com.tinkerpatch.sdk:tinkerpatch-android-sdk:1.0.2")
}

注意,若使用 annotation 自動生成 Application, 需要單獨引入 Tinker的 tinker-android-anno 庫。除此之外,我們無需再單獨引入 tinker 的其他庫。

為了簡單方便,我們將 TinkerPatch 相關的配置都放於 tinkerpatch.gradle 中, 我們需要將其引入:

apply from: 'tinkerpatch.gradle'

第三步 配置 tinkerpatchSupport 引數

開啟引入的 tinkerpatch.gradle 檔案,它的具體引數如下:

tinkerpatchSupport {
    tinkerEnable = true
    appKey = "f828475486f91936"
    appVersion = "1.0.0"

    autoBackupApkPath = "${bakPath}"

    baseApkFile = "${bakPath}/${appName}/app-debug.apk"
    baseProguardMappingFile = "${bakPath}/${appName}/app-debug-mapping.txt"
    baseResourceRFile = "${bakPath}/${appName}/app-debug-R.txt"
}

它的具體含義如下:

引數 預設值 描述
tinkerEnable true 是否開啟 tinkerpatchSupport 外掛功能。
appKey "" 在 TinkerPatch 平臺 申請的 appkey, 例如 sample 中的 'f828475486f91936'
appVersion "" 在 TinkerPatch 平臺 輸入的版本號, 例如 sample 中的 '1.0.0'。 注意,我們使用 appVersion 作為 TinkerId, 我們需要保證每個釋出出去的基礎安裝包的 appVersion 都不一樣。
reflectApplication false 是否反射 Application 實現一鍵接入;一般來說,接入 Tinker 我們需要改造我們的 Application, 若這裡為 true, 即我們無需對應用做任何改造即可接入
autoBackupApkPath "" 將每次編譯產生的 apk/mapping.txt/R.txt 歸檔儲存的位置
baseApkFile "" 基準包的檔案路徑, 對應 tinker 外掛中的 oldApk 引數;編譯補丁包時,必需指定基準版本的 apk,預設值為空,則表示不是進行補丁包的編譯。
baseProguardMappingFile "" 基準包的 Proguard mapping.txt 檔案路徑, 對應 tinker 外掛 applyMapping 引數;在編譯新的 apk 時候,我們希望通過保持基準 apk 的 proguard 混淆方式,從而減少補丁包的大小。這是強烈推薦的,編譯補丁包時,我們推薦輸入基準 apk 生成的 mapping.txt 檔案。
baseResourceRFile "" 基準包的資源 R.txt 檔案路徑, 對應 tinker 外掛 applyResourceMapping 引數;在編譯新的apk時候,我們希望通基準 apk 的 R.txt 檔案來保持 Resource Id 的分配,這樣不僅可以減少補丁包的大小,同時也避免由於 Resource Id 改變導致 remote view 異常。

一般來說,我們無需修改引用 android 的編譯配置,也不用修改 tinker 外掛原來的配置。針對特殊需求,具體的引數含義可參考 Tinker 文件:Tinker 接入指南.

第四步 初始化 TinkerPatch SDK

最後在我們的程式碼中,只需簡單的初始化 TinkerPatch 的 SDK 即可,我們無需考慮 Tinker 是如何下載/合成/應用補丁包, 也無需引入各種各樣 Tinker 的相關類。

1. reflectApplication = true 的情況

若我們使用 reflectApplication 模式,我們無需為接入 Tinker 而改造我們的 Application 類。初始化 SDK 可參考 tinkerpatch-easy-sample 中的 SampleApplication 類.

public class SampleApplication extends Application {
...
     public void attachBaseContext(Context base) {
         TinkerPatch.init(TinkerPatchApplicationLike.getTinkerPatchApplicationLike());
     }
...

我們將 Tinker 載入補丁過程的結果存放在 TinkerPatchApplicationLike 中。

2. reflectApplication = false 的情況

若我們已經完成了應用的 Application 改造,即將 Application 的邏輯移動到 ApplicationLike類中。我們可以參考 tinkerpatch-sample 中的 SampleApplicationLike 類.

public class SampleApplicationLike extends DefaultApplicationLike {
...
     public void onBaseContextAttached(Context base) {
        TinkerPatch.init(this);
     }
...
}

第五步 使用步驟

TinkerPatch 的使用步驟非常簡單,一般來說可以參考以下幾個步驟:

  1. 執行 assembleRelease task 構建基準包,即將要釋出的版本;
  2. 通過 autoBackupApkPath 儲存編譯的產物 apk/mapping.txt/R.txt 檔案;
  3. 若想釋出補丁包, 只需將步驟2儲存下來的檔案分別填到 baseApkFile/baseProguardMappingFile/baseResourceRFile 引數中;
  4. 執行 tinkerPatchRelease task 構建補丁包,補丁包將位於 build/outputs/tinkerPatch 中。

搞定!

後面就是將差異包提交的Tinker的Web上了。


差異包的釋出可根據需要選擇條件,不再囉嗦了。大家可以自己去看下介紹,沒什麼難度。有不懂的可以直接評論,第一次寫這麼長的部落格,自我感覺都很爛,但這是一個鍛鍊的過程,而且沒有足夠的時間來總結,只是碰巧今天又點時間就先寫上來了。公司一直都忙忙忙啊!!!!!受不了了,再看看咱們的IOS多爽,3個月沒做過專案,爽死了!不過誰叫我們是Android屌絲呢^_^,吐槽歸吐槽,還是要把工作幹好!最後期待18號年會能給我抽個大獎啊!!!

各位見笑了,有問題Call我,能解決的一定盡力,幫不到的一起努力!祝自己2017工作順利,身體健康,家庭和睦!祝大家步步高昇!