android 热修补之andfix实践
首先有这方面需要的请到https://github.com/xiangzhihong/andfixDemo/tree/master下载例子
对于网上提供的热补丁修复就不多说了,主要有这3种方式可以实现(至于其他的方式,暂不清楚)
1.dexposed github https://github.com/alibaba/dexposed
2.andfix github https://github.com/alibaba/AndFix
3.bsdiff http://blog.csdn.net/lazyer_dog/article/details/47173013
dexposed和andfix是alibaba的开源项目,都是apk增量更新的实现框架,目前dexposed的兼容性较差,只有2.3,4.0~4.4兼容,其他Android版本不兼容或未测试,详细可以去dexposed的github项目主页查看,而andfix则兼容2.3~6.0,所以就拿这个项目来实现增量更新吧。至于bsdiff,只是阅览了一下,还没研究过。
首先 git clone github https://github.com/alibaba/AndFix,将andfix项目下载下来,Android studio可以在build.gradle里导入andfix,
compile 'com.alipay.euler:andfix:0.3.1'
但是我是使用module的方式添加andfix,这样可以直接查看编辑源码,而且直接gradle导入的话还有个问题,后面再说。
我看了下官网的demo主要是在android装载到内存的时候去加载我们新的dex的包,然后加载到内存,要研究原理的请到这个地址去查看:
http://blog.csdn.net/xiangzhihong8/article/details/50949691
下面主要说实现:
andfix里有些文件夹不用导入的,例如tools,doc等,记得新建jniLibs文件夹,libs里的so文件移到jniLibs里。
接下来我们参照官网的demo
public class MainApplication extends Application {
private static final String TAG = "euler";
private static final String APATCH_PATH = "/out.apatch";
private static final String DIR = "apatch";//补丁文件夹
/**
* patch manager
*/
private PatchManager mPatchManager;
@Override
public void onCreate() {
super.onCreate();
// initialize
mPatchManager = new PatchManager(this);
mPatchManager.init("1.0");
Log.d(TAG, "inited.");
// load patch
mPatchManager.loadPatch();
// Log.d(TAG, "apatch loaded.");
// add patch at runtime
try {
// .apatch file path
String patchFileString = Environment.getExternalStorageDirectory()
.getAbsolutePath() + APATCH_PATH;
mPatchManager.addPatch(patchFileString);
Log.d(TAG, "apatch:" + patchFileString + " added.");
//这里我加了个方法,复制加载补丁成功后,删除sdcard的补丁,避免每次进入程序都重新加载一次
File f = new File(this.getFilesDir(), DIR + APATCH_PATH);
if (f.exists()) {
boolean result = new File(patchFileString).delete();
if (!result)
Log.e(TAG, patchFileString + " delete fail");
}
} catch (IOException e) {
Log.e(TAG, "", e);
}
}
刚刚说的直接在gradle里导入andfix会有个问题,是在原来的项目中,加载一次补丁后,out.apatch文件会copy到getFilesDir目录下的/apatch文件夹中,在下次补丁更新时,会检测补丁是否已经添加在apatch文件夹下,已存在就不会复制加载sdcard的out.apatch。
原来的addpath方法
public void addPatch(String path) throws IOException {
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 [" + path + "] has be loaded.");
return;
}
FileUtil.copyFile(src, dest);// copy to patch's directory
Patch patch = addPatch(dest);
if (patch != null) {
loadPatch(patch);
}
}
修改后,判断apatch下的out.apatch存在即删除掉,重新复制加载sdcard下的out.apatch
public void addPatch(String path) throws IOException {
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);
}
}
还有源码混淆
-optimizationpasses 5 # 指定代码的压缩级别
-dontusemixedcaseclassnames # 是否使用大小写混合
-dontskipnonpubliclibraryclasses # 是否混淆第三方jar
-dontpreverify # 混淆时是否做预校验
-verbose # 混淆时是否记录日志
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* # 混淆时所采用的算法
#重要,別忘了這些,不混淆andfix包,不混淆native方法
-dontwarn android.annotation
-dontwarn com.alipay.euler.**
-keep class com.alipay.euler.** {*;}
-keep class * extends java.lang.annotation.Annotation
-keepclasseswithmembernames class * {
native <methods>;
}
下面我们打包:
cmd输入命令,具体参数看usage
apkpatch.bat -f new.apk -t old.apk -o output1 -k suning.keystore -p Suning1234 -a suning -e Suning1234 【完整命令】
上面这个命令有点问题,用下面的:
apkpatch -f new.apk -t old.apk -o output -k xzh.jks -p 19881205 -a keyalias -e 19881205
解释下这个意思,apkpatch -f <new apk> -t <old.apk> -o<输出位置> -k <keystore> -p<password> -a <key alias> -e <password>
这里的keystore就是你签名包
如无错误,编译后会生成一个apatch文件,改名成out.apatch
里面的smali列出了不同的文件,diff.dex就是android 虚拟机加载运行的不同的文件。
安装打开1.apk
关闭app,将out.apatch放sdcard根目录后,重新打开app,toast方法改变了
2) 几个开源热修复或插件化解决方案(排名不分先后)
https://github.com/lzyzsd/AndroidHotFixExamples
https://github.com/simpleton/dalvik_patch
https://github.com/dodola/HotFix
https://github.com/jasonross/Nuwa
https://github.com/alibaba/AndFix
https://github.com/rovo89/Xposed
https://github.com/alibaba/dexposed
https://github.com/bunnyblue/DroidFix
https://github.com/CtripMobile/DynamicAPK
3) 技术原理博客(排名不分先后)
http://bugly.qq.com/blog/?p=781(QQ空间的解决方案)
https://m.oschina.net/blog/308583(Android Dex分包方案)
http://lirenlong.github.io/hotfix/(浅析xposed、dexposed和AndFix的原理)
http://blog.csdn.net/lmj623565791/article/details/49883661(鸿洋)
http://blog.csdn.net/vipzjyno1/article/details/21039349/(android反编译)
android 热修补之andfix实践的更多相关文章
- 爱奇艺技术分享:爱奇艺Android客户端启动速度优化实践总结
本文由爱奇艺技术团队原创分享,原题<爱奇艺Android客户端启动优化与分析>. 1.引言 互联网领域里有个八秒定律,如果网页打开时间超过8秒,便会有超过70%的用户放弃等待,对Andro ...
- Android App 性能优化实践
本文记录了Android App优化需要用到的工具和以及在实践中的Tips.也算对我这半年来部分工作的总结. 工具 Hierarchy Viewer 是 Android SDK 自带的 Layout ...
- (转)Android开发:性能最佳实践-管理应用内存
翻自:http://developer.android.com/training/articles/memory.html 在任何软件开发环境中,RAM都是宝贵的资源,但在移动操作系统中更加珍贵.尽管 ...
- Robotium之Android控件定位实践和建议(Appium/UIAutomator姊妹篇)
本人之前以前撰文描写叙述Appium和UIAutomator框架是怎样定位Android界面上的控件的. UIAutomator定位Android控件的方法实践和建议 Appium基于安卓的各种Fin ...
- Android 模块化探索与实践
首发于<程序员>杂志五月刊 一.前言 万维网发明人 Tim Berners-Lee 谈到设计原理时说过:"简单性和模块化是软件工程的基石:分布式和容错性是互联网的生命." ...
- Android Studio Git 分支实践
新公司有些项目是用的 Git,以前公司都是 svn,为了练手 Git,我个人 APP 用到了,但是仅简单的 git pull/push 的使用,并未用到 Git 精髓,只有当项目中用到,才会紧迫去全面 ...
- Robotium之Android控件定位实践和建议
本人之前曾经撰文描述Appium和UIAutomator框架是如何定位Android界面上的控件的. UIAutomator定位Android控件的方法实践和建议Appium基于安卓的各种FindEl ...
- Android MVP+Retrofit+RxJava实践小结
关于MVP.Retrofit.RxJava,之前已经分别做了分享,如果您还没有阅读过,可以猛戳: 1.Android MVP 实例 2.Android Retrofit 2.0使用 3.RxJava ...
- Android热修复AndFix
热修复主要用来修复代码.修复bug.添加独立的功能,他的原理主要是操作PathClassLoader.DexClassLoader. PathClassLoader是类加载器,DexClassLoad ...
随机推荐
- iOS常见控件的基本使用
UI相关类继承关系 UIView 常见属性和方法 UIView属性 UIView方法 UIControl 常用控件 UIImageView 图片显示控件android ImageView UISlid ...
- iOS中让Settings Bundle中的变化立即在App中反应出来的两种方法
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 为了能够在Settings Bundle中的变化在进入App后 ...
- android6.0SDK 删除HttpClient的相关类的解决方法
本文转载自博客:http://blog.csdn.net/yangqingqo/article/details/48214865 android6.0SDK中删除HttpClient的相关类的解决方法 ...
- springMVC 使用ajax 出现No serializer found for class异常
转自 http://mxdba.iteye.com/blog/668155 google了一下,发现坛子里已经有人解答了 http://godfox.iteye.com/blog/646887 不过 ...
- JavaI/O体系详解
Java中IO操作主要是指使用Java进行输入,输出操作,Java中所有的IO操作类都存放在Java.io包中,在使用时需要导入此包. 在整个Java.io包中最重要的就是5个类和一个接口.5个类指的 ...
- Redefine:Change in the Changing World
EMC World 2014的主题就是REDEFINE.的确,现在科技的发展在重新定义了技术,影响了生活,改变了你我. 对于一个有数万员工,甚至数十万员工的企业来说,Redefine无疑更加具有挑战, ...
- iOS开发之五:常用控件--UITextField的使用
UITextField 是iOS开发中用的非常多的一种控件,主要是供用户输入单行信息的.下面来详细介绍UITextField. 1.常用属性 <span style="font-siz ...
- 【一天一道LeetCode】#107. Binary Tree Level Order Traversal II
一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 来源: htt ...
- 控件之combox
一. combox显示 首先combox有两个属性来存储数据:DisplayMember(显示成员),ValueMember(值成员) ,DisplayMember是我们在combox界面上看 ...
- 调用awk的三种方式
调用awk的三种方式 调用awk有三种方式,一种为Shell命令行方式,另外两种是将awk程序写入脚本文件,然后执行该脚本文件.三种方式的命令格式归纳如下: 一.在Shell命令行输入命令调用awk, ...