1. 程式人生 > >Android studio3.0 命令列方式簡單整合騰訊Tinker熱修復外掛

Android studio3.0 命令列方式簡單整合騰訊Tinker熱修復外掛

簡介:

關於熱修復的介紹現在網上有很多,所以在此我就不過多BB,此篇部落格的特點有兩個,首先,這是一個針對Android studio3.0使用者的部落格,其次,這裡採用的是命令列的方式,這是方式在工作中並不經常使用,相反,在工作中基本都是使用gradle配置的方式,但是命令列的方式相比於gradle是簡單很多的,所以這就這是一個入門級的tinker整合,意在讓大家瞭解tinker這個相對最為全面的熱修復框架(高手請繞路,前方低能)。

1、在gradle.properties中配置我們tinker的版本。這種配置方式就相當於定義一個變數,用於指定我們匯入依賴的版本,這樣對於同一框架的多個依賴可以進行很好的版本控制。

貼上板:TINKER_VERSION=1.9.0


2、module中匯入依賴,在這裡可以看到我們剛剛定義的變數在這裡得以使用

貼上板:

    //可選,用於生成application類
    implementation("com.tencent.tinker:tinker-android-lib:${TINKER_VERSION}") { changing = true }
    //tinker的核心庫
    annotationProcessor("com.tencent.tinker:tinker-android-anno:${TINKER_VERSION}") { changing = true }

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

    implementation "com.android.support:multidex:1.0.2"

3、建立一個管理類,來管理我們Tinker中所有的api,方便我們的使用和以後對其他工程的植入。程式碼都有註釋,這裡就直接上程式碼了

package com.jiaxin.tinkerthree.tinker;

import android.content.Context;

import com.tencent.tinker.lib.tinker.Tinker;
import com.tencent.tinker.lib.tinker.TinkerInstaller;
import com.tencent.tinker.loader.app.ApplicationLike;

/**
 * Created by Zzw on 2017/12/24.14:06
 *
 * @function 對Tinker的所有api做一層封裝
 */

public class TinkerManger {

    //判斷tinker是否已經初始化
    private static boolean isInstalled = false;

    private static ApplicationLike mAppLike;

    /**
     * 由外部呼叫完成tinker 的初始化
     * @param applicationLike
     */
    public static void instaillTinker(ApplicationLike applicationLike){
        mAppLike = applicationLike;
        if (isInstalled){
            return;
        }
        TinkerInstaller.install(mAppLike);//完成tinker初始化
        isInstalled = true;
    }

    /**
     * 完成patch檔案載入
     * @param path
     */
    public static  void loadPatch(String path){
        if (Tinker.isTinkerInstalled()){
            TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(), path);
        }
    }

    /**
     * 通過applicationLike獲取context
     * @return
     */
    private static Context getApplicationContext(){
        if (mAppLike != null){
            return mAppLike.getApplication().getApplicationContext();
        }
        return null;
    }
}

3、根據官方的要求我們要使用ApplicationLike這個類,來生成application,所以我們這裡建立一個類來繼承他
package com.jiaxin.tinkerthree.tinker;

import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.support.multidex.MultiDex;

import com.tencent.tinker.anno.DefaultLifeCycle;
import com.tencent.tinker.loader.app.ApplicationLike;
import com.tencent.tinker.loader.shareutil.ShareConstants;

/**
 * Created by Zzw on 2017/12/24.14:11
 */

@DefaultLifeCycle(application = ".MyTinkerApplication" ,
        flags = ShareConstants.TINKER_ENABLE_ALL , loadVerifyFlag = false)
public class CustomTinkerLike extends ApplicationLike {
    public CustomTinkerLike(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);

        MultiDex.install(base);//使應用支援分包

        TinkerManger.instaillTinker(this);
    }
}

注意這裡我們使用了 一個註解,註解中後面兩個引數可以認為是固定引數,第一個是我們指定的生成Application類的名字,這裡我們叫他"MyTinkerApplication"

以上配置都完畢後我們編譯整個工程,tinker的註解就會為我們生成一個MyTinkerApplication類。

4、清單檔案中配置

這裡的配置就是指定application為我們剛剛生成的"MyTinkerApplication",還有一個TINKER_ID的配置,這個主要是因為tinker在載入補丁檔案的時候會只能的判斷當前版本和補丁版本是否一致,如果不一致就會認為此補丁檔案無效,就不會載入,所以我們這裡做測試的話兩次apk生成的時候只要這裡不該動就好了

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

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application
<!-- 此處指定application為tinker為我們生成的application -->
        android:name=".tinker.MyTinkerApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        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>

        <meta-data
            android:name="UMENG_CHANNEL"
            android:value="${UMENG_CHANNEL_VALUE}" />
<!-- 此處為tinker配置當前的應用版本 -->
        <meta-data
            android:name="TINKER_ID"
            android:value="tinker_id_123456"
            />
    </application>

</manifest>


5、以上步驟完成後,我們tinker的配置工作基本也就完成了,接下來只要使用我們的tinker管理類,生成兩個不同版本的apk即可,這裡因為tinker是支援佈局檔案的修改的,所以我模擬了點選一個按鈕增加一個按鈕的功能, 下面是我activity中的使用,佈局就不寫了哈

package com.jiaxin.tinkerthree;

import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.jiaxin.tinkerthree.tinker.TinkerManger;

import java.io.File;

public class MainActivity extends AppCompatActivity {

    //log key
    public static final String TAG = "myLog";

    //file's end name
    private static final String FILE_END = ".apk";

    //patch file's path
    private String mPatchDir;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mPatchDir = Environment.getExternalStorageDirectory().getAbsolutePath();

        Log.d(TAG, "onCreate: " + mPatchDir);
        File file = new File(mPatchDir);
        if (file.exists()){
            Toast.makeText(this, "檔案存在", Toast.LENGTH_SHORT).show();
        }else{
            boolean mkdirs = file.mkdir();
            Toast.makeText(this, mkdirs ? "建立成功" : "建立失敗", Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * @click
     * @param view
     * load tinker patch for application
     */
    public void loadPatch(View view){
        TinkerManger.loadPatch(getPathName());
    }

    //get tinker patch fileName
    private String getPathName() {
        return mPatchDir.concat("/tinker").concat(FILE_END);
    }
}

6、好,接下來我們只要改變佈局檔案生成兩個版本不同的apk即可,我這裡是在新的apk中添加了一個按鈕,所以old版本的apk只有一個按鈕,用於點選載入補丁檔案,new版本的apk中在第一個按鈕的基礎上又添加了一個按鈕。

7、兩個apk版本生成成功後接下來就是生成補丁apk,我們採用的是命令列的方式,所以當然是要使用tinker為我們提供的工具,我們將所有要使用到的檔案和新舊兩個版本的apk檔案以及jks簽名檔案放在同一個目錄下(建議新建一個資料夾),然後開啟命令列工具進入該資料夾,執行jar檔案:

java -jar  tinker-patch-cli-1.7.7.jar


可以看到tinker提示我們該命令需要一堆引數,可以看到新舊版本apk檔案我們已經準好了,只差一個tinker_config檔案,我們開啟這個檔案,修改其中的loader為我們的application的名字,修改issue配置為我們簽名的配置和密碼



8、配置完畢後,開啟命令列工具,指定好引數在執行剛剛的命令就可以在output資料夾中看到tinker為我們生成的apk檔案,將patch_signed.apk(簽名版的)這個檔案改為我們一開始指定的檔名稱(我這裡是tinker.apk),再將其拷貝到我們一開始指定的路徑,我這裡指定的是sd下預設路徑,安裝old版本apk整個過程就完成了~~。

9、開啟安裝好的舊版本apk,點選按鈕,程式會閃退,再次開啟就會發現後新增的按鈕就已經被新增上去了,這裡閃退不用擔心,這是tinker預設的設定,因為tinker在載入補丁檔案完畢後,不重新啟動是不會生效的。這個也可以通過配置來更改,具體可以通過檢視相關文件來實現。