如何用同一个Runtime Resource Overlay(RRO)包适配多个应用?
单个RRO包适配多个目标应用的解决方案
Android系统的Manifest规范明确要求:每个Runtime Resource Overlay(RRO)包只能包含一个<overlay>标签,所以直接添加第二个<overlay>节点的方式是不被系统识别的。要实现一个项目适配多个目标应用,有两种可行方案:
方案一:拆分多个独立RRO模块(推荐,兼容API 29+)
在同一个Android项目中创建多个RRO子模块,每个模块对应一个目标应用,共享资源可以通过公共模块复用。
实现步骤:
- 创建第一个RRO模块(比如
firelauncher-overlay),其Manifest内容如下:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.example.firelauncher.overlay"> <application android:hasCode="false" android:theme="@style/Theme.Fluid.Dark"/> <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/> <overlay android:targetPackage="com.amazon.firelauncher" android:targetName="CarUiCodelab" android:isStatic="true" android:priority="1" android:resourcesMap="@xml/sample_overlay" /> </manifest>
- 创建第二个RRO模块(比如
settings-overlay),其Manifest内容如下:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.example.settings.overlay"> <application android:hasCode="false" android:theme="@style/Theme.Fluid.Dark"/> <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/> <overlay android:targetPackage="com.android.settings" android:targetName="CarUiCodelab1" android:isStatic="true" android:priority="1" android:resourcesMap="@xml/sample_overlay" /> </manifest>
- (可选)创建一个公共资源模块,将两个RRO共用的
sample_overlay.xml、主题样式等资源放在这里,让两个RRO模块依赖该公共模块,避免重复代码。
方案二:使用动态RRO(仅API 31+)
如果你的目标系统是Android 12(API 31)及以上,可以使用动态RRO,通过代码在运行时注册多个覆盖目标。注意这种方式需要系统权限或特定签名,且用户需要授权。
实现步骤:
- 修改Manifest,将
android:isStatic设为false,只保留一个基础<overlay>标签:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.example.myapplication"> <application android:hasCode="true" android:theme="@style/Theme.Fluid.Dark"> <activity android:name=".OverlaySetupActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="31" android:targetSdkVersion="31"/> <uses-permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES" /> <overlay android:isStatic="false" android:priority="1" android:resourcesMap="@xml/sample_overlay" /> </manifest>
- 在代码中使用
OverlayManager注册多个目标:
import android.content.Context import android.content.pm.PackageManager import android.os.Build import android.os.OverlayManager import android.os.UserHandle import androidx.appcompat.app.AppCompatActivity import android.os.Bundle class OverlaySetupActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_overlay_setup) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { val overlayManager = getSystemService(Context.OVERLAY_SERVICE) as OverlayManager val selfPackageName = packageName // 注册第一个目标应用 registerOverlay(overlayManager, selfPackageName, "com.amazon.firelauncher") // 注册第二个目标应用 registerOverlay(overlayManager, selfPackageName, "com.android.settings") } } private fun registerOverlay(overlayManager: OverlayManager, overlayPackage: String, targetPackage: String) { try { val overlayInfo = overlayManager.getOverlayInfo(overlayPackage, UserHandle.myUserId()) overlayInfo.targetPackageName = targetPackage overlayManager.registerOverlay(overlayInfo) // 启用覆盖 overlayManager.setEnabled(overlayPackage, true, UserHandle.myUserId()) } catch (e: PackageManager.NameNotFoundException) { e.printStackTrace() } } }
注意:动态RRO需要应用拥有CHANGE_OVERLAY_PACKAGES权限,在Android 13及以上,用户需要在系统设置中手动授权该权限。
内容的提问来源于stack exchange,提问作者Hadoop1234
相关产品推荐
相关产品推荐

