关于andfix 看这。
最近主管说要把热修复做下,组长把任务交给了我,那就领命开始干,网上找了几篇文章学习了下,最后选择了andfix。在网上找了几篇文章学习了下,感觉just so so嘛,我的内心开始膨胀(只是滚轮子嘛)。
遇到了几个问题,5.0以下同一个方法可以多次修改,5.0以上不行这个问题困扰我很久,报错如下:
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)
至于为什么报这个错误的原因,不知道。。。知道的哥们麻烦告诉我。
既然不能解决这个错误,那只好绕过这个坑了,于是我把将patch文件做成最初版本apk和最新修改过的apk对比生成,andfix对外提供了一个方法patchManager.removeAllPatch()
从字面上就能理解这个方法了,去除所有的.apatch文件。so,在每次下载成功后patchManager.addPatch(target)
前我调用前面的patchManager.removeAllPatch()
方面。看起来一切是如此的合理,此时的我已经膨胀的快要爆炸了。接下来的结果让我很是意外,在修复当前patch文件完成后,再次启动app,最新的已经修复过的patch不再下载和add,此时没有进行addpatch()操作,于是app变成了最初的版本,没有任何修复完成。在我的理解中,这两步操作patchManager.removeAllPatch();patchManager.addPatch( target);
可以永远只保留最后修复过的那个.apatch文件,就不会出现多次修改同一个方法的情况了,看上去完全没有问题啊,我迷茫了。。。我开始意识到andfix肯定在某个步骤中将我最后保留的.apatch文件清除了,我对着源码寻寻觅觅,发现patchManager.removeAllPatch()
不仅仅只是清除了.apatch文件,他还清除了当前的SharedPreferences文件
public void removeAllPatch() {
cleanPatch();
SharedPreferences sp = mContext.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
sp.edit().clear().commit();
}
于是在init时
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,于是我自认为能保留下来的.apatch文件也被删除了。
接下来我采取了如下两种措施:
1、不直接调用removeAllPatch()
反射调用 cleanPatch();
2、听取网上哥们的意见,在removeAllPatch()
后自己将移除的SharedPreferences 文件保存下来,将版本号保存。
最后的结果还是报错,错误还是上面列出来的。
此时的我有点心累。。好受伤。。
最后和组长讨论了下,他说何不自己建立目录保存.apatch文件呢?一语惊醒梦中人啊!方案出来了:
1、在file目录下建立一个文件夹保存.apatch文件(ps:andfix就是这么做的),将下载的文件保存在里面。当然,文件名要是个唯一标识。
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、检查有更新文件时,将先前自己保存的文件删除,再去下载文件。保证只保留一个文件,多的浪费存储空间。
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()
的实现很简单。在检查更新时如果没有更新就直接加载最后保留的那个,当然本身就没有更新文件,那就不用加载,可以通过查看保留的唯一标识来判断。
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,没有问题,其他的没有试过,因为没有手机。。。
希望这篇文章能帮助到你,当然你不想修复多次,也就没有这个问题了,前面说了一堆废话,只是想发泄一下(还可以筹字数。。。。嘎嘎)。