参考链接:
浅谈Android热修复:http://blog.youkuaiyun.com/caihongdao123/article/details/52051799
Android 热补丁动态修复框架小结:http://blog.youkuaiyun.com/lmj623565791/article/details/49883661
Android热修复之AndFix:http://blog.youkuaiyun.com/zhimingshangyan/article/details/51893983
准备工作
下载拆分包工具apkpatch-1.0.3
https://github.com/alibaba/AndFix/tree/master/tools
引入AndFix库
compile 'com.alipay.euler:andfix:0.3.1@aar'
查看AndFix源码:
https://github.com/alibaba/AndFix
关键代码
//补丁管理器
PatchManager mPatchManager = new PatchManager(this);
//初始化
mPatchManager.init("1.0");
//移除所有补丁
mPatchManager.removeAllPatch();
//加载当前所有补丁
mPatchManager.loadPatch();
//添加补丁
mPatchManager.addPatch(patchFileString);
doc命令:
apkpatch.bat -f new1.apk -t old.apk -o output -k andfix.keystore -p 123456 -a andfix -e 123456
apkpatch.bat -f 修改后的apk -t 未修改前的apk -o output -k keystore签名 -p ketstore密码 -a alias名称 -e alias密码
程序代码
MainApplication.java
public class MainApplication extends Application {
public static PatchManager mPatchManager;
@Override
public void onCreate() {
super.onCreate();
try {
//注意每次appversion变更都会导致所有补丁被删除,如果appversion没有改变,则会加载已经保存的所有补丁。
String appversion = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
PatchManager mPatchManager = new PatchManager(this);
mPatchManager.init(appversion);
} catch (Exception e) {
}
}
}
MainActivity.java
public class MainActivity extends Activity {
public PatchManager mPatchManager;
static TextView tv_say_content;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
MainApplication application = (MainApplication) getApplication();
this.mPatchManager = application.mPatchManager;
//值得注意的是andfix只能加载一次补丁,如果要生效需要调用
mPatchManager.removeAllPatch();
mPatchManager.loadPatch();
//添加patch,只需指定patch的路径即可,补丁会立即生效
File fileDir = new File(Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/apatch");
if(!fileDir.exists()){
fileDir.mkdir();
}else{
//按顺序添加多个补丁,建议不超过2个,AndFix适合紧急修复不适合迭代修复
File[] files = fileDir.listFiles();
for (int i = 0; i < files.length; i++) {
String name = files[i].getName();
mPatchManager.addPatch(files[i].getAbsolutePath());
}
}
//添加单个补丁
// String APATCH_PATH = "/out.apatch";
// String patchFileString = Environment.getExternalStorageDirectory()
// .getAbsolutePath() + APATCH_PATH;
// mPatchManager.addPatch(patchFileString);
} catch (Exception e) {
e.printStackTrace();
}
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
tv_say_content = (TextView)rootView.findViewById(R.id.tv_say_content);
Button btn_say = (Button)rootView.findViewById(R.id.btn_say);
btn_say.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
tv_say_content.setText(new AndFixSay().sayFix());
}
});
//1.没有image,点击btn say
//2.没有image,点击btn sayFix
//3.有image,点击btn sayFix
//4.有image,点击btn sayFix,点击image say
ImageView image = (ImageView)rootView.findViewById(R.id.iv);
image.setVisibility(View.VISIBLE);
image.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
tv_say_content.setText(new AndFixSay().say());
}
});
return rootView;
}
}
}
生成补丁操作
准备keystore,old.apk,new.apk放在apkpatch-1.0.3目录下
进入到apkpatch-1.0.3目录下,执行apatch命令
回车生成output文件夹
output目录下有一个.apatch的文件,这个就是新旧版本的差分补丁
.apatch补丁名可随意修改,方便理解。
注意点:
不要指望依赖.apatch来完成多个版本的迭代,任何的补丁修复技术只是用于bug的紧急修复。
正式开发的时候建议将.apatch文件放在后台,能在适当时机起到修复补丁的作用。
有什么不懂的请点击本文开头的3个参考链接,那里有更加详细的说明。