Miui的多主题效果非常cool,但应该如何实现呢?有些人可能会想到使用Android系统提供的Overlay机制。但是Overlay机制能否实现多主题呢?通过调研,我的答案是:部分实现。
为何是部分实现?究竟什么是部分实现?
部分实现指的是Overlay机制可以实现framework资源的多主题替换,但是无法做到App的多主题。Overlay机制本身的目的是为OEM厂商提供一种替换原生系统资源的机制。通过阅读framework的AssetManager.cpp代码(addAssetPath)可以知道,系统在加载framework资源时,会查找是否有framework-res.apk的overlay资源,他是在/vendor/overlay/framework目录下进行查找的。这意味着只要替换/vendor/overlay/framework中的framework-res.apk就能实现framework资源的替换,当然前提需要重启系统。
但是APP资源的Overlay只能在APP编译时完成,一旦编译完成,Overlayed资源也就固定在一个APP中了。当然framework-res.apk也支持这种overlay方式。看AssetManager.cpp代码注释中提到, // add overlay packages for /system/framework; apps are handled by the (Java) package manager。A HA!也就是说android系统将应用层的资源Overlay通过PackageManager来完成。究竟PackageManager是怎么完成overlay呢?如果你搜索一下PackageManager.java的源代码会惊异的发现,它根本不包含任何"overlay"关键字。这时,突然会想到网上介绍的应用程序如何实现多主题。没错,就是通过PackageManager的getResourcesForApplication找到overlay apk的资源,使用overlay apk的资源代替自身app的资源。这就是apps are handled by the (Java) package manager的含义了。
因此,我说Overlay机制是部分支持实现多主题的。那有没有办法实现完全支持呢?既然找到了原因也就找到了思路,那就是在PackageManager添加一层重定向机制。将APP的资源请求转换为对Overlay APP的资源请求。当然以上只是一种思路,还有很多具体细节需要解决,而其中最重要的一个就是如何使主题切换立即生效?思考吧,少年。。。
补充资料:如何通过overlay机制对framework-res.apk进行替换,可以参考Android系统源码/framework/base/core/tests/overlaytests/OverlayTestOverlay项目。