熱更新之Tinker的快速集成

前言:

如今的Android項目,大部分都離不開熱更新這項技術。因爲公司須要,入坑Tinker,結果發現dex以及資源文件,能夠替換。而So文件,Log日誌提示替換成功,而使用時很差使。因此有了該文章。也算時把我踩的坑記錄一下,給你們加快點效率。android

目標:

更新Dex,資源文件,以及So庫文件git

原理:

簡單說下Tinker的原理。經過算法,將新的更新的APK和原版的BaseApk之間的差別生成一個Patch補丁包。將補丁包發送到手機本地,在用戶打開手機時將補丁包加載進手機。更加具體的原理,此處不作敘述。程序員

集成:

1. 在全局的build.gradle中新增classpath。如圖:
classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.9.1')
複製代碼

image.png

2.將Demo中的app中的build.gradle複製進項目中。這裏有幾個須要注意的地方。

image.png

image.png

image.png

3.將Demo中的文件複製進項目中.並註冊service。

image.png

4.新建ApplicationLike。繼承自DefaultApplication。這裏是爲了自動生成Application。
//application爲生成的Application的名稱。flags爲能夠替換的類型,這裏TINKER_ENABLE_ALL爲全均可以替換(dex,資源文件,so庫)
@DefaultLifeCycle(application = ".TestTinkerApplication",flags = ShareConstants.TINKER_ENABLE_ALL
)
public class TestTinkerLike extends DefaultApplicationLike {
    private static TestTinkerLike mTestTinkerLike;
    public TestTinkerLike(Application application, int tinkerFlags, boolean tinkerLoadVerifyFlag, long applicationStartElapsedTime, long applicationStartMillisTime, Intent tinkerResultIntent) {
        super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent);
        mTestTinkerLike=this;
    }

    /**
     * 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); TinkerManager.fastInstallAll(this); } public static TestTinkerLike getmTestTinkerLike(){ return mTestTinkerLike; } } 複製代碼
5.註冊Application。會報錯,由於TestTinkerApplication沒有生成,build一下便可。

image.png

熱更新

1. 配置簽名

image.png

2. 生成基礎APK包,生成位置如圖。生成位置能夠自行配置(在build.gradle中修改bakPath)

image.png

3. 生成補丁代碼。注意:這裏生成的補丁必須是基於用戶安裝的基礎APK。假如用戶安裝的是A版本。而你是基於B版本生成的補丁包。這樣是沒法在A版本上更新的。即圖中的基礎APK必須是用戶正在用的版本。

image.png

4. 將補丁包放到手機中,具體位置爲圖中所示(能夠自行更改)。這裏有一點須要注意就是權限問題,我看別人的Demo貌似不須要申請權限,可我作時卻必須申請。這點你們能夠本身試試。

image.png

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                        != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
                } else {
                    TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(), Environment.getExternalStorageDirectory().getAbsolutePath() + "/patch_signed_7zip.apk");
                }
複製代碼
5.加載so庫的幾種方式:
  • Hack方式(成功率最大的方式)
String CPU_ABI = android.os.Build.CPU_ABI;
// 將tinker library中的 CPU_ABI架構的so 註冊到系統的library path中。
TinkerLoadLibrary.installNavitveLibraryABI(MainActivity.this, CPU_ABI);
複製代碼
  • 非Hack方式:
String CPU_ABI = android.os.Build.CPU_ABI;
boolean a=TinkerLoadLibrary.loadLibraryFromTinker(getApplicationContext(), "lib/" + CPU_ABI, "native-lib");

複製代碼
  • Arm方式:
TinkerLoadLibrary.loadArmLibrary(getApplicationContext(), "native-lib");
複製代碼
  • Arm-V7a方式:
TinkerApplicationHelper.loadArmV7aLibrary(TestTinkerLike.getmTestTinkerLike(), "native-lib");
複製代碼
注意

這裏有兩個類能夠加載So文件,TinkerLoadLibraryTinkerApplicationHelper 不過他們的原理時同樣的,不知道做者爲何封了兩個。github

特別注意

so文件是打補丁的時候自動加載的,可是卻須要手動的鏈一下,至關於,基礎apk自己的so文件A。在打補丁的時候加載了so文件B。此時有兩個so文件。你每次都要手動的用上面的方法加載so庫B。不然默認調用的仍是基礎APK的so文件A中的方法。一旦你在加載so庫前,調用了A中的方法,默認加載的是so庫A。此時你要調用so庫B中 新增的方法(so庫B中有,可是so庫A中沒有的方法)。就會報錯。算法

文件 :

基礎文件,以及補丁包。如圖所示! 切記,第一次的時候因爲沒有權限,須要手動打補丁。 bash

image.png

項目地址:github.com/13046434521…
問題:

若是文章有什麼錯誤,請及時指正。好比權限的問題,我這裏是必須申請的。好比so文件同時存在,而不是替換,也是我的猜想,有時間我會去證明。但願你們一同進步。架構

總結:

特別注意中這個簡單的邏輯,卻難了我3天的時間,因爲大部分集成tinker的,只要替換資源文件和dex便可。因此幾乎很難找到so沒法生效的緣由。也算是爲後來人,鋪了個路。後續會上代碼和圖片。但願你們點個喜歡,關注。仍是老話,風力雨裏,都在這裏等你,大家的關注是我最大的動力。感謝各位了,一個入坑JNI開發的小Android程序員的訴求。感謝各位大佬啦。app

相關文章
相關標籤/搜索