文档章节

Android Hotpatch系列之-项目介绍

fneg
 fneg
发布于 2015/08/03 23:07
字数 995
阅读 8501
收藏 41

    在手淘工作期间,内部有一套解决方案,给线上apk打补丁,直接修复bug,不用客户端升级,有严重线上bug,找到问题,写个patch,推上线就把问题解决了,用过的都说好。前段时间,他们终于把这套东西的Android端开源了,Dexposed,具体可以看详细的项目介绍。其功能就是可以加载类,替换原先apk里面某个类的方法,或者在方法之前,方法之后做些什么,比如在方法执行之前,修改传入方法的参数了,方法执行以后,修改方法的返回值,或者就是完全替换掉原先的方法。

    项目里面有一个sample,介绍了如何加载一个外部apk包,然后替换宿主apk里面类的方法。其实这就已经完成了80%的工作了,我做的工作只是将Patch获取从本地加载改成了去服务器获取,以及添加了Patch apk的校验(md5和签名信息)。

    Hotpatch的工作流程是:

         1.实现一个从服务器端获取Patch信息的接口(上传本地客户端版本等信息,服务器好根据这些信息来判断是否有对应的Patch包),并将这个信息注入给HotpatchManager。

         2.检测客户端是否可以支持。(Android L和Android M)目前都不支持,最低支持2.3

         3.如果客户端支持,那就调用第一步注入的Patch包获取类,获取到对应的Patch信息。下载Patch apk文件。

         4.校验。获取下载好的Patch apk md5签名信息和服务器给的Patch信息的md5值是否一样,然后还要校验Patch apk和宿主apk签名是否一致。加校验是为了防止Patch apk被篡改,如果load进去了一个第三方的Patch,那就是引狼入室了。一定不能去掉校验,不能去掉,不能去掉,重要的事情说三遍!!!

         5.校验成功,就load Patch apk。

   下面是贴代码时间:

public class HotpatchManager {
    private static HotpatchManager INSTANCE=new HotpatchManager();
    private HotpatchManager() {

    }

    public static HotpatchManager getInstance(IPatchInfoRequest request){
        RequestManager.getInstance().setIPatchInfoRequest(request);
        return INSTANCE;
    }

    public boolean init(final Context ctx) {
        boolean isSupport = DexposedBridge.canDexposed(ctx);
        if (isSupport) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    check(ctx);
                }
            }).start();
        }
        return isSupport;
    }

    private  void check(final Context ctx) {
        RequestManager manager = RequestManager.getInstance();
        manager.setIPatchInfoRequest(RequestManager.getInstance().getIPatchInfoRequest());
        manager.reqeust(new RequestManager.OnRequestCallBackListener() {
            @Override
            public void onRequest(final PatchInfo info) {
                if (null != info) {
                    String apkPath = Utils.getCacheApkFilePath(ctx, info.apkFileUrl);
                    File file = new File(apkPath);
                    if (file.exists()) {
                        loadPath(info, ctx, apkPath);
                    } else {
                        DownLoadManager.getInstance().downloadFile(ctx, info.apkFileUrl, new DownLoadManager.OnFileDownload() {
                            @Override
                            public void fileDownload(String apkFilePath) {
                                loadPath(info, ctx, apkFilePath);
                            }
                        });
                    }
                }
            }
        });
    }

    private  void loadPath(PatchInfo info, Context ctx, String apkFilePath) {
        if (Utils.isSignEqual(ctx, apkFilePath) && TextUtils.equals(info.apkMd5, Utils.getMd5ByFile(new File(apkFilePath)))) {
            PatchMain.load(ctx, apkFilePath, null);
        }
    }

}

  

    已经提供了实现好的客户端和服务器例子。网址分别是:

    客户端例子实现:https://github.com/fengcunhan/Hotpatch-Sample

   服务器简易实现:https://github.com/fengcunhan/Hotpatch-SimpleServer

    运行例子步骤:

    1.修改 DefaultPatch类中的info.patchApkUrl  的url中的IP替换成你的服务器的IP,将代码部署到tomcat中。

    2.导入Hotpatch-Sample中的工程到Android Studio中。

    3.打开网址 http://服务器IP:服务器端口/PathServer,将patchsample下build/outputs/apk/app-debug.apk上传到服务器上面,一定不要改名字。

    4.修改DefaultPatchInfoRequest 中的hostUrl的IP和端口为你的服务器端IP和端口。  

    5.运行dexposedexamples项目,点击 Check Hotpatch,如果出现 “The dialog is shown from patch apk”,恭喜你,成功运行了Demo。

     Demo中的Patch只是很简单的一个例子,后续会碰到混淆的类怎么怎么写Patch之类的问题,这些都将在以后一一叙述。请大家关注这个Hotpatch系列。     

     Demo中服务器实现很渣渣。请服务器端大神不要喷,可以fork,不要fuck。

     

       

© 著作权归作者所有

共有 人打赏支持
fneg

fneg

粉丝 77
博文 43
码字总数 23812
作品 0
杭州
高级程序员
私信 提问
加载中

评论(24)

时光Mincir
时光Mincir
SDK 21 的市场份额已经达到32%多,那代表5.0以后的手机都不能进行hotpatch
ZQiang94
ZQiang94

引用来自“fneg”的评论

引用来自“y1世荣耀”的评论

博主,这个和差量更新有什么区别? 没有搞明白,希望楼主解释一下 THX
差量更新,需要在本地再次合并成一个apk,然后提示用户安装新apk,这个patch,不需要用户接入

类似静默安装? 还是压根就没有安装 只是把其中的二进制文件修改或替换了是吧?
fneg
fneg

引用来自“y1世荣耀”的评论

博主,这个和差量更新有什么区别? 没有搞明白,希望楼主解释一下 THX
差量更新,需要在本地再次合并成一个apk,然后提示用户安装新apk,这个patch,不需要用户接入
ZQiang94
ZQiang94
博主,这个和差量更新有什么区别? 没有搞明白,希望楼主解释一下 THX
王宝康
王宝康
楼主,你好,我想问下在补丁包中如何拿到宿主apk中某一个fragment的上下文对象,方便的话可以加下QQ吗,我最近在做这一块,我的QQ 553925770
王宝康
王宝康
知道了,我通过资源id获取到了资源被设置不同的资源id改变了imageView的默认图片,谢谢楼主...
王宝康
王宝康

引用来自“EmbraceTheFuture”的评论

我发现用系统的fragment是没问题的,可是用support包下的就不行了,不知道楼主遇到过没,是否有解决方案。

引用来自“fneg”的评论

我看看,还没有试过,今天试一下

引用来自“EmbraceTheFuture”的评论

ok,期待你的回复,谢谢...

引用来自“fneg”的评论

已经将代码提交到github,麻烦更新代码,我在里面做了一个Fragment onCreateView方法的替换
已下载,我出错的原因是把replaceHookedMethod回调中的methodHookParams的thisObject转换成了Fragment导致的,我想请问楼主,要是获取fragment中的实例还是使用XposeHelpers.getObjectField()这个方法吗,XposedHelpers.getObjectField(view.getContext(), "imageView"),我这样获取Fragment中的imagView全局变量,运行时提示在Activity中找不到imagView这个字段。
fneg
fneg

引用来自“EmbraceTheFuture”的评论

我发现用系统的fragment是没问题的,可是用support包下的就不行了,不知道楼主遇到过没,是否有解决方案。

引用来自“fneg”的评论

我看看,还没有试过,今天试一下

引用来自“EmbraceTheFuture”的评论

ok,期待你的回复,谢谢...
已经将代码提交到github,麻烦更新代码,我在里面做了一个Fragment onCreateView方法的替换
王宝康
王宝康

引用来自“EmbraceTheFuture”的评论

我发现用系统的fragment是没问题的,可是用support包下的就不行了,不知道楼主遇到过没,是否有解决方案。

引用来自“fneg”的评论

我看看,还没有试过,今天试一下
ok,期待你的回复,谢谢...
fneg
fneg

引用来自“EmbraceTheFuture”的评论

我发现用系统的fragment是没问题的,可是用support包下的就不行了,不知道楼主遇到过没,是否有解决方案。
我看看,还没有试过,今天试一下
Android HotPatch 技术研究总结

本次HotPatch的研究主要基于一片文章:《Android-HotPatch在线热补丁方案》和一个实践,手机淘宝HotPatch项目。 特性(Features): 不用安装,直接修改当前APK的逻辑。 缺陷(Defect): 1,无法更...

JamesQin
2016/02/14
740
0
Windows环境下Android Studio系列4—界面介绍

参考资料 [1] Android Studio常用功能介绍, http://ask.android-studio.org/?/article/23 [2] Windows环境下Android Studio系列1—下载与安装, http://my.oschina.net/1pei/blog/467210 [3] ......

一配
2015/06/23
0
0
Cocos2dx游戏开发系列笔记1:一个崭新的开始,cocos2dx2.2+ndkr9+Cygwin

Android开发者做cocos2dx最大的绊脚石,不是c++,而是环境的搭建... 骨头也是费了半天劲才终于在真机上看到了那个类似猕猴桃的头,这里简单记录一下。 环境:(算比较新了2013.11.17) coco...

懒骨头
2013/12/09
0
0
Cocos2dx游戏开发系列笔记9:android手机上运行《战神传说》,并解决横竖屏即分辨率自适应

上节说到cygwin下成功编译出so文件,下面我们要把游戏运行在android上。 开始干活! 其实步骤可以参考 Cocos2dx游戏开发系列笔记6:怎样让《萝莉快跑》的例子运行在vs和手机上 1 用eclipse打...

懒骨头
2013/12/09
0
0
android源码分析网上随笔记录

百度查“android源码分析工具”时发现有一篇知乎文章:巨人的肩膀 其它

whoisliang
03/22
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Confluence 6 教程:在 Confluence 中导航

当你对 Confluence 有所了解后,你会发现 Confluence 使用起来非常简单。这个教程主要是针对你使用的 Confluence 界面进行一些说明,同时向你展示在那里可以进行一些通用的任务和操作。 空间...

honeymose
今天
2
0
sed, awk 练习

1. sed打印某行到某行之间的内容 2. sed 转换大小写 将单词首字母转化大写 将所有小写转化大写 3. sed 在某一行最后面添加一个数字 4. 删除某行到最后一行 解析: {:a;N;$!ba;d} :a : 是...

Fc丶
今天
2
0
babel6升级到7,jest-babel报错:Requires Babel "^7.0.0-0", but was loaded with "6.26.3".

自从将前端环境更新到babel7,jest-babel之前是基于babel6的,执行时候就会报:Requires Babel "^7.0.0-0", but was loaded with "6.26.3". 很烦,因为连续帮好几台电脑修复这个问题,所以记...

曾建凯
今天
1
0
探索802.11ax

802.11ax承诺在真实条件下改善峰值性能和最差情况。 如何改善今天的Wi-Fi? 在决定如何改进当前版本以外的Wi-Fi时,802.11ac,IEEE和Wi-Fi联盟调查了Wi-Fi部署和行为,以确定更广泛使用的障碍...

linuxprobe16
今天
2
0
使用linux将64G的SDCARD格式化为FAT32

一、命令如下: sudo fdisk -lsudo mkfs.vfat /dev/sda -Isudo fdisk /dev/sda Welcome to fdisk (util-linux 2.29.2). Changes will remain in memory only, until you decide to wri......

mbzhong
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部