Anroid 9.0 主题实现方案--Runtime Resource Overlay
简单资源替换生效流程可以进行以下几步:
预制方式:
- 生成overlay apk;
- 将overlay apk push 到vendor/overlay目录下;
- 重启手机;
- 主题切换
- 此时若目标应用正在显示,Activity 会重新走生命周期,显示新的资源信息。
安装方式
- 生成overlay apk;
- 安装apk
- 重启手机;
- 主题切换
- 此时若目标应用正在显示,Activity 会重新走生命周期,显示新的资源信息。
生成overlay apk(Android studio)
假如手机预制 默认和theme1, theme2 3个主题
制作theme1主题流程如下
a. AS内新建项目,仅保留AndroidManifest.xml 和res目录下要替换的资源文件。
b. 用系统签名对overlay app 进行签名,保持签名一致。
以空调为例,车机空调包名为com.android.car.hvac,demo overlay app包名为com.abc.theme1.hvac(theme1主题 overlay apk 包名必须满足带”theme1“, 同理theme2主题overlay apk 包名必须带“theme2” )
代码结构图
AndroidManifest.xml
仅包含以下信息即可,其中targetPackage为要替换资源的app包名
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.abc.theme1.hvac">
<overlay
android:priority="9"
android:targetPackage="com.android.car.hvac" />
</manifest>
res目录下仅保留需要替换的资源信息(values下的colors.xml , strings.xml , dimens.xml themes.xml等 和 drawables/xml目录下的资源, 不支持替换布局文件)
如colors.xml 中
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="hvac_icon_color">#00F5F5</color>
<color name="hvac_background_color">#17ff26</color>
<color name="hvac_fanspeed_bg_color">#ff1C21</color>
</resources>
常用adb命令
- 命令可以查看系统里面的overlay包以及包的状态。:
adb shell dumpsys overlay
- 设置每个资源包的状态,设置成enable就会立即生效,(具体命令可以到代码里面查到shellcommand)
adb exec-out cmd overlay enable com.abc.theme1.hvac
主要控制实现代码逻辑
控制模块Androidmanifest.xml 需要权限
<!-- Allows an app to set the theme overlay in /vendor/overlay
being used.
@hide <p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.MODIFY_THEME_OVERLAY"
android:protectionLevel="signature" />
//获取每个主题的overlay 包名列表
private Map<String, List<OverlayInfo>> mOverlayInfoMap;
private List<String> mTheme1List = new ArrayList<String>(); //theme1 overlay pkgName list
private List<String> mTheme2List = new ArrayList<String>(); //theme2 overlay pkgName list
public void getOverlayList() {
IOverlayManager mOverlayManager = IOverlayManager.Stub.asInterface(ServiceManager.getService("overlay"));
mTheme1List.clear();
mTheme2List.clear();
try {
mOverlayInfoMap = mOverlayManager.getAllOverlays(0);
for (List<OverlayInfo> overlayInfos : mOverlayInfoMap.values()) {
for(int j = 0; j < overlayInfos.size(); j++) {
String overlayPackageName = overlayInfos.get(j).packageName;
if(overlayPackageName.contains("theme1")) {
mTheme1List.add(overlayPackageName);
} else if(overlayPackageName.contains("theme2")) {
mTheme2List.add(overlayPackageName);
}
}
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
//设置应用选择哪一个主题
IOverlayManager mOverlayManager = IOverlayManager.Stub.asInterface(ServiceManager.getService("overlay"));
//setEnabledExclusive: enable 只有为true时才会起作用,
//会启用参数中的overlayPackage,禁用其他overlay package
mOverlayManager.setEnabledExclusive(overlayPackage, enable, userId);
//setEnabled: 针对参数中的overlayPackage 进行设置
mOverlayManager.setEnabled(overlayPackage, enable, userId);
设置时序图
备注
- 可以替换values下的colors.xml , strings.xml , dimens.xml themes.xml等 和 drawables/xml目录下的资源, 不支持替换布局文件
- 2s内完成替换
- 替换过程中添加窗口覆盖之前页面,以保证之前页面重新绘制屏幕不闪烁,当前demo 用窗口为只包含图片的View
- 预制主题apk 需放在目录 vendor/overlay下
- 主题生效逻辑为Activity 会重新启动,因此应用需关注后台应用Activity重新启动后相关信息是否和切换前相同(输入框信息默认仍然存在), 同时需要监听setting 数据库的变化更新虚浮窗口 等非Activity ;
- 待替换app 使用资源 路径位于 frameworks/support/car/ 的资源尚不支持替换 ==>使用frameworks/base/core/res下的资源或者应用本身内置资源