关于andfix热更新的配置
配置环境 Android studio
1、在build.gradle中添加引用包
compile 'com.alipay.euler:andfix:[email protected]//官方最新的为0.5.0,但是在4.4版本中存在bug,推荐使用0.4.0
2、在Application中初始化
代码如下
public static PatchManager mPatchManager; @Override public void onCreate() { super.onCreate(); // 初始化patch管理类 mPatchManager = new PatchManager(this); // 初始化patch版本 mPatchManager.init("1.0"); // String appVersion = getPackageManager().getPackageInfo(getPackageName(), 0).versionName; // mPatchManager.init(appVersion); // 加载已经添加到PatchManager中的patch mPatchManager.loadPatch(); }
3、混淆不能忘记
-keep class * extends java.lang.annotation.Annotation -keepclasseswithmembernames class * { native <methods>; }
4、设置补丁名称
private static final String APATCH_PATH = "/fix.apatch"; // 补丁文件名
5、下载补丁包
/** * 网络请求下载补丁包 */ private class DownloadFileThread implements Runnable { @Override public void run() { try { File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + APATCH_PATH); HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); connection.setRequestMethod("GET"); connection.setRequestProperty("Accept-Encoding", "identity"); long sum = 0; if (file.exists()) { file.delete(); /*sum = file.length(); // 设置断点续传的开始位置 connection.setRequestProperty("Range", "bytes=" + file.length() + "-");*/ } int code = connection.getResponseCode(); if (code == 200 || code == 206) { int contentLength = connection.getContentLength(); contentLength += sum; InputStream is = connection.getInputStream(); /* * * 创建一个向具有指定 name 的文件中写入数据的输出文件流。 * true表示当文件在下载过程中出现中断, * 当再次链接网络时,将会从断点处追加。 * * */ if(Build.VERSION.SDK_INT>=23){ verifyStoragePermissions(MainActivity.this); } FileOutputStream fos = new FileOutputStream(file, true); byte[] buffer = new byte[1024]; int length; while ((length = is.read(buffer)) != -1) { fos.write(buffer, 0, length); sum += length; percent = sum * 100.0f / contentLength; } update(); } } catch (IOException e) { e.printStackTrace(); } } }
6、加载补丁包
private void update() { String patchFileStr =Environment.getExternalStorageDirectory().getAbsolutePath() + APATCH_PATH; try { AndFixApplication.mPatchManager.addPatch(patchFileStr); } catch (IOException e) { e.printStackTrace(); } }7、注意Android 6.0以上要动态设置读取权限
private static final int REQUEST_EXTERNAL_STORAGE = 1; private static String[] PERMISSIONS_STORAGE = { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE };
public static void verifyStoragePermissions(Activity activity) { // Check if we have write permission int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE); if (permission != PackageManager.PERMISSION_GRANTED) { // We don't have permission so prompt the user ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE); } }
8、准备打补丁
设置button ,当点击button是提示一句话,用来和加载补丁之后做对比判断补丁是否加载成功
9、下载官方提供的工具
https://github.com/alibaba/AndFix.git 找到apkpatch-1.0.3文件夹下载下来放到桌面
10、先打一个正式包
放到下载好的apkpatch-1.0.3文件中设置一个名字。我设置的是andfix_v1.0
11、修改一处地方再打另一个正式包
也放到下载好的 apkpatch-1.0.3文件中设置一个名字。我设置的是andfix_v2.0
12、把打包用的jks文件也放到这个文件中
13、打开cmd命令窗口
输入cd Desktop回车
再输入 cd apkpatch-1.0.3 回车
再输入
解释如下
- -f <new.apk> :新apk
- -t <old.apk> : 旧apk
- -o <output> : 输出目录(补丁文件的存放目录)
- -k <keystore>: 打包所用的keystore
- -p <password>: keystore的密码
- -a <alias>: keystore 用户别名
- -e <alias password>: keystore 用户别名密码
在output中得到文件andfix_v2-64aef0866fcd3f5d7046716911b8cf52.apatch,然后改为和自己设置的文件名一致,然后放到服务器中。
我打补丁之前写的是提示的是打补丁之前,加载补丁之后提示打补丁之后
注意:
andfix 只能修改代码不能修改布局文件,不能替换资源文件,无法添加新类和新的字段
需要使用加固前的apk制作补丁,但是补丁文件很容易被反编译,也就是修改过的类源码容易泄露。
使用加固平台可能会使热补丁功能失效(看到有人在360加固提了这个问题,自己还未验证)。
应用patch不需要重启。但由于从实现上直接跳过了类初始化,设置为初始化完毕,所以像是静态函数、静态成员、构造函数都会出现问题,复杂点的类Class.forname很可能直接就会挂掉
'