Xpoded模块开发教程
模块开发教程
Xpoded模块
当然,你可以去学习如何创建⼀个Xposed模块。所以你可以阅读这篇教程(官⽅教程)去学习怎样解决这个问题。这不仅仅讲解如何新建模块、如何编写模块,我们要往更深处思考,为什么按照这些步骤,为什么要新建这个类。如果你是“TL博⼠”那样的⼈,那么可以直接阅读"" 这⼀章节。如果你想看完整个教程那么你需要很好的理解能⼒。你将会花费时间去阅读这篇⽂章,因为你不能但靠⾃⼰解决任何的问题。
⼀、修正通告
你可以在Github中到重新创建红⾊时钟的例⼦,它包括状态栏时钟的颜⾊改为红⾊和添加⼀个笑脸,我选择这个例⼦,因为它是⼀个相当⼩,但很容易看到变化。此外,它使⽤了⼀些由框架提供的基本⽅法。
⼆、Xposed是如何⼯作的
在你修改之前,你应该思考⼀下Xposed是如何⼯作的(如果你觉得太⽆聊可以跳过这⼀节)。⽅法如下:
有个进程叫做“Zygote ”。这是Android运⾏环境的的核⼼。每⼀个应⽤程序启动都是通过它fork出来的。当⼿机被启动就会执⾏/这个脚本,这个进程会启动/system/bin/app_process ,然后他会调加载所需的类并调⽤初始化函数。
现在说说Xposed什么时候开始启动。当您安装了Xposed,它会把修改的app_process可执⾏⽂件复制到/system/bin中。这个修改过的启动进程增加了⼀个额外的jar包到classpath路径,并在某些地⽅调⽤那⾥的⽅法。例如,在虚拟机刚刚创建后,在Zygote 的main⽅法调⽤后。我们的jar包也可以Zygote⾥⾯⼯作。
这个jar包位于:/data/bv.android.xposed.installer/bin/XposedBridge.jar和它的源代码可以在这⾥到()。综观
类XposedBridge,你可以看到的main ⽅法。这就是我上⾯写的,这个类会在进程启动之前被调⽤。在那时候执⾏⼀些初始化和模块的加载(我会在后⾯讲解模块的加载)。
三、Method hooking/replacing
Xposed真正的能⼒在于可以hook函数的调⽤。当您修改完反编译后的APK,你可以直接插⼊命令或者修改命令。但是您将需要重新编译/签名APK,并且重新安装这个安装包。你可以⽤Xposed的hooks,你不⽤修改内部函数的任何代码(这⽆法清晰地定义什么叫“没有修改”这个词语)。相反,你可以注⼊java⾥最⼩的单元(每⼀句代码)到函数的前⾯和后⾯,这可以清晰地解决问题。
XposedBridge有⼀个私有的本地⽅法叫hookMethodNative。此⽅法同样的会在扩展的app_process进程中应⽤。它会将⽅法类型改变
为“native ”并且将这⽅法的实现替换为它⾃⼰本地的泛型⽅法。这意味着任何时候调⽤这个被hook的⽅法,⽅法调⽤者并不知道已经
被native ⽅法给代替了java层的⽅法。在该⽅法中,在XposedBridge的⽅法handleHookedMethod会被调⽤,⽤来传递需要的参数和⾃⾝的引⽤。并且这个⽅法负责调⽤给这个函数注册过的回调⽅法。他可以改变传进来的参数,可以更改实例变量和静态变量、可以调⽤其他⽅法、处理⼀下返回值,或者跳过任何你想跳过的代码。这是⾮常灵活的。
好了,理论讲解完了。现在,让我们创建⼀个模块!
四、创建项⽬
模块是正常的应⽤程序,只需⽤⼀些特殊的元数据和⽂件。因此,⾸先创建⼀个新的Android项⽬。我假设你之前已经做到了这⼀点。如果不是,官⽅⽂档⾮常详细。当被问及对于SDK中,我选择了4.0.3(API15)。我建议你试试这个,因为已经做过测试了。你不需要创建⼀
个activity ,因为修改没有任何⽤户界⾯。回答完这个问题之后,你应该有⼀个空⽩的项⽬。
五、Making the project an Xposed module
现在我们开始讲解如何加载Xposed 模块。需要按以下⼏个步骤来进⾏的。
1.l
Xposed Installer根据模块列表查模块程序的详细信息是通过meta-data这个标签的。您可以这样创建
它:l => Application => Application Nodes (在底部) => Add => Meta Data。这个名字应该是xposedmodule和值为true。让资源为空。然后重复相同的操作填写xposedminversion(见下⽂)和xposeddescription(你的模块的⼀个⾮常简短的描述)。 XML源代码现在看起来像这样:
2.XposedBridgeApi.jar
接下来,让项⽬认识XposedBridge API 。你可以从下载XposedBridgeApi-<version>.jar 。把它复制到
⼦⽂件夹名为lib⽬录下。然后在其上单击右键,选择Build Path => Add to Build Path 。你需要将版本名插⼊到xposedminversion的声明清单中。
可以选择库引⽤的⽅式。但是确保你的API类被正确地编译到APK⽂件中,否则你会得到⼀个IllegalAccessError 。通过引⽤libs ⽂
件(有“s”),通过Eclipse的简单设置可以不⽤把XposedBridgeApi-<version>.jar 包含进去。
3.模块的实现
现在,您可以创建⼀个类的模块。我的被命名为“Tutorial ”,并在包de.robv.ds.tutorial⾥⾯:
⽤于第⼀步骤中,我们将只做⼀些记录以显⽰被加载的模块。⼀个模块可以有⼏个⼊⼝点。选择哪⼀个取决于您要修改的内容。您可以
在Android系统启动时、当⼀个app将要被加载时、⼀个app的资源将要被初始化时,通过Xposed调⽤你模块中的⼀个函数。
本教程往下⼀点,您将学习必要的更改需要在⼀个特定的应⽤程序中完成,所以让我们⼀起去看看“当⼀个新的应⽤程序被载⼊的时候”的⼊⼝点。所有⼊⼝点都标有IXposedMod的⼦接⼝。在这种情况下,你需要实现IXposedHookLoadPackage这个函数。它实际上只是⼀个⽅法加上⼀个参数,它提供了有关环境的实现模块的更多信息。在我们的例⼦中,我们记录的加载应⽤程序的名称:
这个log⽅法将⽇志输出到标准logcat窗⼝中和/data/bv.android.xposed.installer/log/debug.log⽂件中。(通过它很容易了
解Xposed Installer )
4.assets/xposed_init
android学习教程现在需要关⼼的事情是仍然丢失了XposedBridge 的⼀些类包含的⼊⼝点的追踪。这是通过⼀个名为xposed_init的⽂件,在assets ⽂件夹中⽤它的名字创建⼀个新的⽂本⽂件。在这个⽂件中,每⼀⾏包含⼀个完全限定的类名,就像这样,这⾥的
是:de.robv.ds.tutorial.Tutorial
六、Trying it out
保存⽂件。然后运⾏你的项⽬为Android应⽤程序。因为这是你第⼀次安装它,在使⽤它之前您需要启⽤它。打开Xposed安装的应⽤程序,并确保你已经安装了框架。然后去了“模块”选项卡。你应该到你的应⽤程序在⾥⾯。选中该复选框来启⽤它。然后重新启动。你不会看到有任何的变化,但如果你检查⽇志,你应该看到的东西是这样的:
瞧!它这⼯作了。现在你有⼀个Xposed模块。它仅仅只有写log的作⽤。。。
七、探索你的⽬标,到⼀个⽅法来修改它
好了,现在开始这⼀话题,可以是⾮常不同,这取决于你想要做什么。如果你以前有修改过的APK,你可能知道我在说什么。在⼀般情况下,你⾸先需要获得有关⽬标的实现的⼀些细节。在本教程中,⽬标是在状态栏的那个时钟。它有助于知道状态栏和⼀部分SystemUI的细节。因此,让我们开始搜索。
可能性之⼀:反编译。这将给你准确的实现,但是它是难以阅读和理解的,因为你得到smali格式的代码。可能性⼆:获取AOSP源()并且浏览他。但这官⽅ROM可能与你的不⼀样,但在这种情况下,它是⼀个类似甚⾄相同的实现。第⼀,我想看看AOSP,看看是否是⼀样的。如果我需要更多的细节,看看实际的反编译代码。
你可以寻与“时钟”类名称或包含该字符串的类。下⼀步就是,寻他所使⽤的资源和布局。如果您下载了官⽅AOSP的代码,就可以开始在这⾥开始寻:frameworks/base/packages/SystemUI 。你会发现不少地⽅出现“时钟”。这是正常的,的确会有不同的⽅式来实现修改。请记住,你仅仅可以hook⽅法。所以,你必须要到⼀个可以在他之前、之后、或全部替换可以插⼊⼀些代码的地⽅。你应该hook 住尽可能具体的⽅法,⽽不是那些会被调⽤上千次的⽅法,去避免性能问题和意想不到的副作⽤。
在这种情况下,您可能会发现这个layout布局res/layout/l 包含了⼀个⾃定义视图
类:com.android.systemui.statusbar.policy.Clock。多个想法可能会现在你的头脑中。⽂字颜⾊的定义是通过textAppearance属性,所以最简单的⽅法就是改变它,将会改变外观的定义。然⽽,这可能有效也可能⽆效(因为它可能存在于更深的native 代码中)。更换布局状态栏将是可能的,但是你们只可以做最⼩的变化去更改他,相反,看看这个类。有⼀个叫updateClock⽅法,它看上去会被每分钟调⽤去更新时间
看起来完美的修改,因为它是这似乎是唯⼀设置⽂本时钟的⾮常具体的⽅法。假如我们改变了这个clock的颜⾊或者字体,那么任何调⽤这个⽅法的都会受此影响。就达成我们的需求了,我们⽴刻⾏动.
(单独的⽂本颜⾊,这⾥有⼀种更好的⽅式.看到“修改布局”的例⼦在 "".)
⼋、使⽤反射来查和hook⼀个⽅法
什么是我们已经知道的?我们到⼀个⽅法:updateClock 在com.android.systemui.statusbar.policy.C
lock,我们要拦截它。我们发现这个类是在SystemUI sources ⾥⾯,所以它只能对SystemUI的进程有效。修改⼀些其他的归属于框架的类是会任何地⽅都有效的。如果我们试图获得任何信息和直接引⽤此类在handleLoadPackage ⽅法中,这会失败的,因为它们在不同的进程中。所以,当⼀个指定的包将被加载时,让我们来实现⼀个执⾏特定代码的条件。
使⽤参数,我们可以很容易地检查,我们是否选中正确的包。⼀旦我们证实,我们可以从包中获得这个类通过也是从这个变量引⽤的类加载器。现在我们来看看在com.android.systemui.statusbar.policy.Clock类及其updateClock⽅法,可以告诉XposedBridge把它hook了:
findAndHookMethod是类的⼀个⽅法。请注意,它是静态导⼊的,如果你配置了它描述的链接页⾯就会⾃动添加。此⽅法通
过ClassLoader 在ClassLoader 包中查Clock类。然后,它会在⾥⾯寻updateClock⽅法。如果这种⽅法有任何参数,那你就必须列出这些参数的类型。不同的情况不⼀样的处理,但我们的⽅法没有任何参数,可以跳过这个假设。作为最后⼀个参数,你需要提
供XC_MethodHook类的实现。对于较⼩的改动,就可以使⽤⼀个匿名类。如果你有太多的代码,最好
创建⼀个普通的类,只在这⾥创建实例。随后,helper 将尽⼀切⽅法hook住以上的函数。
你可以重写XC_MethodHook的两个⽅法。您可以同时覆盖,甚⾄不做操作,但后者是完全没有意义的。这两个⽅法
是beforeHookedMethod和afterHookedMethod。这不是太难猜测,这两个⽅法会在原始的⽅法的之前和之后执⾏。您可以使
⽤beforeHookedMethod ⽅法来评价/篡改⽅法调⽤的参数(通过param.args) ,甚⾄阻⽌调⽤原来的⽅法(发送⾃⼰的结
果)。afterHookedMethod ⽅法可以⽤来做基于原始⽅法的结果的事情。您还可以⽤它来操纵结果。当然,你可以添加⾃⼰的代码,它将会准确地在原始⽅法的前或后执⾏。
(如果你想完全取代⽅法,看看⼦类XC_MethodReplacement相反,你只需要覆盖replaceHookedMethod )
XposedBridge保留着⼀个记录了每个已经hook了的函数的注册回调函数的列表。那些具有最⾼优先级(如hookMethod定义)会⾸先调⽤。原始⽅法始终是优先级最低的。所以,假如你hook了⼀个函数并注册了回调A(PRIO⾼点)和B(PRIO默认值),那么每当hook的⽅法被调⽤,控制流将是这样的:
A.before - > B.before - >原始的⽅法 - > B.after - > A.after。因此,A修改了的参数,B是可以看到的,这样可以在传递给原始⽅法之前多步地改变它。原⽅法的结果⾸先会被B处理,但是这个原始⽅法最终返回的结果是由A来决定的。
九、最后⼀个步骤:执⾏⾃⼰的代码在⽅法调⽤之前/之后
好了,你现在有⼀个每次updateClock 调⽤时,都会被调⽤的⽅法,⽽且可以精确到原始⽅法的前后(你已经在SystemUI 的进程⾥⾯了)。现在,让我们来修改⼀些东西。
⾸先要检查:我们有没有得到具体的时钟对象?是的,我们有,它在param.thisObject参数⾥。因此,如果该⽅法
被myClock.updateClock()调⽤,然后param.thisObject将会使myClock这个对象。
下⼀步:我们可以做什么⽤的时钟?这个Clock 类是不可以利⽤的,你可以不转换param.thisObject变成类(甚⾄不要去尝试)。然⽽,它继承⾃TextView的。所以,你可以使⽤像的setText,gettext和setTextColor的⽅法,⼀旦你已经把Clock引⽤映射成TextView。这些改变应该在原始⽅法调⽤后去设置新的时间。由于在⽅法调⽤前没有事做,我们就不考虑 beforeHookedMethod。调⽤ (empty) "super" ⽅法是没有必要的。所以不要重写这⽅法。
这是完整的源代码:
⼗、对结果满意
现在安装/重新启动您的应⽤程序。正如你在运⾏之前已经在XposedInstaller 启⽤了它,你就不需要再来⼀次了,重新启动就⾜够了。不过,如果你想使⽤它停⽤这个红⾊时钟的例⼦。两者都使⽤缺省的优先级给他们的updateClock处理程序,那么你不知道哪⼀个会胜出(它实际上取决于处理⽅法的字符串表⽰形式,但并不依赖于此)。
⼗⼀、结论
我知道,这个教程很长。但我希望你现在不仅可以实现⼀个绿⾊的时钟,还可以实现和这个完全不同的东西。到好的⽅法来hook是⼀个经
验上的问题,所以开始的东西⽐较容易。尝试刚开始就多使⽤⽇志功能去确保被调⽤的是预期的事件。现在:玩得开⼼!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论