和android热修复AndFix技术亲密接触

每次回家都偷懒,不想整理一下,今天周末,强迫自己整理下,内容一定很全。

前言

随着app版本升级迭代,难免有些bug会出现,用户升级新版的代价较高,如果能给app打热补丁,热更新掉app的bug,岂不更好。

Andfix

andfix是阿里的一个热修复框架,更新至今,已经相对完善了,可以满足我们日常需求。它有很多优点,比如:

1.热修复免重启app

2.更新包小

3.支持360加固(很多blog上说不支持,其实是支持的,下文会介绍怎么用)

至于缺点吗,我不说,哈哈。

下图为热修复图解

使用方式

1.在android studio里添加依赖

compile ‘com.alipay.euler:andfix:[email protected]‘

1.在Application的onCreate方法中初始化andfix

   // 初始化patch管理类
   mPatchManager = new PatchManager(this);
   // 初始化patch版本
   String appVersion = "1.0";
   try {
       appVersion = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;//获取app版本号
   } catch (PackageManager.NameNotFoundException e) {
       e.printStackTrace();
   }
   mPatchManager.init(appVersion);
   // 加载已经添加到PatchManager中的patch
   mPatchManager.loadPatch();

在热修复版本时,appversion不用变。

页面布局

为了方便测试,主页面放3个button,第一个用来显示是否有bug,第二个用来从网络上下载热修复包(需自建web服务),然后热修复,第三个用来从本地文件中加载热修复包(无需自建web服务)。

代码

public class MainActivity extends AppCompatActivity {
    private MyApplication app;
    private static final String LOCAL_NAME = "local.apatch";//本地SD卡中的更新文件[2选1]
    private static final String NET_NAME = "net.apatch";//网络上的更新文件[2选1]
    private final String url="http://192.168.1.2/net.apatch";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //用于模拟是否有bug
        findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "出现bug", Toast.LENGTH_SHORT).show();
//              Toast.makeText(MainActivity.this, "bug已经修复", Toast.LENGTH_SHORT).show();
              //[第二个版本注释第一行,取消第二行注释]
            }
        });
        //网络下载并热修复
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                fix();
            }
        });
        //本地热修复
        findViewById(R.id.button3).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                update();
            }
        });
    }
    .....

更新的两个方法

    //本地热更新
    private void update() {
        String patchFileStr = Environment.getExternalStorageDirectory().getAbsolutePath() +File.separator+ LOCAL_NAME;
        try {
            MyApplication.mPatchManager.addPatch(patchFileStr);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //网络下载热更新
    private void fix() {
        new Thread(){
            @Override
            public void run() {
                try {
                    String patchFileStr = Environment.getExternalStorageDirectory().getAbsolutePath();
                    downLoadFromUrl(url, NET_NAME, patchFileStr);
                    MyApplication.mPatchManager.addPatch(patchFileStr);//热修复
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

为了减少代码量,这里网络请求没有使用框架,而是自己写的网络请求方法

/**
     * 从网络Url中下载文件
     *
     * @param urlStr
     * @param fileName
     * @param savePath
     * @throws IOException
     */
    public static void downLoadFromUrl(String urlStr, String fileName, String savePath) throws IOException {
        URL url = new URL(urlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        //设置超时间为3秒
        conn.setConnectTimeout(3 * 1000);
        //防止屏蔽程序抓取而返回403错误
        conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");

        //得到输入流
        InputStream inputStream = conn.getInputStream();
        //获取自己数组
        byte[] getData = readInputStream(inputStream);

        //文件保存位置
        File saveDir = new File(savePath);
        if (!saveDir.exists()) {
            saveDir.mkdir();
        }
        File file = new File(saveDir + File.separator + fileName);
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(getData);
        if (fos != null) {
            fos.close();
        }
        if (inputStream != null) {
            inputStream.close();
        }
        System.out.println("info:" + url + " download success");
    }

    /**
     * 从输入流中获取字节数组
     *
     * @param inputStream
     * @return
     * @throws IOException
     */
    public static byte[] readInputStream(InputStream inputStream) throws IOException {
        byte[] buffer = new byte[1024];
        int len = 0;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        while ((len = inputStream.read(buffer)) != -1) {
            bos.write(buffer, 0, len);
        }
        bos.close();
        return bos.toByteArray();
    }

编译

项目编译需要自备签名文件,如果没有的话,自己创建一个




生成含bug的apk

将生成出的app-release.apk文件重命名为bug.apk

生成解决bug的apk

把出现bug的那条toast注释掉,改为bug已修复的toast

再次编译将生成的app-release.apk文件重命名为fixedbug.apk

生成apatch

这里需要去下载工具

https://github.com/alibaba/AndFix

tools文件夹里是工具,下载到本地

顺便将刚刚两个bug.apk和fixedbug.apk以及签名文件放入文件夹

因为我们只有一个fixedbug.apk所以我们用下面的生成代码

apkpatch -f <new> -t <old> -o <output> -k <keystore> -p <***> -a <alias> -e <***>
 -a,--alias <alias>     keystore entry alias.
 -e,--epassword <***>   keystore entry password.
 -f,--from <loc>        new Apk file path.
 -k,--keystore <loc>    keystore path.
 -n,--name <name>       patch name.
 -o,--out <dir>         output dir.
 -p,--kpassword <***>   keystore password.
 -t,--to <loc>          old Apk file path.

具体做法

1.先打开cmd或者终端,cd到当前目录下

2.敲入

apkpatch-1.0.3/apkpatch.sh -f fixedbug.apk  -t bug.apk  -o Out -k a.jks -p 123456 -a 654321 -e 654321

3.这个时候这个out文件夹下apatch文件就是热更新包

4.将此文件改名net.apatch放入www目录下

保证刚刚的http://192.168.1.2/net.apatch路径可以访问

开始测试

先安装bug.apk到手机上

1.打开ddms

2.将net.apatch复制一份命名为local.apatch拉入手机中

可以顺便将bug.apk也放入手机,方便安装(或其它方式安装bug.apk)

3.打开app,运行如图

出现bug



4.点击本地文件热修复,然后再次点击显示

提示bug已修复

至此从本地文件热修复演示完成

5.卸载app,重新安装然后点击显示,出现bug,点击网络下载热修复,再次点击显示,提示bug已修复(同上图)

总结

至此两种方法热修复均解决了appbug,代码不复杂,需要源码请留言。

补充

当团队协作时,多个小组生成出多个apatch文件,可以使用工具合并

apkpatch -m <apatch_path...> -o <output> -k <keystore> -p <***> -a <alias> -e <***>
 -a,--alias <alias>     keystore entry alias.
 -e,--epassword <***>   keystore entry password.
 -k,--keystore <loc>    keystore path.
 -m,--merge <loc...>    path of .apatch files.
 -n,--name <name>       patch name.
 -o,--out <dir>         output dir.
 -p,--kpassword <***>   keystore password.

混淆代码

-keep class * extends java.lang.annotation.Annotation
-keepclasseswithmembernames class * {
    native <methods>;
}
时间: 2024-12-16 02:52:28

和android热修复AndFix技术亲密接触的相关文章

Android热修复原理普及

Android热修复原理普及 这段时间比较难闲,就抽空研究一下Android热修复的原理.自从Android热修复这项技术出现之后,随之而现的是多种热修复方案的出现.前两天又看到一篇文章分析了几种热修复方案的比较. 原文地址是:[Android热修复] 技术方案的选型与验证 看完这篇文章,有点汗颜.有这么多的热修复方案,并且他们之间的实现原理也不一样,各有优缺点. 然后在尼古拉斯_赵四的博客中看到几篇关于热修复的文章,对着这几篇文章撸了一番.大概的了解了热修复一种原理,其思路和QQ空间提出的安卓

Android热修复之微信Tinker使用初探

文章地址:Android热修复之微信Tinker使用初探 前几天,万众期待的微信团队的Android热修复框架tinker终于在GitHub上开源了. 地址:https://github.com/Tencent/tinker 官方介绍:https://my.oschina.net/shwenzhang/blog/751618 接入指南:https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%9

Android热修复:Andfix和Hotfix,两种方案的比较与实现

Andfix和hotfix是两种android热修复框架. android的热修复技术我看的最早的应该是QQ空间团队的解决方案,后来真正需要了,才仔细调查,现在的方案中,阿里有两种Dexposed和Andfix框架,由于前一种不支持5.0以上android系统,所以阿里系的方案我们就看Andfix就好.Hotfix框架算是对上文提到的QQ空间团队理论实现.本文旨在写实现方案,捎带原理. Andfix 引入 框架官网:https://github.com/alibaba/AndFix 介绍是用英文

Android热修复技术专题:来自微信、淘宝、支付宝、QQ空间的热修复方案

最近好多人都讨论关于热更新的话题,所以查询了一些资料看看 当一个App发布之后,突然发现了一个严重bug需要进行紧急修复,这时候公司各方就会忙得焦头烂额:重新打包App.测试.向各个应用市场和渠道换包.提示用户升级.用户下载.覆盖安装.有时候仅仅是为了修改了一行代码,也要付出巨大的成本进行换包和重新发布. 这时候就提出一个问题:有没有办法以补丁的方式动态修复紧急Bug,不再需要重新发布App,不再需要用户重新下载,覆盖安装?答案当然是有的,那就是最近涌现出来得热补丁方案,主要包括淘宝的Dexpo

全面了解Android热修复技术

WeTest 导读 本文探讨了Android热修复技术的发展脉络,现状及其未来. 热修复技术概述 热修复技术在近年来飞速发展,尤其是在InstantRun方案推出之后,各种热修复技术竞相涌现.国内大部分成熟的主流APP都拥有自己的热修复技术,像手淘.支付宝.QQ.饿了么.美团等等. 目前能搜集到的资料,大多简单罗列每个方案的特点并进行横向比较,而其中技术发展的脉络往往被掩盖了.热修复技术从何而来,又将往何处去?在这些资料中都找不到答案. 我认为,走马观花地看一遍各家的热修复方案并不能找到答案,所

Android 热修复方案分析

绝大部分的APP项目其实都需要一个动态化方案,来应对线上紧急bug修复发新版本的高成本.之前有利用加壳,分拆两个dex结合DexClassLoader实现了一套全量更新的热更方案.实现原理在Android 基于Proxy/Delegate 实现bug热修复这篇博客中有分解.因为这套方案是在Java端实现,并且是全量更新所以兼容性较好,成功率较高.但是在线上跑了几个月之后就碰到了瓶颈,因为随着业务的增长分拆过之后的dex文件方法数也超过65535个,更换拆包方案的话维护成本太高.同时由于没有做差异

Android 热修复 Tinker接入及源码浅析

本文已在我的公众号hongyangAndroid首发.转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/54882693本文出自张鸿洋的博客 一.概述 放了一个大长假,happy,先祝大家2017年笑口常开. 假期中一行代码没写,但是想着马上要上班了,赶紧写篇博客回顾下技能,于是便有了本文. 热修复这项技术,基本上已经成为项目比较重要的模块了.主要因为项目在上线之后,都难免会有各种问题,而依靠发版去修复问题,成本太高了. 现在热

Android热修复框架汇总整理(Hotfix)

??Android平台出现了一些优秀的热更新方案,主要可以分为两类:一类是基于multidex的热更新框架,包括Nuwa.Tinker等:另一类就是native hook方案,如阿里开源的Andfix和Dexposed. 基于native hook的方案 ??需要针对dalvik虚拟机和art虚拟机做适配,需要考虑指令集的兼容问题,需要native代码支持,兼容性上会有一定的影响: 基于Multidex的方案 ??需要反射更改DexElements,改变Dex的加载顺序,这使得patch需要在下

Android热修复与插件化实践之路

第1章 class文件与dex文件解析本章通过从java最基本的class文件与android最基本的dex文件进行对比,并不借助IDE去生成及执行class与dex文件,通过讲解class与dex的手动生成,执行, 格式对比,让学生明白二者的相同与不同.1-1 课程项目整体介绍1-2 本章概述1-3 class文件详解上1-4 class文件详解下1-5 dex文件详解上1-6 dex文件详解下 第2章 虚拟机深入讲解本章主要介绍jvm,dvm,art.通过对这三个虚拟机的介绍让学生明白,an