一直关注App的热修复的技术发展,之前做的应用也没用使用到什么热修复开源框架。在App的热修复框架没有流行之前,做的应用上线后发现一个小小的Bug,就要马上发一个新的版本。我亲身经历过一周发两个版本,真的折腾用户的节奏~~所以,要开始考虑引入热修复。下面记录使用开源框架阿里巴巴的AndFix过程。

实现的原理

这里说的不是热修复怎么实现修bug的原理,这里说的是怎么使用AndFix。如果你想了解更多的andFix实现原理,你可以参考下面的文章:

  1. 应用启动的时候,在 onCreate() 方法中获取友盟的在线参数来判断当前的应用版本是否有补丁需要下载,有则通过ThinDonloadManager来下载到SD下并且通过使用AndFix来加载到应用中。
  2. 使用极光推送消息到该应用的版本需要下载补丁,如果应用收到了消息后,应用判断当前的版本是否需要下载补丁。如果应用没有收到消息的通知,则下次启动App的时候,获取友盟在线参数来判断是否需要下载补丁。
步骤
  1. 在gradle文件中增加相应的依赖。这里我使用thindownlaodmanager来下载补丁,使用极光推送来推送自定义消息下载补丁通知,使用友盟在线参数来获取补丁包的信息。也许你会问为了修复一个补丁而增加这么多的依赖,值得吗?我认为还可以吧,因为我的项目一般会使用到这些。

    AndFix的引入是: compile 'com.alipay.euler:andfix:0.3.1@aar'

  2. 导入AndFix的so库文件以及极光推送的so库文件;
    极光推送集成参考文档:http://docs.jpush.io/client/android_sdk/
    注意:导入AndFix的so文件时,可以先阅读这下个:https://github.com/zhonghanwen/AndFix-Ndk-Build-ADT

  3. 配置友盟在线参数的参数以及推光推送自定义的内容

    • 友盟在线参数

    • 极光推送自定义消息(自定义消息有长度限制,所以补丁的下载url写成拼接形式:站点+下载资源名称)

    • 定义相对应的Bean

  4. 在启动的自定义Application类进行初始化工作(AndFix、极光的初始化)

  5. 在程序的入口类进行友盟补丁的检测:

    private void getUmengParamAndFix() {
    //获取友盟在线参数对应key的values
    String pathInfo = OnlineConfigAgent.getInstance().getConfigParams(this, UMENG_ONLINE_PARAM);
    if (!TextUtils.isEmpty(pathInfo)){
    PatchBean onLineBean = GsonUtils.getInstance().parseIfNull(PatchBean.class , pathInfo);
    try {
    //进行判断当前版本是否有补丁需要下载更新
    RepairBugUtil.getInstance().comparePath(this, onLineBean);
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }

      

  6. 再加上推送推送的自定义内容的处理:(当推送消息过来的时候应用处于运行状态的时候,程序会处理消息进行下载补丁包)

        private WeakHandler mHandler = new WeakHandler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
    if (msg.what == MSG_WHAT_DOWNLOAD){
    String message = (String) msg.obj;
    if (TextUtils.isEmpty(message)) return false;
    try {
    PatchBean bean = GsonUtils.getInstance().parse(PatchBean.class, message);
    RepairBugUtil.getInstance().comparePath(MainActivity.this, bean);
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    return false;
    }
    }); //for receive customer msg from jpush server
    private MessageReceiver mMessageReceiver;
    public static final String MESSAGE_RECEIVED_ACTION = "com.zhw.andfix.MESSAGE_RECEIVED_ACTION";
    public static final String KEY_MESSAGE = "message"; public void registerMessageReceiver() {
    mMessageReceiver = new MessageReceiver();
    IntentFilter filter = new IntentFilter();
    filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
    filter.addAction(MESSAGE_RECEIVED_ACTION);
    registerReceiver(mMessageReceiver, filter);
    } public class MessageReceiver extends BroadcastReceiver { @Override
    public void onReceive(Context context, Intent intent) {
    if (MESSAGE_RECEIVED_ACTION.equals(intent.getAction())) {
    String message = intent.getStringExtra(KEY_MESSAGE);
    Message msg = new Message();
    msg.what = MSG_WHAT_DOWNLOAD;
    msg.obj = message;
    mHandler.sendMessage(msg);
    }
    }
    }

      

  7. 补丁包的生成

    • 下载AndFix的补丁生成工具:here
    • 生成补丁的文件需要的文件有:原apk文件,修复Bug后生成的新apk,签名文件。
    • 在解压apkpatch工具的目录下,打开命令行输入以下命令生成补丁包。apkpatch -m <apatch_path...> -o <output> -k <keystore> -p <***> -a <alias> -e <***>
    • 将生成的补丁放到指定服务器上。(这里我放到了七牛上)
  8. 自己测试一下成不成啦~

代码

通过ThinDownloadManager下载补丁包,下载成功后使用AndFix加载补丁包的方法:

public void downloadAndLoad(Context context, final PatchBean bean, String downloadUrl) {
if (mLocalPreferencesHelper == null) {
mLocalPreferencesHelper = new LocalPreferencesHelper(context, SPConst.SP_NAME);
}
Uri downloadUri = Uri.parse(downloadUrl);
Uri destinationUri = Uri.parse(Environment.getExternalStorageDirectory()
.getAbsolutePath() + bean.url);
DownloadRequest downloadRequest = new DownloadRequest(downloadUri)
.setDestinationURI(destinationUri)
.setPriority(DownloadRequest.Priority.HIGH)
.setDownloadListener(new DownloadStatusListener() {
@Override
public void onDownloadComplete(int id) {
// add patch at runtime
try {
// .apatch file path
String patchFileString = Environment.getExternalStorageDirectory()
.getAbsolutePath() + bean.url;
BaseApplication.mPatchManager.addPatch(patchFileString);
Log.d(TAG, "apatch:" + patchFileString + " added."); //复制且加载补丁成功后,删除下载的补丁
File f = new File(patchFileString);
if (f.exists()) {
boolean result = new File(patchFileString).delete();
if (!result)
Log.e(TAG, patchFileString + " delete fail");
}
// mLocalPreferencesHelper.saveOrUpdate(SPConst.IsHavePathDownLoad, false);
} catch (IOException e) {
Log.e(TAG, "", e);
} catch (Throwable throwable) { }
} @Override
public void onDownloadFailed(int id, int errorCode, String errorMessage) {
//下载失败的时候,标注标记位,等下次重新打开应用的时候重新下载
// mLocalPreferencesHelper.saveOrUpdate(SPConst.IsHavePathDownLoad, true);
Log.e(TAG, "onDownloadFailed"); } @Override
public void onProgress(int id, long totalBytes, int progress) {
Log.e(TAG, "progress:" + progress);
}
});
mDownloadManager = new ThinDownloadManager(THREAD_COUNT);
mDownloadManager.add(downloadRequest);
}

  

判断是否有补丁包需要下载的方法:

  public void comparePath(Context context, PatchBean RemoteBean) throws Exception {
String pathInfo = mLocalPreferencesHelper.getString(SPConst.PATH_INFO);
final PatchBean localBean = GsonUtils.getInstance().parseIfNull(PatchBean.class, pathInfo);
//远程的应用版本跟当前应用的版本比较
if (BaseApplication.VERSION_NAME.equals(RemoteBean.app_v)) {
//远程的应用版本跟本地保存的应用版本一样,但补丁不一样,则需要下载重新
/**
*第一种情况:当本地记录的Bean为空的时候(刚安装的时候可能为空)并且远程的Bean的path_v不为空的时候需要下载补丁。
* 第二种情况:当本地记录的path_v和远程Bean的path_v不一样的时候需要下载补丁。
*/
if (localBean == null && !TextUtils.isEmpty(RemoteBean.path_v)
|| localBean.app_v.equals(RemoteBean.app_v) &&
!localBean.path_v.equals(RemoteBean.path_v)) {
downloadAndLoad(context, RemoteBean,
SPConst.URL_PREFIX + RemoteBean.url);
String json = GsonUtils.getInstance().parse(RemoteBean);
mLocalPreferencesHelper.saveOrUpdate(SPConst.PATH_INFO, json);
} /*else {
mLocalPreferencesHelper.saveOrUpdate(SPConst.IsHavePathDownLoad, false);
}*/
}
}

  

项目GitHub地址:https://github.com/zhonghanwen/AndFix-Bad-Practices

Android热修复实践应用--AndFix的更多相关文章

  1. Android热修复之AndFix使用教程

    AndFix的github地址 AndFix 全称Android hot-fix,是alibaba的Android热修复框架,支持Android 2.3到6.0的版本,支持arm与X86系统架构,支持 ...

  2. 全面了解Android热修复技术

    WeTest 导读 本文探讨了Android热修复技术的发展脉络,现状及其未来. 热修复技术概述 热修复技术在近年来飞速发展,尤其是在InstantRun方案推出之后,各种热修复技术竞相涌现.国内大部 ...

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

      文章地址:Android热修复之微信Tinker使用初探 前几天,万众期待的微信团队的Android热修复框架tinker终于在GitHub上开源了. 地址:https://github.com/ ...

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

      Android平台出现了一些优秀的热更新方案,主要可以分为两类:一类是基于multidex的热更新框架,包括Nuwa.Tinker等:另一类就是native hook方案,如阿里开源的Andfix ...

  5. Android热修复技术原理详解(最新最全版本)

    本文框架 什么是热修复? 热修复框架分类 技术原理及特点 Tinker框架解析 各框架对比图 总结   通过阅读本文,你会对热修复技术有更深的认知,本文会列出各类框架的优缺点以及技术原理,文章末尾简单 ...

  6. Android热修复技术总结

    https://blog.csdn.net/xiangzhihong8/article/details/77718004 插件化和热修复技术是Android开发中比较高级的知识点,是中级开发人员通向高 ...

  7. Android热修复技术原理详解

    阿里Dexposed -- native解决方案 原理: 直接在native层进行方法的结构体信息对换,从而实现完美的方法新旧替换,从而实现热修复功能   他的思想完全来源于Xposed框架,完美诠释 ...

  8. 深入探索Android热修复技术原理读书笔记 —— 热修复技术介绍

    1.1 什么是热修复 对于广大的移动开发者而言,发版更新是最为寻常不过的事了.然而,如果你 发现刚发出去的包有紧急的BUG需要修复,那你就必须需要经过下面这样的流程: 这就是传统的更新流程,步骤十分繁 ...

  9. 深入探索Android热修复技术原理读书笔记 —— 代码热修复技术

    在前一篇文章 深入探索Android热修复技术原理读书笔记 -- 热修复技术介绍中,对热修复技术进行了介绍,下面将详细介绍其中的代码修复技术. 1 底层热替换原理 在各种 Android 热修复方案中 ...

随机推荐

  1. asp.net mvc 之旅—— 第二站 窥探Controller下的各种Result

    平时我们在Action中编码的时候,我们都知道所有的Action返回值类型都是ActionResult,并且我们的返回值也是各种奇葩,比如:Json(),Content(), View()等等...当 ...

  2. 深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点

    深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点 2011-12-28 23:00 by 汤姆大叔, 139489 阅读, 119 评论, 收藏, 编辑 才华横溢的 ...

  3. ubuntu16.04下vim安装失败

    问题? 重装了ubuntu系统,安装vim出现了以下问题:   sudo apt-get install vim   正在读取软件包列表... 完成 正在分析软件包的依赖关系树        正在读取 ...

  4. 利用apply和arguments复用方法

    首先,有个单例对象,它上面挂了很多静态工具方法.其中有一个是each,用来遍历数组或对象. var nativeForEach = [].forEach var nativeMap = [].map ...

  5. java汉化

    http://download.eclipse.org/technology/babel/babel_language_packs/R0.13.0/luna/luna.php _x86_64版本下载地 ...

  6. 第14章 位图和位块传输_14.4 GDI位图对象(3)

    14.4.10 非矩形的位图图像 (1)“掩码”位图——单色位图,要显示的像素对应的掩码置1,不显示置0(2)光栅操作(点这里,见此文分析) (3)MaskBlt函数 ①MaskBlt(hdcDest ...

  7. Unity 碰撞器

    Unity引擎的碰撞器 常见的有Box Collider,Capsule Collider等等 IsTrigger(触发器) 在这些碰撞器中有一个属性 Is Trigger(是否使用触发器) 触发器事 ...

  8. web 小知识

    document.write和innerHTML的区别   document.write是直接写入到页面的内容流,如果在写之前没有调用document.open, 浏览器会自动调用open.每次写完关 ...

  9. Windows 10 UWP开发:如何不让界面卡死

    http://edi.wang/post/2016/2/18/windows-10-uwp-async-await-ui-thread 关于UI线程 这里我们需要一点关于 UI 线程模型的概念,简单的 ...

  10. jmeter 函数助手里的P,property的使用

    1.函数助手里的 p及property的使用 ${__P(init,2)} , ${__property(init,start,200)} 可以自行定义变量名称,及变量的默认值 P 变量名为init, ...