当然,你可以去学习如何创建一个Xposed模块。所以你可以阅读这篇教程(官方教程)去学习怎样解决这个问题。这不仅仅讲解如何新建模块、如何编写模块,我们要往更深处思考,为什么按照这些步骤,为什么要新建这个类。如果你是“TL博士”那样的人,那么可以直接阅读"Making the project an Xposed module" 这一章节。如果你想看完整个教程那么你需要很好的理解能力。你将会花费时间去阅读这篇文章,因为你不能但靠自己解决任何的问题。
here)。综观类XposedBridge,你可以看到的main 方法。这就是我上面写的,这个类会在进程启动之前被调用。在那时候执行一些初始化和模块的加载(我会在后面讲解模块的加载)。
这里下载XposedBridgeApi-.jar 。把它复制到子文件夹名为lib目录下。然后在其上单击右键,选择Build Path => Add to Build Path 。你需要将版本名插入到xposedminversion的声明清单中。转自
可以选择库引用的方式。但是确保你的API类被正确地编译到APK文件中 ,否则你会得到一个IllegalAccessError 。通过引用libs 文件(有“s”),通过Eclipse的简单设置可以不用把XposedBridgeApi-.jar 包含进去。
here )并且浏览他。但这官方ROM可能与你的不一样,但在这种情况下,它是一个类似甚至相同的实现。第一,我想看看AOSP,看看是否是一样的。如果我需要更多的细节,看看实际的反编译代码。
你可以寻找与“时钟”类名称或包含该字符串的类。下一步就是,寻找他所使用的资源和布局。如果您下载了官方AOSP的代码,就可以开始在这里开始寻找:frameworks/base/packages/SystemUI 。你会发现不少地方出现“时钟”。这是正常的,的确会有不同的方式来实现修改。请记住,你仅仅可以hook方法 。所以,你必须要找到一个可以在他之前、之后、或全部替换可以插入一些代码的地方。你应该hook 住尽可能具体的方法,而不是那些会被调用上千次的方法,去避免性能问题和意想不到的副作用。
在这种情况下,您可能会发现这个layout布局res/layout/status_bar.xml 包含了一个自定义视图类:com.android.systemui.statusbar.policy.Clock。多个想法可能会现在你的头脑中。文字颜色的定义是通过textAppearance属性,所以最简单的方法就是改变它,将会改变外观的定义 。然而,这可能有效也可能无效(因为它可能存在于更深的native 代码中)。更换布局状态栏将是可能的,但是你们只可以做最小的变化去更改他,相反,看看这个类。有一个叫updateClock方法,它看上去会被每分钟调用去更新时间
看起来完美的修改,因为它是这似乎是唯一设置文本时钟的非常具体的方法。假如我们改变了这个clock的颜色或者字体,那么任何调用这个方法的都会受此影响。就达成我们的需求了,我们立刻行动.
(单独的文本颜色,这里有一种更好的方式.看到“修改布局”的例子在 "Replacing resources".)
helper 类的一个方法。请注意,它是静态导入的,如果你配置了它描述的链接页面就会自动添加 。此方法通过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是一个经验上的问题,所以开始的东西比较容易。尝试刚开始就多使用日志功能去确保被调用的是预期的事件。现在:玩得开心!