Tinker初體驗


微信開源了自己的熱修復Tinker庫,一直沒用過,所以想搞一個小Demo來體驗一下

什么是Tinker?


Tinker是微信官方的Android熱補丁解決方案,它支持動態下發代碼、So庫以及資源,讓應用能夠在不需要重新安裝的情況下實現更新。

Tinker 傳送門:github主頁 wiki介紹 Tinker的接入指南

開始接入


Tinker 的sample 的地址為 sample

1、gradle配置

參照 Tinker sample的做法 在 gradle.properties文件末尾添加

TINKER_VERSION=1.7.11

在項目的 build.gradle 中指定classpath

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.2'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
        classpath "com.tencent.tinker:tinker-patch-gradle-plugin:${TINKER_VERSION}"
    }
}

參考 sample 的build.gradle 進行配置

1、在android {}標簽中添加 簽名配置

signingConfigs {
        release {
            try {
                storeFile file("./keystore/release.keystore")
                storePassword "testres"
                keyAlias "testres"
                keyPassword "testres"
            } catch (ex) {
                throw new InvalidUserDataException(ex.toString())
            }
        }

        debug {
            storeFile file("./keystore/debug.keystore")
        }
    }

2、在dependencies{}標簽添加核心庫

 compile("com.tencent.tinker:tinker-android-lib:${TINKER_VERSION}") { changing = true }
    provided("com.tencent.tinker:tinker-android-anno:${TINKER_VERSION}") { changing = true }

3、其余粘貼sample 中的 配置但是要進行修改

注意修改 ignoreWarning = true **
修改
tinkerId = "tinkerId" //getTinkerIdValue()**

如果涉及到 getTinkerIdValue 的都修改成 tinkerId

然后編譯就能通過了

2、Application配置

與以往的很多庫不同,這里并不是在自定義的Application 中進行初始化之類的‘

@SuppressWarnings("unused")
@DefaultLifeCycle(application = ".SampleApplication",
        flags = ShareConstants.TINKER_ENABLE_ALL,
        loadVerifyFlag = false)
public class SampleApplicationLike extends DefaultApplicationLike {
    private static final String TAG = "Tinker.SampleApplicationLike";

    public SampleApplicationLike(Application application, int tinkerFlags, boolean tinkerLoadVerifyFlag,
                                 long applicationStartElapsedTime, long applicationStartMillisTime, Intent tinkerResultIntent) {
        super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent);
    }

    /**
     * install multiDex before install tinker
     * so we don't need to put the tinker lib classes in the main dex
     *
     * @param base
     */
    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    @Override
    public void onBaseContextAttached(Context base) {
        super.onBaseContextAttached(base);
        //you must install multiDex whatever tinker is installed!
        MultiDex.install(base);

        TinkerInstaller.install(this);
    }

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    public void registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks callback) {
        getApplication().registerActivityLifecycleCallbacks(callback);
    }

}

AndroidManifest.xml 文件進行配置

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.xxh.thinkertest">

  <!--Tinker 需要讀取Sd卡中的差異包apk 需要權限-->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>  

      <!--這里的是我們SampleApplicationLike的注解部分,Tinker會在運行時生成該類-->
    <application
        android:name=".SampleApplication"   
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

3、配置結束開始測試使用

module 執行DeBug 運行,將項目打包生成 apk 文件,運行在手機中。以App為例,會 在 build-> badApk->生成Apk文件 文件是以 日期時間來命名的 ,比較好區分

bad_apk_gen

修改配置 build.gradle 文件

//for normal build
//old apk file to build patch apk
tinkerOldApkPath = "${bakPath}/app-debug-0629-17-10-31.apk"   //這里配置  剛剛生成的  oldApk 文件
//proguard mapping file to build patch apk
tinkerApplyMappingPath = "${bakPath}/app-debug-1018-17-32-47-mapping.txt" //proguard的map映射文件
//resource R.txt to build patch apk, must input if there is resource changed
tinkerApplyResourcePath = "${bakPath}/app-debug-0629-17-10-31-R.txt"   //如果修改了 resource內容,將該文件也更新到最新

修改項目中的代碼,并構建 差異包

修改MainActivity 中的代碼

public class MainActivity extends AppCompatActivity {

    private TextView test_main;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        test_main = (TextView) findViewById(R.id.test_main);
        //在差異包中修改了  界面中的顯示文本   "I am In Path Apk"
        test_main.setText("I am In Patch Apk");
    }

    public void loadPath(View view) {
        String path = Environment.getExternalStoragePublicDirectory(DOWNLOAD_SERVICE).getAbsolutePath() + "/patch_signed_7zip.apk";
        File file = new File(path);
        if (file.exists()) {
            Toast.makeText(this, "補丁存在", Toast.LENGTH_SHORT).show();
            TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(), path);
        } else {
            Toast.makeText(this, "補丁不存在", Toast.LENGTH_SHORT).show();
        }
    }
}

修改完成執行 tinker 的 gradle 命令 tinkerPatchDebug

可以在命令行或者這里點擊運行,然后等待 構建生成 patch 包

在此過程中可能會失敗,重試一次,生成的差異包會在該目錄下:

將生成的 patch_signed_7zip.apk 文件 導入到sd卡中,但是導入到哪個目錄呢?看下面的代碼

    public void loadPath(View view) {
      //這里制定了  加載差異包的文件名和目錄
        String path = Environment.getExternalStoragePublicDirectory(DOWNLOAD_SERVICE).getAbsolutePath() + "/patch_signed_7zip.apk";
        File file = new File(path);
        if (file.exists()) {
            Toast.makeText(this, "補丁存在", Toast.LENGTH_SHORT).show();
            TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(), path);
        } else {
            Toast.makeText(this, "補丁不存在", Toast.LENGTH_SHORT).show();
        }
    }

導入的目錄要與 代碼中的目錄保持一致

再次運行剛剛打包到手機中的應用 點擊 loadPath按鈕看效果如下

這里只是體驗了一下Tinker的簡單實用,具體在項目中的使用還需要進一步的去研究,相信還有很多坑在等著我!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,559評論 25 708
  • 微信熱升級tinker初體驗 基于v1.6.2 總項目工程https://github.com/Tencent...
    162f127842fc閱讀 324評論 0 0
  • Tinker使用 前言 寫在前面的話,在上家公司一直在主導組件框架的開發,所以對Android領域組件化,熱更新的...
    徐正峰閱讀 1,946評論 6 6
  • 1.熱修復: 熱修復從原理上說應該是屬于插件化的一類,我們可以用熱修復來處理線上緊急的bug,而不需要提示用戶重新...
    茴香豆的第五種寫法閱讀 1,466評論 0 1
  • 掬一捧清泉入心,攜一縷墨香如夢。書不盡江山萬里,念一心三千繁夢。剎那錦繡繁華,恒久筆墨丹青,不過一紙信箋,卻...
    瓊喑閱讀 465評論 0 4