[Android]AndFix使用说明
AndFix使用说明
AndFix,全称是Android hot-fix。是阿里开源的一个热补丁框架,允许APP在不重新发布版本的情况下修复线上的bug。支持Android 2.3 到 6.0,并且支持arm 与 X86系统架构的设备。完美支持Dalvik与ART的Runtime,补丁文件是以 .apatch 结尾的文件。
参考网站:
AndFix使用说明:
http://www.jianshu.com/p/479b8c7ec3e3
Alibaba-AndFix Bug热修复框架原理及源码解析 :
http://blog.csdn.net/qxs965266509/article/details/49816007
Andfix修复的整体流程:

AndFix的实现原理是方法的替换:

具体使用:
我们以一个具体的例子来说明:
demo测试activity生命周期函数界面很简单,只是一个textView加button,当前textView显示的是有bug,那么点击button之后,就会加载补丁,textView就会显示bug第一次被修复了。
先给出TestActivityLifeCycle.java:
 package com.tulipsport.android.andfixdemos.test_activity;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import com.tulipsport.android.andfixdemos.R;
import com.tulipsport.android.andfixdemos.utils.PatchUtils;
public class TestActivityLifeCycle extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    TextView text=(TextView)findViewById(R.id.test);
    text.setText("有bug");
    findViewById(R.id.button).setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v){
            PatchUtils.loadPatch(getApplicationContext());
        }
    });
}
}
按照下面1-3步执行,然后打包生成一个“有bug”的apk文件,我们将它命名为1.apk。
然后,将上面的   text.setText("有bug");换成   text.setText("bug第一次被修复了");再次打包,生成apk文件,我们将它命名为2.apk。然后使用apkpatch工具,根据1.apk和2.apk生成补丁文件,有关 补丁文件的生成操作和命名方式,见5-6.
假设我们生成的补丁为2_1.apatch,现在来演示效果。
将有bug的apk安装到模拟器上:

打开app:显示有bug

我们将补丁文件放在sdcard根目录下的tulipsport_patches文件夹下,

开始演示效果:

1.使用gradle添加依赖
compile 'com.alipay.euler:andfix:0.3.1@aar'
2.使用PatchUtils
创建一个PatchUtils的工具类,用于加载补丁。
public class PatchUtils{
private static final String TAG="euler";
private static final String TULIPSPORT_PATCHES="/tulipsport_patches";
private static final String DIR="apatch";//补丁文件夹
/**
 * patch manager
 */
public static PatchManager mPatchManager;
public static void loadPatch(Context context){
    mPatchManager=new PatchManager(context);
    mPatchManager.init(getVersionName(context));
    mPatchManager.loadPatch();
    try {
        File dir=new File(Environment.getExternalStorageDirectory()
                .getAbsolutePath() + TULIPSPORT_PATCHES);
        String loadPatchName=Environment.getExternalStorageDirectory()
                .getAbsolutePath() + TULIPSPORT_PATCHES + "/" +
                String.valueOf(getVersionCode(context))
                + "_" +
                FileUtils.getLoadPatchName(dir,
                        "apatch",String.valueOf(getVersionCode(context))) + ".apatch";
        Log.d("loadPatchName",loadPatchName);
        mPatchManager.addPatch(loadPatchName);
        Log.d(TAG,"apatch:" + loadPatchName + " added.");
        //复制且加载补丁成功后,删除下载的补丁
        File f=new File(context.getFilesDir(),DIR);
        if (f.exists()) {
            boolean result=new File(loadPatchName).delete();
            if (!result)
                Log.e(TAG,loadPatchName + " delete fail");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}
private static int getVersionCode(Context context){
    try {
        PackageInfo pi=context.getPackageManager().getPackageInfo(context.getPackageName(),0);
        return pi.versionCode;
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
        return 0;
    }
}
private static String getVersionName(Context context){
    try {
        PackageInfo pi=context.getPackageManager().getPackageInfo(context.getPackageName(),0);
        return pi.versionName;
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
        return null;
    }
}}
注意:补丁的下载位置为sdcard根目录下的tulipsport_patches文件夹,可以自行修改。
PatchUtils中使用了FileUtils类,在这里简单给出FileUtils:
package com.tulipsport.android.andfixmorebugs;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
 * Created by Brooks on 2016/3/9.
 */
public class FileUtils{
/**
 * @param fileDir  文件目录
 * @param fileType 后缀名
 * @return 特定目录下的所有后缀名为fileType的文件列表
 */
public static List<String> getFiles(File fileDir,String fileType) throws Exception{
          List<String> lfile=new ArrayList<String>();
           File[] fs=fileDir.listFiles();
          for (File f : fs) {
                   if (f.isFile()) {
                   if (fileType
                  .equals(f.getName().substring(
                   f.getName().lastIndexOf(".") + 1,
                               f.getName().length())))
                   lfile.add(f.getName());
            }
          }
    return lfile;
}
public static String getLoadPatchName(File fileDir,String fileType,String versionCode)  throws Exception{
               List<String> files=getFiles(fileDir,fileType);
                      int maxPatchVersion=0;
                for (String name : files) {
                        if (name.startsWith(versionCode + "_")) {
                                  int patchVersion=Integer.valueOf(name.substring(name.indexOf("_") + 1,name.indexOf(".")));
                                 maxPatchVersion=Math.max(maxPatchVersion,patchVersion);
                      }
                 }
                return String.valueOf(maxPatchVersion);
       }
}
3.添加权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
4.加载补丁
在需要加载补丁的地方调用:
PatchUtils.loadPatch(context);
5.生成补丁
使用工具apkpatch-1.0.3
下载地址:https://github.com/alibaba/AndFix/raw/master/tools/apkpatch-1.0.3.zip
使用命令apkpatch生成补丁。

图示参数缺一不可,否则无法生成补丁!!!
例如:
旧的apk为1.apk,新的apk为2.apk, -o表示补丁的输出目录,-k表示keystore, -p表示keystore的密码,-a表示alias, -e表示entry password。

可以看到在当前目录下生成了相应的补丁文件:

补丁命名规则如下:
6.补丁的命名规则
a_b.apatch
a表示versionCode,b表示当前的补丁的版本。
例如:如果当前的versionCode的版本为4,补丁的版本为3,则命名为4_3.apatch。
7.适用环境说明
Andfix并不能修复所有情况下出现的bug,测试结果如下:

该Demo就是用来测试上述这12种情况的。
例子中都是有bug的情况,请读者自行将bug修复,测试修复情况,使用方法见上面的具体使用。
8.补丁加载的时机
可以放在自定义Application的onCreate方法中,也可以放在button的点击事件中,也可以放在监听网络变化的广播中。
例如:
放在自定义Application中:
package com.tulipsport.android.andfixmorebugs;
 import android.app.Application;
 /**
     * Created by Brooks on 2016/3/4.
      */
  public class MyApplication extends Application{
@Override
public void onCreate(){
    super.onCreate();
    PatchUtils.loadPatch(getApplicationContext());
}
 }
或者放在监听网络变化广播中:
public class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context,Intent intent){
    ConnectivityManager connectivityManager=(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo mobNetInfo=connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
    NetworkInfo wifiNetInfo=connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
    if (!mobNetInfo.isConnected() && !wifiNetInfo.isConnected()) {
        Toast.makeText(context,"网络不可以用",Toast.LENGTH_SHORT).show();
        //改变背景或者 处理网络的全局变量
    } else {
        //改变背景或者 处理网络的全局变量
        //这里开始执行下载补丁操作,下载完成后,开始加载补丁
        Toast.makeText(context,"开始加载补丁",Toast.LENGTH_SHORT).show();
        PatchUtils.loadPatch(context);
    }
}}
9.补丁加载流程

10.混淆
-printmapping proguard.map
首先需要生成mapping文件记录混淆规则,之后可以把printmapping 这句话注释掉,每次只使用applymapping。
-applymapping proguard.map
然后在下面加上
-keep class * extends java.lang.annotation.Annotation
-keepclasseswithmembernames class * {
native <methods>;
}
-keep class com.alipay.euler.andfix.** { *; }
11.局限性
- 无法添加新类和新的字段
 
[Android]AndFix使用说明的更多相关文章
- Android AndFix修复方式的限制
		
这里阅览了很多网上关于修复的资料,一一贴在这里便于查看: https://github.com/alibaba/AndFix 这是官方处 要了解使用,一定得看看这里. http://www.jia ...
 - android studio使用说明
		
一.学习的基本配置文档,搞好各种参数的基本配置,熟练使用. C:\Program Files\Java\jdk1.7.0_09\bin 二.problems meet in weather and ...
 - android ActionBarSherlock使用说明
		
源代码地址:https://github.com/JakeWharton/ActionBarSherlock 1.添加项目依赖包 2.修改AndroidManifest.xml中的主题(或者继承该主题 ...
 - Android 项目的代码混淆,Android proguard 使用说明
		
简单介绍 Java代码是非常easy反编译的. 为了非常好的保护Java源码,我们往往会对编译好的class文件进行混淆处理. ProGuard是一个混淆代码的开源项目.它的主要作用就是混淆,当然它还 ...
 - GT性能测试Android版使用说明
		
1 GT简介 GT(随身调) Android版是腾讯 MIG 专项测试组自行研发的 Android APP 随身调测平台,它是直接运行在手机上的“集成调测环境”(ITE, Integrated Tes ...
 - Android.mk 使用说明
		
Android.mk 详解https://blog.csdn.net/dearsq/article/details/50585537 Android.mk中的主要配置参数: 1.LOCAL_JACK ...
 - 《android基于andFix的热修复方案》实战篇
		
有篇文章说的比较简洁,大家可以参考下:AndFix使用说明 下面说说实际使用中遇到的问题 1:如何继承到gradle项目中 dependencies { compile 'com.alipay.eul ...
 - Android(java)学习笔记153:layout_weight使用注意事项
		
1. android:layout_weight使用说明: layout_weight是权重的意思,也就是各个控件所占的比重,用在LinearLayout布局中.当我们使用layout_weight的 ...
 - Android 混淆那些事儿
		
本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/WmJyiA3fDNriw5qXuoA9MA 作者:l ...
 
随机推荐
- oracle游标:查询并打印员工的姓名和薪水
			
--查询并打印员工的姓名和薪水 --set serveroutput on /* 1.光标的属性 %found:假设取到了记录就是true否则是false: %notfound: */ declare ...
 - Eclipse Android 代码自己主动提示功能
			
Eclipse Android 代码自己主动提示功能 Eclipse for android 实现代码自己主动提示智能提示功能.介绍 Eclipse for android 编辑器中实现两种主要文件 ...
 - Java基础数据类型的默认值
			
1.整数类型(byte.short.int.long)的基本类型变量的默认值为0. 2.单精度浮点型(float)的基本类型变量的默认值为0.0f. 3.双精度浮点型(double)的基本类型变量的默 ...
 - Android开发:《Gradle Recipes for Android》阅读笔记(翻译)5.3——使用Robotium进行功能测试
			
问题: 你想要使用Robotium库测试activity. 解决方案: 增加Robotium依赖,编写自己的测试脚本. 讨论: Android Test Support Library提供类可以操作a ...
 - Castle.MVC框架介绍
			
Castle.MVC目前还在Castle的Sandbox中,只是在源代码管理中有,还没有向外发布版本,这里介绍多时Web的MVC,和Castle的MonoRail相比较,这个MVC可以Asp.Net的 ...
 - cxGrid 显示行号及行号列列名
			
cxGrid默认不显示行号,但是可以通过cxGrid1DBTableView1CustomDrawIndicatorCell事件来重绘行号 选中cxGrid1DBTableView1,在OnCusto ...
 - hdu1066(经典题)
			
求N个数阶乘末尾除0后的数值. 主要的难点在于要把这个N个数所含的2和5的队数去掉. 网上方法很多很好. 不多说 Last non-zero Digit in N! Time Limit: 2000/ ...
 - border-radius 原理分析
			
border-radius 想必大家都有所了解,比较常见的用法就像下面一样: 注意左边的盒子 border-radius: 100px; 右边的为0哦,所以右边的实际上没有设置圆角边框属性:咱们比较 ...
 - 160704、commons-beanutils.jar常用方法
			
package com.test.beanutils; import java.lang.reflect.InvocationTargetException;import java.text.Pars ...
 - pycharm中配置Django运行环境(包括run manage.py task)
			
1.特别注意Environment variables(环境变量)的配置 DJANGO_SETTINGS_MODULE=(项目名).settings 如: DJANGO_SETTINGS_MODULE ...