- 浏览: 2204122 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (1240)
- mac/IOS (287)
- flutter (1)
- J2EE (115)
- android基础知识 (582)
- android中级知识 (55)
- android组件(Widget)开发 (18)
- android 错误 (21)
- javascript (18)
- linux (70)
- 树莓派 (18)
- gwt/gxt (1)
- 工具(IDE)/包(jar) (18)
- web前端 (17)
- java 算法 (8)
- 其它 (5)
- chrome (7)
- 数据库 (8)
- 经济/金融 (0)
- english (2)
- HTML5 (7)
- 网络安全 (14)
- 设计欣赏/设计窗 (8)
- 汇编/C (8)
- 工具类 (4)
- 游戏 (5)
- 开发频道 (5)
- Android OpenGL (1)
- 科学 (4)
- 运维 (0)
- 好东西 (6)
- 美食 (1)
最新评论
-
liangzai_cool:
请教一下,文中,shell、C、Python三种方式控制led ...
树莓派 - MAX7219 -
jiazimo:
...
Kafka源码分析-序列5 -Producer -RecordAccumulator队列分析 -
hp321:
Windows该命令是不是需要安装什么软件才可以?我试过不行( ...
ImageIO读jpg的时候出现javax.imageio.IIOException: Unsupported Image Type -
hp321:
Chenzh_758 写道其实直接用一下代码就可以解决了:JP ...
ImageIO读jpg的时候出现javax.imageio.IIOException: Unsupported Image Type -
huanghonhpeng:
大哥你真强什么都会,研究研究。。。。小弟在这里学到了很多知识。 ...
android 浏览器
引用
阿里巴巴无线事业部最近开源的Android平台下的无侵入运行期AOP框架Dexposed,该框架基于AOP思想,支持经典的AOP使用场景,可应用于日志记录,性能统计,安全控制,事务处理,异常处理等方面。
针对Android平台,Dexposed支持函数级别的在线热更新,例如对已经发布在应用市场上的宿主APK,当我们从crash统计平台上发现某个函数调用有bug,导致经常性crash,这时,可以在本地开发一个补丁APK,并发布到服务器中,宿主APK下载这个补丁APK并集成后,就可以很容易修复这个crash。
Dexposed是基于久负盛名的开源Xposed框架实现的一个Android平台上功能强大的无侵入式运行时AOP框架。Dexposed的AOP实现是完全非侵入式的,没有使用任何注解处理器,编织器或者字节码重写器
针对Android平台,Dexposed支持函数级别的在线热更新,例如对已经发布在应用市场上的宿主APK,当我们从crash统计平台上发现某个函数调用有bug,导致经常性crash,这时,可以在本地开发一个补丁APK,并发布到服务器中,宿主APK下载这个补丁APK并集成后,就可以很容易修复这个crash。
Dexposed是基于久负盛名的开源Xposed框架实现的一个Android平台上功能强大的无侵入式运行时AOP框架。Dexposed的AOP实现是完全非侵入式的,没有使用任何注解处理器,编织器或者字节码重写器
先来讲讲集成方法,从项目地址下载整个项目dexposed,将..\dexposed\sample\patchsample\app\libs目录下的两个jar拷出来备用,以及将..\dexposed\sample\dexposedexamples\app\src\main\jniLibs目录下的native库拷出来备用。
打开Android Studio,新建项目,将前面拷出来的jar拷到libs目录下,在main目录下新建jniLibs目录,将native库拷进去。最终项目结构会成这样
为了应用热更新,所以我们还要建一个module用于编写热更新的代码,用Android studio新建一个module,这里让其名叫patch,将之前的jar拷入到patch下的libs目录。而native库不需要拷。之后进行同步,点击如图图标
我们在Application中检查是否支持Dexposed,编写一个子类继承Application类,并在Manifest文件中指定该类。
/** * User:lizhangqu(513163535@qq.com) * Date:2015-08-06 * Time: 13:46 */ public class App extends Application { private boolean mIsSupported = false; private boolean mIsLDevice = false; @Override public void onCreate() { super.onCreate(); mIsSupported= DexposedBridge.canDexposed(this); mIsLDevice= Build.VERSION.SDK_INT>=21; if (mIsSupported) { //do something } public boolean isSupported(){ return mIsSupported; } public boolean isLDevice(){ return mIsLDevice; } }
我们调用了 DexposedBridge.canDexposed函数用于判断是否支持Dexposed,如果支持,我们则做下一步动作。
现在有这么一个需求,需要给每个Activity的onCreate调用前增加日志,调用完成后增加日志,调用完成后需要调用另外一个统计用的方法。同时,需要直接替换掉MainActivity中的一个叫replaceMethod的方法。我们来编写代码。
private void hook() { DexposedBridge.findAndHookMethod(Activity.class, "onCreate", Bundle.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { Log.e("TAG", "onCreate:" + param.thisObject.getClass().getSimpleName() + "start"); } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { Log.e("TAG", "onCreate:" + param.thisObject.getClass().getSimpleName() + "end"); XposedHelpers.callMethod(param.thisObject, "statics", new Class[]{long.class}, System.currentTimeMillis()); } }); DexposedBridge.findAndHookMethod(MainActivity.class, "replaceMethod", new XC_MethodReplacement() { @Override protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable { Log.e("TAG", "the method has replaced by DexposedBridge!"); return "has replaced"; } }); }
代码中调用了 XposedHelpers.callMethod进行反射调用统计方法statics。
replcaeMethod方法的原型
public String replaceMethod(){ Log.e("TAG","replaceMethod"); return "replaceMethod"; }
statics方法原型
public void statics(long a){ Log.e("TAG","==now:"+a+"=="); //do something }
然后我们调用hook函数
if (mIsSupported) { hook(); }
同时我们的MainActivity中进行了调用replaceMethod
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String result=replaceMethod(); Log.d("TAG","result:"+result); }
这时候观察一下日志输出
我们发现在onCreate方法前后都有日志输出,并且onCreate后有统计方法的调用,而replaceMethod方法的内容以及完全被替换了。
我们开到前面使用了XposedHelpers类,这个类是一个辅助类,里面全是跟反射相关的。使用了DexposedBridge.findAndHookMethod进行注入。
对于某个函数而言,有三个注入点可供选择:函数执行前注入(before),函数执行后注入(after),替换函数执行的代码段(replace),分别对应于抽象类XC_MethodHook及其子类XC_MethodReplacement中的函数:
public abstract class XC_MethodHook extends XCallback { /** * Called before the invocation of the method. * <p>Can use {@link MethodHookParam#setResult(Object)} and {@link MethodHookParam#setThrowable(Throwable)} * to prevent the original method from being called. */ protected void beforeHookedMethod(MethodHookParam param) throws Throwable {} /** * Called after the invocation of the method. * <p>Can use {@link MethodHookParam#setResult(Object)} and {@link MethodHookParam#setThrowable(Throwable)} * to modify the return value of the original method. */ protected void afterHookedMethod(MethodHookParam param) throws Throwable {} }
public abstract class XC_MethodReplacement extends XC_MethodHook { @Override protected final void beforeHookedMethod(MethodHookParam param) throws Throwable { try { Object result = replaceHookedMethod(param); param.setResult(result); } catch (Throwable t) { param.setThrowable(t); } } protected final void afterHookedMethod(MethodHookParam param) throws Throwable { } /** * Shortcut for replacing a method completely. Whatever is returned/thrown here is taken * instead of the result of the original method (which will not be called). */ protected abstract Object replaceHookedMethod(MethodHookParam param) throws Throwable; }
可以看到这三个注入回调函数都有一个类型为MethodHookParam的参数,这个参数包含了一些很有用的信息:
- MethodHookParam.thisObject:这个类的一个实例
- MethodHookParam.args:用于传递被注入函数的所有参数
- MethodHookParam.setResult:用于修改原函数调用的结果,如果在beforeHookedMethod回调函数中调用setResult,可以阻止对原函数的调用。但是如果有返回值的话仍然需要通过hook处理器进行return操作。
下面我们来应用一下在线热更新
在线热更新一般用于修复线上严重的,紧急的或者安全性的bug,这里会涉及到两个apk文件,一个我们称为宿主apk,也就是发布到应用市场的apk,一个称为补丁apk。宿主apk出现bug时,通过在线下载的方式从服务器下载到补丁apk,使用补丁apk中的函数替换原来的函数,从而实现在线修复bug的功能。
为了实现这个功能,需要再引入一个名为patchloader的jar包,我们已将将它拷到libs目录下,这个函数库实现了一个热更新框架,宿主apk在发布时会将这个jar包一起打包进apk中,而补丁apk只是在编译时需要这个jar包,但打包成apk时不包含这个jar包,以免补丁apk集成到宿主apk中时发生冲突。因此,补丁apk将会以provided的形式依赖dexposedbridge.jar和patchloader.jar,补丁apk也就是patch的build.gradle文件中依赖部分脚本如下所示:
dependencies { provided fileTree(dir: 'libs', include: ['*.jar']) }
现在假设我们MainActivity中有一个初始化数据的方法
public List<String> initData() { return null; }
但是我们手误返回了null,但是在MainActivity中调用了这个返回值的内容
public void showTextView(){ tv.setText(initData().get(0) + ""); }
于是就产生了常见的异常,即空指针异常。我们使用patch来修复这个bug。我们需要实现IPatch接口
public class TestPatch implements IPatch { @Override public void handlePatch(PatchParam patchParam) throws Throwable { Log.e("TAG","handlePatch"); Class<?> cls = null; try { cls= patchParam.context.getClassLoader() .loadClass("zafu.edu.cn.dexposed.MainActivity"); } catch (ClassNotFoundException e) { e.printStackTrace(); return; } DexposedBridge.findAndHookMethod(cls, "initData", new XC_MethodReplacement() { @Override protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { List<String> list=new ArrayList<String>(); list.add("1111111111"); list.add("2222222222"); list.add("3333333333"); list.add("4444444444"); //param.setResult(list); return list; } }); } }
我们的补丁程序返回了几个数据,完成后我们生成module为patch的apk。然后将该apk拷到对应的目录下,这里简单的将其拷到Android/data/your package/cache/pacth.apk目录下。然后我们要应用该补丁
public void runPatchApk(){ if (isLDevice()){ Log.e("TAG","it does not support L"); return; } if (!isSupported()){ Log.e("TAG","It does not support!"); return ; } File cacheDir = getExternalCacheDir(); if(cacheDir != null){ String fullpath = cacheDir.getAbsolutePath() + File.separator + "patch.apk"; Log.e("PATH",fullpath); PatchResult result = PatchMain.load(this, fullpath, null); if (result.isSuccess()) { Log.e("Hotpatch", "patch success!"); } else { Log.e("Hotpatch", "patch error is " + result.getErrorInfo()); } } }
if (mIsSupported) { hook(); runPatchApk(); }
之后你会发现不再报空指针了。
对于热更新,我们可以在手机淘宝中找到它的影子。如下图
总之,该库前途无量,但是目前支持的系统有限,也希望它能不断发展,造福开发者。
源码下载
http://download.csdn.net/detail/waterseason/9288437
发表评论
-
jni未释放资源问题。Failed adding to JNI local ref table (has 512 entries)
2016-02-01 14:51 983Native Code 本身的内存泄漏 JNI 编程首先是一 ... -
android ApkPlug使用
2015-12-09 15:14 734直接下载附件吧, 有两个是官方的demo包,还有一个是他们技术 ... -
dynamic-load-apk-Apk动态加载框架使用初体验
2015-12-03 10:40 799因为想要将本网站上的开源代码直接做成一个能显示效果的app,决 ... -
Android动态加载进阶 代理Activity模式
2015-11-30 17:20 885技术背景 简单模式中 ... -
Android NDK rb5 文档之本地活动和应用程序
2015-11-24 22:34 816Native Activities and Applicati ... -
Android NDK rb5 文档之 native_activity.h 文件翻译
2015-11-24 22:30 1010/** * Copyright (C) 2010 The A ... -
Android NDK开发之JNI基础知识
2015-11-21 13:05 1128JAVA层与JNI层数据类型的对应 下面是一个测试方法 pu ... -
ANDROID2.2 JNI 配置luajit2
2015-11-21 11:18 744去http://luajit.org/官网下载最新的版本 在 ... -
在Android平台上加载本地库的危险性[转]
2015-11-13 09:30 1588在2012年KeepSafe的创业初期,我们试图找到一种为An ... -
JNI: 能否用 GetFieldID()/GetStaticFieldID()取得enum变量的属性?
2015-11-06 11:52 1846没有问题的,jni下面一样可以动态获取的 仅供参考! VOI ... -
ndk-stack定位不出崩溃代码行的问题
2015-10-30 08:51 1250NDK开发包中自带的NDK-STACK工具是可以查看崩溃栈信息 ... -
Android.mk文件详解
2015-10-27 09:23 1843Android.mk是Android提供的 ... -
NDK在增加断点时跳不进去,不管用的解决办法
2015-10-26 10:09 1106先看下面的错,如果报的不是这个那就不是我这个问题,那就不用再看 ... -
插件化的基石 -- apk动态加载
2015-09-25 09:13 971Android动态加载技术在蘑菇街的第一次实践,还是在14年的 ... -
warning:deprecated conversion from string constant to 'char *' 解决方案
2015-09-25 09:01 1857char* createClass(){ ret ... -
jni内存释放
2015-09-24 12:03 3677调用GetStringUTFChars,GetDoubleAr ... -
如何不要让ndk-build自动删除.so
2015-08-04 15:33 1175在用ndk-build的时候突然发现在编译完成之后会自动删除a ... -
超简单的NDK单步调试方法
2015-08-03 21:19 603最近为了性能需求,开始搞JNI,白手起搞真心不容易。中间差点崩 ... -
JNI调用java中的类方法和静态方法
2015-08-03 16:46 2758在JNI调用中,肯定会涉及到本地方法操作Java类中数据和方法 ... -
[转]Android JNI层实现文件的read、write与seek操作
2015-08-03 14:41 12551、 在Andr ...
相关推荐
该框架基于AOP思想,支持...Dexposed是基于久负盛名的开源Xposed框架实现的一个Android平台上功能强大的无侵入式运行时AOP框架。Dexposed的AOP实现是完全非侵入式的,没有使用任何注解处理器,编织器或者字节码重写器。
**JVM-SANDBOX:基于JVM的实时无侵入AOP框架容器** JVM-SANDBOX是一个强大的工具,它允许开发者在Java虚拟机(JVM)上实现无侵入的面向切面编程(AOP)框架,提供实时监控和干预应用程序的能力。这个框架的核心在于...
本文将深入探讨如何利用AOP在Android项目中实现无侵入式的工具,以提升开发效率。 首先,我们需要理解什么是AOP。AOP是一种编程思想,它允许我们把关注点分离到各个不同的“切面”中,这些切面通常包括日志记录、...
本资料主要探讨的是阿里巴巴的Web框架及其设计理念,旨在帮助开发者更好地理解和运用这些技术。 "阿里巴巴Web及框架简介"这一主题,核心在于介绍阿里巴巴开发的Web框架,如Webx,以及相关框架的应用和特性。Webx是...
Android-Jet-AOP便是一个专为Android平台设计的AOP框架,它借助注解和AspectJ技术,使得在Android应用中实现AOP变得简单易行。 ### 一、面向切面编程(AOP) AOP的核心理念是将程序中的关注点分离,关注点可以理解...
3. **Android Annotation库**:像Dagger、Butter Knife等流行的Android库也采用了注解处理技术,它们虽然不是纯AOP框架,但可以实现类似的功能,例如依赖注入。通过在类或方法上添加注解,这些库能在编译时生成辅助...
AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,旨在提高软件的模块化程度,通过将关注点分离,使代码更易于维护和扩展。在C#中,实现AOP可以帮助开发者处理如日志记录、事务管理、性能度量等横...
7. **微型框架**:与大型、功能丰富的AOP框架(如Spring.NET或Unity)相比,微型框架通常更轻量级,专注于核心的AOP功能,适合小型项目或作为学习AOP原理的起点。 8. **EnterpriseServerBase.Aop**:这可能是框架的...
在IT领域,Spring框架是Java开发中的一个基石,尤其在企业级应用开发中扮演着重要角色。Spring的主要功能包括依赖注入(IoC)和面向切面编程(AOP)。本教程将带你深入理解这两个概念,并通过手写一个简易的IoC和AOP...
"Spring AOP 框架实现的结构分析" 本文主要目标是从实现的角度来认识 SpringAOP 框架。首先,我们需要了解 AOP 的基本概念,包括关注点、核心关注点、横切关注点、方面、连接点、切入点、增强、引介、混入继承和织...
本篇文章将深入探讨仿Spring AOP框架,通过实例讲解自定义注解、切面和通知等关键概念,为学习AOP的学员提供详尽的参考资料。 首先,让我们了解**自定义注解**在AOP中的作用。自定义注解可以作为元数据,标记在方法...
嵩山版是该手册的一个更新版本,反映了最新的技术趋势和阿里巴巴内部的实践经验。 一、编程基础 1. 类与对象:强调面向对象的设计原则,如单一职责、开闭原则、里氏替换、依赖倒置等,以及如何合理设计类和接口。 2...
1. Dexposed:面向 Android 应用开发的一个强大的非侵入式的运行时 AOP 框架,支撑了阿里大部分 App 的在线分钟级客户端 bugfix 和线上调试能力。 五、数据访问框架 1. TDDL:淘宝根据自己的业务特点开发了框架,...
这个名为“GreeFramOfficial”的压缩包文件,很可能是提供了一个基于C#实现的IOC和AOP框架,供开发者学习和使用。 IOC(Inversion of Control)的核心思想是将对象的创建和管理交给一个容器来处理,而不是由对象...
《阿里巴巴Java开发手册》是Java开发者的一份重要参考资料,它由阿里巴巴集团的众多技术专家共同编写,旨在规范Java编程实践,提升代码质量和团队协作效率。手册分为纪念版和详尽版,两者各有侧重点,为不同阶段的...
面向方面编程(AOP,Aspect-Oriented Programming)是一种编程范式,旨在通过将关注点分离,提升代码的模块化程度和可维护性。在传统的面向对象编程(OOP)中,关注点往往混杂在一起,例如日志、事务管理等横切关注...
通过这样的简易AOP框架,开发者可以学习到AOP的基本思想和实现方式,了解如何在不修改原始代码的情况下,添加跨切面的关注点,提高代码的可维护性和复用性。同时,这也是一种实践面向切面编程理念的有益尝试,有助于...
《阿里巴巴Java开发手册》是阿里巴巴集团为Java开发者制定的一份权威技术规范,旨在提升团队协作效率,保证代码质量,减少项目风险。嵩山版作为其更新版本,包含了最新的最佳实践和编程规范,覆盖了基础设定、编程...
总之,"基于Bytebuddy的Java Agent AOP框架"项目为我们提供了一个探索动态类型生成和AOP技术的实践平台。通过学习和实践,我们可以掌握如何使用ByteBuddy来创建高效、灵活的代理类,以及如何利用Java Agent实现字节...