關(guān)于andfix 看這。
最近主管說要把熱修復(fù)做下蹦锋,組長把任務(wù)交給了我兆沙,那就領(lǐng)命開始干,網(wǎng)上找了幾篇文章學(xué)習(xí)了下莉掂,最后選擇了andfix葛圃。在網(wǎng)上找了幾篇文章學(xué)習(xí)了下,感覺just so so嘛憎妙,我的內(nèi)心開始膨脹(只是滾輪子嘛)库正。
遇到了幾個(gè)問題,5.0以下同一個(gè)方法可以多次修改厘唾,5.0以上不行這個(gè)問題困擾我很久褥符,報(bào)錯(cuò)如下:
Fatal Exception: java.lang.IllegalAccessError: Method 'void com.amour.chicme.activity.MainActivity_CF.q()' is inaccessible to class 'com.amour.chicme.activity.MainActivity_CF' (declaration of 'com.amour.chicme.activity.MainActivity_CF' appears in /data/user/0/com.amour.chicme/files/apatch/572340d6d21e9e13ac2d7556.apatch)
at com.amour.chicme.activity.MainActivity_CF.onCreate(Unknown Source)
at android.app.Activity.performCreate(Activity.java:6237)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
至于為什么報(bào)這個(gè)錯(cuò)誤的原因,不知道抚垃。喷楣。。知道的哥們麻煩告訴我鹤树。
既然不能解決這個(gè)錯(cuò)誤铣焊,那只好繞過這個(gè)坑了,于是我把將patch文件做成最初版本apk和最新修改過的apk對(duì)比生成罕伯,andfix對(duì)外提供了一個(gè)方法patchManager.removeAllPatch()
從字面上就能理解這個(gè)方法了曲伊,去除所有的.apatch文件。so追他,在每次下載成功后patchManager.addPatch(target)
前我調(diào)用前面的patchManager.removeAllPatch()
方面坟募。看起來一切是如此的合理邑狸,此時(shí)的我已經(jīng)膨脹的快要爆炸了懈糯。接下來的結(jié)果讓我很是意外,在修復(fù)當(dāng)前patch文件完成后推溃,再次啟動(dòng)app昂利,最新的已經(jīng)修復(fù)過的patch不再下載和add届腐,此時(shí)沒有進(jìn)行addpatch()操作铁坎,于是app變成了最初的版本蜂奸,沒有任何修復(fù)完成。在我的理解中硬萍,這兩步操作patchManager.removeAllPatch();patchManager.addPatch( target);
可以永遠(yuǎn)只保留最后修復(fù)過的那個(gè).apatch文件扩所,就不會(huì)出現(xiàn)多次修改同一個(gè)方法的情況了,看上去完全沒有問題啊朴乖,我迷茫了祖屏。。买羞。我開始意識(shí)到andfix肯定在某個(gè)步驟中將我最后保留的.apatch文件清除了袁勺,我對(duì)著源碼尋尋覓覓,發(fā)現(xiàn)patchManager.removeAllPatch()
不僅僅只是清除了.apatch文件畜普,他還清除了當(dāng)前的SharedPreferences文件
public void removeAllPatch() {
cleanPatch();
SharedPreferences sp = mContext.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
sp.edit().clear().commit();
}
于是在init時(shí)
public void init(String appVersion) {
if (!mPatchDir.exists() && !mPatchDir.mkdirs()) {// make directory fail
Log.e(TAG, "patch dir create error.");
return;
} else if (!mPatchDir.isDirectory()) {// not directory mPatchDir.delete();
return;
}
SharedPreferences sp = mContext.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
String ver = sp.getString(SP_VERSION, null);
if (ver == null || !ver.equalsIgnoreCase(appVersion)) {
cleanPatch();
sp.edit().putString(SP_VERSION, appVersion).commit();
} else {
initPatchs();
}
}
獲取到的ver為null期丰,于是我自認(rèn)為能保留下來的.apatch文件也被刪除了。
接下來我采取了如下兩種措施:
1吃挑、不直接調(diào)用removeAllPatch()
反射調(diào)用 cleanPatch();
2钝荡、聽取網(wǎng)上哥們的意見,在removeAllPatch()
后自己將移除的SharedPreferences 文件保存下來舶衬,將版本號(hào)保存埠通。
最后的結(jié)果還是報(bào)錯(cuò),錯(cuò)誤還是上面列出來的逛犹。
此時(shí)的我有點(diǎn)心累端辱。。好受傷虽画。掠手。
最后和組長討論了下,他說何不自己建立目錄保存.apatch文件呢狸捕?一語驚醒夢(mèng)中人芭绺搿!方案出來了:
1灸拍、在file目錄下建立一個(gè)文件夾保存.apatch文件(ps:andfix就是這么做的),將下載的文件保存在里面做祝。當(dāng)然,文件名要是個(gè)唯一標(biāo)識(shí)鸡岗。
private void uploadFixData(final Hotfix hotfix) {
File file = new File(getFilesDir(), "hotfix");
if (!file.exists() && !file.mkdirs()){
return;
}
final String target = file.getAbsolutePath() + "/" + hotfix.id + ".apatch";
ConfigManager.getInstance().downloadHotfixFile(hotfix.patchUrl, target, new RequestCallBack<File>() {
@Override
public void onSuccess(ResponseInfo<File> responseInfo) {
try {
patchManager.removeAllPatch();
patchManager.addPatch( target);
SPUtils.save("hotfix", "hotfixID", hotfix.id);
} catch (Exception e) {
addLastApatch();
UIUtils.showToast(e.toString());
SPUtils.save("hotfix", "hotfixID", "0");
e.printStackTrace();
}
}
@Override
public void onFailure(HttpException e, String s) {
addLastApatch();
}
});
}
2混槐、檢查有更新文件時(shí),將先前自己保存的文件刪除轩性,再去下載文件声登。保證只保留一個(gè)文件,多的浪費(fèi)存儲(chǔ)空間。
private void checkAndfixData() {
ConfigManager.getInstance().getAppHotfixData(new RequestCallBack<String>() {
@Override
public void onSuccess(ResponseInfo<String> responseInfo) {
ResponseUtils responseUtils = new ResponseUtils(responseInfo.result);
if (responseUtils.isSuccess()) {
Hotfix hotfix = responseUtils.onSuccessModel(Hotfix.class);
String existId = SPUtils.getString("hotfix", "hotfixID"); if (hotfix == null || TextUtils.isEmpty(hotfix.id)) {
return;
} else if (hotfix != null && !hotfix.id.equals(existId)) {
File file = new File(getFilesDir(), "hotfix");
if (file.exists()){
file.delete();
}
uploadFixData(hotfix);
} else {
addLastApatch();
}
} else {
String existId = SPUtils.getString("hotfix", "hotfixID");
if (!TextUtils.isEmpty(existId)) {
addLastApatch();
}
}
}
@Override
public void onFailure(HttpException e, String s) {
addLastApatch();
}
});
}
3悯嗓、addLastApatch()
的實(shí)現(xiàn)很簡單件舵。在檢查更新時(shí)如果沒有更新就直接加載最后保留的那個(gè),當(dāng)然本身就沒有更新文件脯厨,那就不用加載铅祸,可以通過查看保留的唯一標(biāo)識(shí)來判斷。
private void addLastApatch() {
try {
File file = new File(getFilesDir(), "hotfix");
if (!file.exists()){
return;
}
String lastApatchPath = file.getAbsolutePath() + "/" + SPUtils.getString("hotfix", "hotfixID") + ".apatch";
patchManager.addPatch(lastApatchPath);
} catch (IOException e) {
e.printStackTrace();
}
}
至此合武,問題解決了临梗。試過三星NOTE3,紅米note2稼跳,nexus 5盟庞,LG,沒有問題汤善,其他的沒有試過什猖,因?yàn)闆]有手機(jī)。萎津。卸伞。
希望這篇文章能幫助到你,當(dāng)然你不想修復(fù)多次锉屈,也就沒有這個(gè)問題了荤傲,前面說了一堆廢話,只是想發(fā)泄一下(還可以籌字?jǐn)?shù)颈渊。遂黍。。俊嗽。嘎嘎)雾家。