AndFix的使用(详解)
来源:互联网 发布:那些软件 新用户 编辑:程序博客网 时间:2024/06/06 18:36
一、Andfix的使用范围(与其他的比较)
图片参考:http://m.blog.csdn.net/alpha58/article/details/74854680
也就是说AndFix存在以下的缺陷:
① 不支持YunOS
② 无法添加新类和新的字段
③ 需要使用加固前的apk制作补丁,但是补丁文件很容易被反编译,也就是修改过的类源码容易泄露。
④ 使用加固平台可能会使热补丁功能失效(看到有人在360加固提了这个问题,自己还未验证)。
⑤ andfix不支持布局资源等的修改
⑥ 官网:AndFix supports Android version from 2.3 to 7.0, both ARM and X86 architecture, both Dalvik and ART runtime, both 32bit and 64bit.
⑦ 应用patch不需要重启。但由于从实现上直接跳过了类初始化,设置为初始化完毕,所以像是静态函数、静态成员、构造函数都会出现问题,复杂点的类Class.forname很可能直接就会挂掉。
⑧ AndFix的一个潜在问题:
加载一次补丁后,out.apatch文件会copy到getFilesDir目录下的/apatch文件夹中,在下次补丁更新时,会检测补丁是否已经添加在apatch文件夹下,已存在就不会复制加载sdcard的out.apatch。(后面会解决的)
二、自定义签名
参考:http://blog.csdn.net/nimasike/article/details/51457229
三、集成AndFix
1.在app的build.gradle 添加
compile ‘com.alipay.euler:andfix:0.5.0’
2.所需要自定义一个PacthManger.
因为上述存在的问题:加载一次补丁后,out.apatch文件会copy到getFilesDir目录下的/apatch文件夹中,在下次补丁更新时,会检测补丁是否已经添加在apatch文件夹下,已存在就不会复制加载sdcard的out.apatch。所需要自定义一个PacthManger.
public class MyPatchManager { private static final String TAG = "PatchManager"; // patch extension private static final String SUFFIX = ".apatch"; private static final String DIR = "apatch"; private static final String SP_NAME = "_andfix_"; private static final String SP_VERSION = "version"; /** * context */ private final Context mContext; /** * AndFix manager */ private final AndFixManager mAndFixManager; /** * patch directory */ private final File mPatchDir; /** * patchs */ private final SortedSet<Patch> mPatchs; /** * classloaders */ private final Map<String, ClassLoader> mLoaders; /** * @param context * context */ public MyPatchManager(Context context) { mContext = context; mAndFixManager = new AndFixManager(mContext); mPatchDir = new File(mContext.getFilesDir(), DIR); mPatchs = new ConcurrentSkipListSet<Patch>(); mLoaders = new ConcurrentHashMap<String, ClassLoader>(); } /** * initialize * * @param appVersion * App version */ 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(); } } private void initPatchs() { File[] files = mPatchDir.listFiles(); for (File file : files) { addPatch(file); } } /** * add patch file * * @param file * @return patch */ private Patch addPatch(File file) { Patch patch = null; if (file.getName().endsWith(SUFFIX)) { try { patch = new Patch(file); mPatchs.add(patch); } catch (IOException e) { Log.e(TAG, "addPatch", e); } } return patch; } private void cleanPatch() { File[] files = mPatchDir.listFiles(); for (File file : files) { mAndFixManager.removeOptFile(file); if (!FileUtil.deleteFile(file)) { Log.e(TAG, file.getName() + " delete error."); } } } /** * remove all patchs */ public void removeAllPatch() { cleanPatch(); SharedPreferences sp = mContext.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); sp.edit().clear().commit(); } /** * load patch,call when plugin be loaded. used for plugin architecture.</br> * * need name and classloader of the plugin * * @param patchName * patch name * @param classLoader * classloader */ public void loadPatch(String patchName, ClassLoader classLoader) { mLoaders.put(patchName, classLoader); Set<String> patchNames; List<String> classes; for (Patch patch : mPatchs) { patchNames = patch.getPatchNames(); if (patchNames.contains(patchName)) { classes = patch.getClasses(patchName); mAndFixManager.fix(patch.getFile(), classLoader, classes); } } } /** * load patch,call when application start * */ public void loadPatch() { mLoaders.put("*", mContext.getClassLoader());// wildcard Set<String> patchNames; List<String> classes; for (Patch patch : mPatchs) { patchNames = patch.getPatchNames(); for (String patchName : patchNames) { classes = patch.getClasses(patchName); mAndFixManager.fix(patch.getFile(), mContext.getClassLoader(), classes); } } } /** * load specific patch * * @param patch * patch */ private void loadPatch(Patch patch) { Set<String> patchNames = patch.getPatchNames(); ClassLoader cl; List<String> classes; for (String patchName : patchNames) { if (mLoaders.containsKey("*")) { cl = mContext.getClassLoader(); } else { cl = mLoaders.get(patchName); } if (cl != null) { classes = patch.getClasses(patchName); mAndFixManager.fix(patch.getFile(), cl, classes); } } } public void addPatch(String path) throws IOException { /* *@Description :addPatch,重写这个方法,那是因为源码中的addPatch()方法, * 在gradle里导入andfix会有个问题,是在原来的项目中,加载一次补丁后, * out.apatch文件会copy到getFilesDir目录下的/apatch文件夹中, * 在下次补丁更新时,会检测补丁是否已经添加在apatch文件夹下, * 已存在就不会复制加载sdcard的out.apatch, * 所以我们需要对框架中patch文件下的PatchManager类中的addPatch()方法进行修改 *@Author: gaogang6 *@Date : 2017/8/29 15:34 *@Params: [path] *@Return: void */ File src = new File(path); File dest = new File(mPatchDir, src.getName()); if (!src.exists()) { throw new FileNotFoundException(path); } if (dest.exists()) { Log.d(TAG, "patch [" + src.getName() + "] has be loaded."); boolean deleteResult = dest.delete(); if (deleteResult) Log.e(TAG, "patch [" + dest.getPath() + "] has be delete."); else { Log.e(TAG, "patch [" + dest.getPath() + "] delete error"); return; } } FileUtil.copyFile(src, dest);// copy to patch's directory Patch patch = addPatch(dest); if (patch != null) { loadPatch(patch); } }}
3、自定义Application
import java.io.File;import java.io.IOException;import android.app.Application;import android.os.Environment;import android.util.Log;/** * sample application * * @author sanping.li@alipay.com * */public class MainApplication extends Application { private static final String TAG = "euler"; private static final String APATCH_PATH = "/out.apatch";//补丁的文件 /** * patch manager */ private MyPatchManager mPatchManager; @Override public void onCreate() { super.onCreate(); // initialize mPatchManager = new MyPatchManager(this); mPatchManager.init("1.0"); Log.d(TAG, "inited."); // load patch mPatchManager.loadPatch(); Log.d(TAG, "apatch loaded."); // add patch at runtime try { // 自己在sdcard中存放.apatch文件的位置 File file=new File(Environment.getExternalStorageDirectory().getAbsoluteFile() +File.separator+"gaogang"+File.separator); if (!file.exists()){ file.mkdir(); } // 自己在sdcard中存放.apatch文件的位置 String patchFileString = Environment.getExternalStorageDirectory() .getAbsolutePath()+File.separator+"gaogang"+ APATCH_PATH; mPatchManager.addPatch(patchFileString); Log.d(TAG, "apatch:" + patchFileString + " added."); } catch (IOException e) { Log.e(TAG, "打补丁出错了", e); } }}
记住在AndroidManifest.xml文件中添加Application
四、如何使用
在实际中,.apatch文件最好是在Loading界面就通过网络下载补丁文件,然后存储到sdcard自己存放的那么目录下面。(Andoid6.0之后需要动态申请存储权限)。
(1)首先:编辑一个
然后使用Build->Build APK。将apk的名字命名为bug.apk
再随便修改一下
同理将名字命名为nobug.apk
(2)下载一个文件apkpatch.把之前生成的bug.apk和nobug.apk,还有打包所使用的keystore文件放到apkpatch-1.0.3目录下
打开cmd,进入到apkpatch-1.0.3目录下,输入如下指令
apkpatch.bat -f nobug.apk -t bug.apk -o out -k andfix.jks -p 111111 -a gaogang -e 111111
每个参数含义如下
-f 新版本的apk
-t 旧版本的apk
-o 输出apatch文件的文件夹,可以随意命名
-k 打包的keystore文件名
-p keystore的密码
-a keystore 用户别名
-e keystore 用户别名的密码
(3)安装有bug.apk
(4)点击显示:
(5)将out.apatch文件放入服务器
关闭了,再代开
大兄弟,项目下载地址在这里
- AndFix的使用(详解)
- AndFix的简单使用
- (4.2.32.3)android热修复之Andfix方式:Andfix的初步使用
- Eclipse下Andfix的使用
- Android热修复(一):AndFix的使用
- Andfix的apkpatch的工具使用
- 热补丁介绍及Andfix的使用
- AndFix的使用和主要点
- AndFix Bug热修复框架的使用
- AndFix 使用实践
- AndFix使用感想
- AndFix使用源码分析
- AndFix 热修复使用
- AndFix使用总结
- Andfix集成与使用
- (4.2.32.4)android热修复之Andfix方式:Andfix的实践应用
- (4.2.32.5)android热修复之Andfix方式:Andfix的补丁生成方法分析
- (4.2.32.6)android热修复之Andfix方式:Andfix的Hook方式打补丁原理
- eclipse优化方案和启动项目需要注意的
- 小老鼠跑步机的插件
- 公网ip路由设置端口转发
- 深入了解mysql数据传输编码原理
- Spring mvc批量插入sql配置
- AndFix的使用(详解)
- Qt5开发学习之模型/视图结构(十)
- 安装sap gui 750后,打开smartforms提示:CSapEditorCtrl::GetObject: Object 13 does not exist的解决方法
- Ognl表达式语言使用以及迭代
- 实例抓包分析USB鼠标枚举数据流
- p的自动换行
- linux内核空间和用户空间的是怎样区别的,如何交互,如何从用户空间进入内核空间
- 【java】Observer和Observable详解
- N个降序数组,找到最大的K个数TOP K