聽說熱修復已經(jīng)很久了,但這是第一次嘗試去應用它。所以我對其它各種熱修復也沒什么了解,這里僅僅記下如何使用Tinker熱修復。
對于Tinker熱修復的介紹和問題這里也不寫了,因為官方文檔已經(jīng)有了,戳這里進入官方介紹文檔 ,這里只記下如何在自己的項目中使用Tinker熱修復。
步驟一、 通過gradle接入Tinker
在項目的build.gradle里添加gradle依賴:
buildscript { repositories { jcenter() } dependencies { ...... // 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:1.7.7') }}在app的build.gradle里添加依賴庫及插件
dependencies { ...... //可選,用于生成application類 步驟二、 拷貝sample項目中app/build.gradle配置文件相關內(nèi)容sample項目 app/build.gradle配置文件地址戳這里
里面的內(nèi)容很多,有些內(nèi)容也許用不上,可以刪去。暫時可以把Tinker相關的配置內(nèi)容全部拷貝。
這里有一個問題需要注意:build.gradle文件中有一個方法
def getTinkerIdValue() { return "TestTinker" + android.defaultConfig.versionName + "_" + android.defaultConfig.versionCode; //return hasproperty("TINKER_ID") ? TINKER_ID : gitSha()} 這個方法生成TinkerId,TinkerId用來標識原始包和補丁包,也就是說給原始包打補丁的時候,原始包是通過這個TinkerId來找到補丁包的。所以這個值必須設置。建議的設值方式是與app的版本號及版本名稱關聯(lián)起來。sample中原來的方法是通過git版本號生成,不太建議使用這種方式,因此配置中的getSha()方法也可以刪除。
步驟三、 自定義Application類
自定義一個Application類,讓他繼承DefaultApplicationLike類,如下:別忘了頂部的注解哦
@DefaultLifeCycle(application = "com.fff.xiaoqiang.testtikner.theApplication", flags = ShareConstants.TINKER_ENABLE_ALL, loadVerifyFlag = false)public class MyApplication extends DefaultApplicationLike { public MyApplication(Application application, int tinkerFlags, boolean tinkerLoadVerifyFlag, long applicationStartElapsedTime, long applicationStartMillisTime, Intent tinkerResultIntent) { super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent); } @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, new DefaultLoadReporter(base), new DefaultPatchReporter(base), new DefaultPatchListener(base), TinkerResultService.class, new UpgradePatch()); } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public void registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks callback) { getApplication().registerActivityLifecycleCallbacks(callback); }}其中,TinkerInstaller.install方法為初始化Tinker方法,它有兩個構造方法,如下:
public static Tinker install(ApplicationLike applicationLike) { ...... } public static Tinker install(ApplicationLike applicationLike, LoadReporter loadReporter, PatchReporter patchReporter, PatchListener listener, Class<? extends AbstractResultService> resultServiceClass, AbstractPatch upgradePatchProcessor) { ...... }最開始的時候我是使用第一個構造方法,只需要傳入ApplicationLike這一個參數(shù)就可以了,也可以熱修復成功,但是每次修復成功后app就會被殺掉。這是因為如果使用第一個構造方法,Tinker就會使用默認參數(shù),從第二個構造方法可以看到除了ApplicationLike外初始化的時候還使用了其它五個參數(shù),他們的五個默認類分別是:
DefaultLoadReporter、 DefaultPatchReporter、 DefaultPatchListener 、DefaultTinkerResultService 和 UpgradePatch其中DefaultTinkerResultService中能接收到熱修復的結(jié)果,查看這個類的源碼可以發(fā)現(xiàn),當修復成功后,就調(diào)用了殺掉進程的方法。因此如果不想把進程殺掉,就需要重寫這個類,修改里面的方法。步驟四、 重寫DefaultTinkerResultService因為我不希望修復成功后app立馬閃退,所以重寫了這個類,如下:
public class TinkerResultService extends DefaultTinkerResultService { private static final String TAG = "TinkerResultService"; @Override public void onPatchResult(PatchResult result) {// super.onPatchResult(result); 把這行注釋掉,屏蔽掉父類中的方法 if (result == null) { Log.e(TAG, "TinkerResultService received null result!!!!"); return; } Log.e(TAG, "TinkerResultService receive result: %s" + result.toString()); //first, we want to kill the recover process// TinkerServiceInternals.killTinkerPatchServiceProcess(getApplicationContext()); if(result.isSuccess){ //修復成功 Log.e(TAG,"修復成功"); deleteRawPatchFile(new File(result.rawPatchFilePath)); //刪除補丁包 Log.e(TAG,"刪除補丁"); } }}步驟五、 別忽略了Manifest.xml文件因為手動添加了Application和Service,所以需要在Manifest.xml文件中配置上去。注意application的 name別填錯。
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.fff.xiaoqiang.testtikner"> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application android:name=".theApplication" 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> <service android:name=".TinkerResultService" android:exported="false"/> </application></manifest>另外別忘了給app添加SD卡讀寫權限代碼配置完成之后,就可以開始打補丁包了
首先打基礎包,也就是和我們平時打包一樣,打包完成之后,會在項目文件的build文件夾下生成一個bakApk文件夾,里面有apk、txt等文件。把這些文件的全名稱填入build.gradle配置文件中,如下:
ext { //for some reason, you may want to ignore tinkerBuild, such as instant run debug build? tinkerEnabled = true //for normal build //old apk file to build patch apk tinkerOldApkPath = "${bakPath}/app-debug.apk" //proguard mapping file to build patch apk tinkerApplyMappingPath = "${bakPath}/app-debug-mapping.txt" //resource R.txt to build patch apk, must input if there is resource changed tinkerApplyResourcePath = "${bakPath}/app-debug-R.txt" //only use for build all flavor, if not, just ignore this field tinkerBuildFlavorDirectory = "${bakPath}/app-0209-19-39-45"}tinkerOldApkPath表示原始包路徑,tinkerApplyMappingPath表示原始包mapping文件路徑,沒有的話可以不要管tinkerApplyResourcePath表示原始包資源文件路徑tinkerBuildFlavorDirectory表示使用flavor多渠道打包時,原始包文件夾路徑。如果使用了flavor多渠道打包,只需要填這一個路徑就行,上面三個可以不要管。如果沒有使用flavor多渠道打包,這個路徑也可以不要管。
基礎包打完,配置好build.gradle之后。可以試著去修改java文件中的代碼,或者修改layout資源文件等,模擬修復原始包中的bug。修改完之后,便可以使用gradle打補丁包。
因為我使用了flavor多渠道打包,所以會有這么多內(nèi)容。雙擊tinker下你需要的打補丁包版本(注意補丁包要和原始包版本一樣),就會生成補丁包了。補丁包在項目文件中的路徑為 app/build/outputs/tinkerPatch。 默認生成的補丁包擴展名是.apk,也可以改為其他類型。把補丁包放入手機sd卡下。
然后在app中觸發(fā)熱修復代碼,如下:
TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(), Environment.getExternalStorageDirectory().getAbsolutePath() + "/patch_signed_7zip.apk"); 其中第二個參數(shù)為補丁包的文件路徑。注意,此方法必須在Tinker初始化完成之后調(diào)用。一個思考: 在正式環(huán)境中,熱修復應該是這樣進行的。 后臺應該提供一個接口,每次app啟動的時候,訪問這個接口看需不需要熱修復,如果需要,后臺要返回補丁包的下載地址。app獲取到補丁包地址后開始下載補丁包到手機中,下載完成之后啟動熱修復,也就是執(zhí)行上面那句代碼。 修復完成之后,app需要重新啟動,修復才會生效。
這是第一次使用熱修復,對于Tinker也還有許多東西沒弄清楚。要投入真正的使用也許還會遇到其它許多問題,比如apk混淆等。歡迎一起交流。
幸好官方文檔已經(jīng)算比較詳細了,還有sample項目可以參考。
官方sample項目地址
官方接入指南
官方介紹以及問題匯總
新聞熱點
疑難解答