IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> android overlay机制实践 -> 正文阅读

[移动开发]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
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-04-09 18:32:44  更:2022-04-09 18:34:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 20:56:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码