前言
本文最主要的是講解下自己是如何在在項目中更恰當合理的運用SopHix,當然這只是我團隊兩個人的做法而已。經驗總是要踩出來的,對同學有幫助就最好了。
以下分為六部分
-
引言
-
官方使用步驟
-
測試開發中熱更新修復操作五部曲
-
下發補丁步驟
-
如何處理加載補丁成功后的彈窗強制更新提醒
-
如何爬坑
一、引言
熱修復技術可謂是百花齊放,許多產品都聲稱自己可以做到全方位全功能的熱修復。不過他們各自有自身的局限性,或者不夠穩定,或者補丁過大,或者效率低下,或者使用起來過于繁瑣,大部分技術上看起來似乎可行,但實際體驗并不好。而在我們看來,有很多技術細節能夠做得更加完美。
終于在2017年6月11日,手淘技術團隊聯合阿里云正式發布了史上首個非侵入式移動熱更新解決方案——Sophix。
Sophix熱修復方案主要開發者,萬壑 就職于手機淘寶。
Sophix的橫空出世,將會打破各家熱修復技術紛爭的局面。我們可以滿懷信心地說,在Android熱修復的三大領域:代碼修復、資源修復、so修復方面,以及方案的安全性和易用性方面,Sophix都做到了業界領先。
文章介紹 https://yq.aliyun.com/articles/103527?spm=5176.8091938.0.0.l6pz1T
??下面的這張表格引用自[ 作者博文],從幾個熱修復最重要的維度,把Sophix和另外兩個主要商業化熱修復方案進行了比較。
而其中唯一不支持的地方就是四大組件的修復,這是因為如果要修復四大組件,必須在AndroidManifest里面預先插入代理組件,并且盡可能聲明所有權限,而這么做就會給原先的app添加很多臃腫的代碼,對app運行流程的侵入性很強。可以插入幾個代理文件即可。我在項目中就這么做。
二、官方使用步驟
Android 接入流程請開發者務必仔細閱讀一遍官方文檔。文檔是最好的老師
先去創建應用
然后快速接入流程
三、測試開發中熱更新修復操作五部曲
打包區分的三個包
Base_1.5.30 (基礎包用于對比)
Safe_1.5.30(加固過后的包,發布給線上使用)
Test_1.5.31(在打完Base包之后修改版本號,再打一個測試包,確保代碼一致,用于安裝,下發補丁首先下發到該版本,我是這么做的)Safe_1.5.30發布完上線之后 ,在你的Android Studio中修改版本號為1.5.33 繼續開發或者修復BUG,反正需要大于1.5.31(因為你做測試需要先在Sophix后臺下發補丁到1.5.31,你本地代碼沒有修改的話, build 運行時會收到Sophix服務器的下發的補丁,此時代碼覆蓋會讓你一臉懵逼)
這時你已經在 Dev_1.5.33 版本中修復了BUG,打包1.5.33之后,需要通過 Sophix工具上傳 基礎包 Base_1.5.30 進行比對生成 Sophix-Patch.jar 補丁包 ,(生成的補丁與版本號無關,工具只會對比代碼結構, so,資源等) 完成后將其上傳至Sophix后臺
指定下發對應版本號,先下發到Test_1.5.31 測試版本,補丁下發成功! 手機安裝 先測試驗收,驗收成功之后再指定下發到 正式的版本 1.5.30 即可
Tips: 在Android Studio中 開發中的版本需要比Test1.5.31版本大,便于在 Build 運行項目時,不會因聯網下發到針對1.5.31的補丁 指示代碼收到下發的補丁 受影響
注意事項:
下發補丁修復bug不要去修改 Manifest 的文件,發布補丁時的版本也最好不要去修改一些依賴庫的版本,會出現某些問題!
還有打base包的 那份代碼需要備份這個分支,然后copy一個分支進行下一步的開發,以防萬一合成補丁出錯,進行代碼比對
舊包內部版本號不能 比新包內部版本號大,不然會生成補丁出錯
??這里我并沒有使用官方的調試工具進行調試。而是直接在項目中查看日志補丁加載狀態。要多注意每個Code代表的意思 ,這里文檔也有描述到,詳情查看SDK中PatchStatus類的代碼,有具體說明
四、下發補丁步驟
生成補丁工具
??假設當前 版本為 1.5.30 為發布的包,而你要先進行更新測試包更新包版本為 1.5.31 ,這個時候你就要將最新代碼生成的apk文件包與base基線版本1.5.30做比對。此時生成的補丁文件 sophix-patch.jar 上傳至 Sophix 后臺。
??補丁版本為后臺自控的。會進行疊加。繼續上傳一個補丁則上一個版本的補丁自動停用.
- 添加版本號要注意格式1.X.X 或者 1.XXX
![~J$E2{$(6OFRBSI]WA7Y0MR.png](http://upload-images.jianshu.io/upload_images/956862-2a3012b0a3c770ab.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -
上傳補丁文件,并且加點描述
bing
五、如何處理加載補丁成功后的彈窗強制更新提醒
- 強制更新補丁狀態說明:
一般都會把查詢補丁的操作放在Application中去操作,Sophix啟動APP時會調用方法請求查詢最新的補丁,這句話一般在Application中的onCreate()方法的Super之前去進行調用,這里貼一下自己項目中的代碼
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
initHotfix(base);
}
public void onCreate() {
SophixManager.getInstance().queryAndLoadNewPatch();
super.onCreate();
...
}
// 阿里熱修復
private void initHotfix(Context context) {
SophixManager.getInstance().setContext(this)
.setAppVersion(VersionUtils.getVersionName(this))
.setAesKey(null)
.setEnableDebug(false)
.setPatchLoadStatusStub((mode, code, info, handlePatchVersion) -> {
// 補丁加載回調通知
String s = "mode:" + mode + " code:" + code + "\npatchVersion:" + handlePatchVersion + "\ninfo:" + info;
hotfixController(context, code, handlePatchVersion, s);//這里是處理相對應的主要Code的操作,代碼就不貼完整了,你可以根據官方的來進行操作,建議多加一個對CODE_LOAD_NOPATCH 狀態碼14,沒有補丁的情況針對性的操作
}).initialize();
}
```
Q:收到Code 12 之后,有的包是需要提示用戶強制冷啟動的,而有的包是不用提示,等下次自己更新就好了。這樣的情況怎么判斷當前的包是處于哪種情況呢?
需要提示 & 不需要再提示?
A:官方給我的提示,需要自己加個推送什么的,回調中沒有這個標識。((__) 嘻嘻…… 如果Shophix后臺有支持就好了)這里主要講解下發成功 狀態為 1 "load new patch success."時,也就是補丁下發成功了,之后提醒用戶的操作。
這里需要判斷兩個前提條件,都要提示用戶去重啟應用, 要注意回調狀態碼Code 等于12 “please relaunch app to load new patch” 的時候 就是冷啟動的提示。 這里我并沒有根據12去做判斷進行重啟。
下面說下我自己項目中的兩個必要重啟判斷條件,僅供參考。
* 1、取得SopHix SDK啟動時返回的最新的補丁版本號(hotfixPatchVersion)和服務器返回的補丁版本號(hotfixMustUpdateVersion)相同,且大于當前最后一次強制重啟的補丁版本號(hotfixLastMustVersion 將每次返回的補丁版本寫入SP記錄)
* 2、或者第一次下載、數據被清除后,如果有新強制更新版本,則強制更新
建議定義三個字段進行比較
public static final String hotfixPatchVersion = "hotfixPatchVersion"; // 阿里返回的補丁版本號
public static final String hotfixMustUpdateVersion = "hotfixMustUpdateVersion"; // 服務器返回的版本號
public static final String hotfixLastMustVersion = "hotfixLastMustVersion"; // 最后一次強制重啟的版本號
注意:
以上所說的這種方式,實際項目中加載了最新的補丁,需要把這個Sophix中最新的補丁版本號,告知后臺進行修改為最新更新的補丁號。一般在版本更新的接口中多加入一個字段(downloadPatchCode ),請求時用于進行比對。
提示用戶關閉時的處理,可以在PatchLoadStatusListener監聽到CODE_LOAD_RELAUNCH后在合適的時機,調用此方法殺死進程。注意,不可以直接Process.killProcess(Process.myPid())來殺進程,這樣會擾亂Sophix的內部狀態。因此如果需要殺死進程,建議使用這個方法,它在內部做一些適當處理后才殺死本進程。本人是直接在一個透明的 彈窗提示判斷中關閉時調用的此方法進行關閉。
SophixManager.getInstance().killProcessSafely();
六、如何爬坑
以下是我所遇到過的兩個問題,遇到問題心態不要蹦,先去查看日志,再去查看官方文檔,或者QA,百分之七八十都可以解決,若你還不能解決你就去官方釘釘群交流:11734260 進行交流。
問題1
熱修復Android SDK:在4.x的手機系統上崩潰
在4.x的系統上出現IllegalAccessException:class ref in pre-verified異常,應用崩潰
問題原因
??這個是由于我們是完整dex修復,所以會出現新dex中的類和老dex中的類沖突,所以要在Sophix初始化前避免加載原有apk中的類,而對于4.x版本的系統,如果在Sophix初始化之前有加載原有apk中的類,則會影響修復的過程,造成崩潰
解決方案
https://help.aliyun.com/knowledge_detail/55414.html?spm=5176.7851422.2.4.SyAVhp
??Sophix初始化在Application最前面,同時盡量用系統類及盡量不使用log等,或者把initialize寫到attachBaseContext里面,但query還是在onCreat的最前面;如果有用到MultiDex,直接繼承Application,在attachBaseContext里寫MultiDex.install(base),然后在onCreat的最前面initialize和query,如果還會出現這個崩潰,把initialize寫到attachBaseContext的MultiDex.install(base)后面,但query還是在onCreat的最前面
問題2
這個問題很奇怪,項目老大解決的。我現在只知道不能這么做而已。
??在4.X的設備上,用OkHttp作為Fresco的網絡加載器的時候,如果發布新的包(比如只修改一個Toast),
在下載完重啟后會直接崩潰報如下錯誤:
Process: com.newtest.myapplication, PID: java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
而其他機型則不會。 很明顯和第一個錯誤是一樣的。
Sophix對4.X的機型有Bug: 在一個外部引用的包里,自帶的實例,需要去調用這個包里的另一個實例方法時,會報上面這個錯; 但把這個包里的實例移到App里創建,再去調用相同的那個方法里就不會了。 就是說4.X的引用包里的方法不能再次調用引用包里的別的方法。 現在已經解決了,但5.0及以上的機型卻不會有這個Bug,這只是很奇葩的問題,如果沒遇到過同學略過吧~
以上兩個問題也屬于同一個問題,詳細閱讀作者這邊文章會有些啟示。
- 由于是直接在項目分支中引入的Sophix 所以沒有寫個Demo。
有空補上(這是我聽過過最大的笑話)
貼一個官方Demo
以上僅是自己的處理方式,寫的不好的地方還望指正,有問題還望同學們指點一二,O(∩_∩)O謝謝!
學會分享~