android overlay机制实践

前言

最近在做launcher时有一个需求是通过overlay机制实现替换主题,中间遇到了不少问题,这里记录一下自己以后能用到,也希望能帮助有需要的同学。我使用的是android11系统,参考官方文档

https://source.android.google.cn/devices/architecture/rros?hl=zh-cn

概述

android overlay是一种资源的动态替换机制,它的工作原理是将叠加层软件包中定义的资源映射到目标软件包中定义的资源。当应用尝试解析目标软件包中资源的值时,系统转而会返回目标资源映射到的叠加层资源的值。它也分为静态的(SRO , Static Resource Overlay)和动态的(RRO , Runtime Resource Overlay)两种,静态的需要在源码编译阶段完成,比如SystemUI等系统应用,而RRO是通过安装Overlay的apk应用实现替换的。

创建overlay应用

首先我创建一个普通的应用用来进行测试,包名是com.ts.overtest,主界面就两个按钮切换主题,这里切换的其实就是页面的背景色color/background,定义在color.xml中, 期望替换这个颜色值实现主题的替换。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@color/background"
    tools:context=".MainActivity">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/button1"
        android:text="切换红色主题"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/button2"
        android:text="切换绿色主题"/>


</LinearLayout>

还要申请权限

    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"
        tools:ignore="ProtectedPermissions" />
    <uses-permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES"
        tools:ignore="ProtectedPermissions" />

接下来创建两个module作为Overlay,为了方便区分,我这里创建的两个module包名分别为com.ts.overtest.overlaygreen和com.ts.overtest.overlayred,下面以红色主题为例。首先是AndroidManifest.xml文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:sharedUserId="android.uid.system"
    package="com.ts.overtest.overlaygreen">

    <overlay android:targetPackage="com.ts.overtest" android:priority="2" android:isStatic="true"/>
    <application
        android:hasCode="false"/>

</manifest>

这里面最重要的是overlay标签,下面说明一下它的各个属性

  • targetPackage 要替换的应用的包名
  • priority 优先级,优先级越高的默认先使用
  • isStatic 表示该overlay应用默认处于active状态,如果我们使用的是SRO,将该Overlay应用的apk push到/vendor/overlay目录下后重启,该主题就默认生效了。

接下来是application标签,由于我们只是进行资源的替换,所以应用中没有代码,hasCode 表示我们的应用中没有代码。

下面是我的build.grade文件,没有什么特别注意的,只是minSdk需要改到26以上,由于没有代码,dependencies也不需要了。

plugins {
    id 'com.android.application'
}

android {
    compileSdk 32

    signingConfigs {
        debug {
            storeFile file('/home/yxd0000/AndroidStudioProjects/系统应用签名/原生android11签名/platform.keystore')
            storePassword 'android'
            keyAlias 'platform'
            keyPassword 'android'
        }
    }

    defaultConfig {
        applicationId "com.ts.overtest.overlayred"
        minSdk 26
        targetSdk 32
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

还需要该一下color中background这个值,将其改为红色。

SRO

编译上面的Overlay应用生成apk文件,将其push到/system/vendor/overlay目录下,但是一般的模拟器都是只读的,所以一般都不能push,需要先root和remount这就需要我们有源码或者开发版的模拟器了。

重启模拟器就会发现已经替换成功了,背景色变为了红色。

RRO

运行时替换要求就没有SRO那么高了,编译生成overlayred安装包后直接安装即可。安装好之后我们就编写代码来通过接受广播的方式替换主题了。

首先定义了一些常量

public class Constants {

    public static String THEME = "com.ts.overTest.overlay";
    // overlay包名
    public final static String OVERLAY_RED = "com.ts.overtest.overlayred";
    public final static String OVERLAY_GREEN = "com.ts.overtest.overlaygreen";
    public final static String CURRENT_THEME = "current_theme";

    public final static String THEME_RED = "theme.red";
    public final static String THEME_GREEN = "theme.green";
    public static final String THEME_DEFAULT = "theme.default";

    public static final String KEY_THEME_TYPE = "android.car.THEME_TYPE";

}

接下来注册一个广播接收器,收到广播后切换主题

public class ThemeChangeReceiver extends BroadcastReceiver {
    private static final String TAG = ThemeChangeReceiver.class.getSimpleName();
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "收到主题切换广播");
        String themeType = intent.getStringExtra(Constants.THEME);
        if (themeType == null || themeType.length() == 0){
            Log.d(TAG, "没有指明主题的类型");
            return;
        }
        ThemeChangeManager.changeTheme(themeType);
    }
}

上面代码中的ThemeChangeManager这个类是我们用来管理切换的,看一下其中的切换为红色主题的方法,它是怎么切换的

    /**
     * 切回红色主题
     */
    public static synchronized void changeToRedTheme() {
        try {
            IBinder binder = ServiceManager.getService("overlay");
            IOverlayManager mOverlayManager = IOverlayManager.Stub.asInterface(binder);
            // 通过IOverlayManager服务
            mOverlayManager.setEnabledExclusive(Constants.OVERLAY_RED, true, 0);
            Log.d(TAG, "切换红色主题成功");
            Settings.System.putString(MyApplication.context.getContentResolver(),Constants.KEY_THEME_TYPE, Constants.THEME_DEFAULT);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

ServiceManager和IOverlayManager这两个类都是不提供给开发者使用的,所以我们需要有frameworks.jar这个包,其次我使用了Settings.System,这是系统数据库,要系统应用才有权限,这一步不是必须的,可以不要,只是为了方便而已。通过OverlayManager这个服务我们还可以查看当前应用所拥有的overlay包的信息

	// 这里的两个参数分别是overlay的包名和userID
 OverlayInfo overlayThemeGreen = mOverlayManager.getOverlayInfo(Constants.OVERLAY_GREEN, 0);
 OverlayInfo overlayThemeRed = mOverlayManager.getOverlayInfo(Constants.OVERLAY_RED, 0);

拿到OverlayInfo后我们就可以查看它的激活状态,包名等等这些信息了。

除此之外,我们还可以通过adb查看和启动overlay

  • 查看
adb shell cmd overlay list --user current

在这里插入图片描述

我的com.ts.overtest这个应用中有两个overlay,签名的[ x ]表示其正在被使用状态。

  • 启用
adb shell cmd overlay enable packageName

总结

  • SRO ,一般在android源码编译阶段一起编译,或者push到/vendor/overlay目录下,重启生效。
  • RRO, 直接安装,通过代码控制,更加灵活。

demo位置

https://gitee.com/yangxudongll/android-overlay
  • 8
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android overlay是一种在Android应用程序中实现界面定制化的技术。通过使用overlay,开发者可以在不修改原始应用程序代码的情况下,添加、修改或替换应用程序的布局、样式和资源。在Android中,overlay通常是通过创建一个新的AndroidManifest.xml文件来实现的。\[1\] 在创建AndroidManifest.xml文件时,需要指定overlay的优先级、是否静态以及目标包名。优先级决定了overlay的显示顺序,静态表示overlay在运行时不会被修改,目标包名指定了要进行定制化的应用程序。\[1\] 除了创建AndroidManifest.xml文件,还可以参考一些相关的资料来了解更多关于Android overlay的信息。例如,可以参考http://mmmyddd.github.io/wiki/android/overlay.html和https://developer.sonymobile.com/2014/04/22/sony-contributes-runtime-resource-overlay-framework-to-android-code-example/。\[2\] 在编译后生成的apk中,overlay的路径可以根据不同的方案进行调整。一种常见的路径是vendor/overlay/TestOverlay/TestOverlay.apk,可以通过设置LOCAL_MODULE_PATH来指定路径。\[3\] #### 引用[.reference_title] - *1* *3* [Android Overlay机制](https://blog.csdn.net/weixin_44021334/article/details/130421043)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Android overlay简单总结](https://blog.csdn.net/Dylan_Sen/article/details/78878641)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值