探索AOSP(Framework)中的RRO:运行时资源覆盖的奥秘

图片

在Android开发中,为了提供更大的灵活性和可定制性,Android提供了一种关键特性:运行时资源覆盖(Runtime Resource Overlay,简称RRO)。本文将深入探讨RRO在Android开源项目(AOSP)中的作用及其实现方法。

什么是运行时资源覆盖(RRO)?

运行时资源覆盖(RRO)是一种允许开发者和设备制造商在运行时动态修改Android应用程序资源的技术。这些资源包括XML布局、图像、样式等,它们共同构成了任何Android应用程序的用户界面和外观。通过RRO,可以在不修改原始资源的情况下定制应用程序的UI组件。

资源的定义

所有UI组件,包括上述的XML、布局、字符串、颜色、样式、主题、图像和图标(drawable),都存在于Android应用程序和框架源代码中的“res”文件夹中。这些资源都可以被RRO系统定制和覆盖。

RRO的工作原理

下面的流程图展示了RRO APK和原始应用程序APK如何在系统中被放置。系统将生成并放置一个“Idmap”文件,该文件包含了两个包的资源映射表,并选择最合适的资源ID来反映在Android设备上的可见UI组件的设计。

图片

机制

RRO通过一种被称为“资源覆盖包”(Resource Overlay Packages,简称ROPs)的机制来实现。每个ROP是一个独立的APK文件,包含在运行时需要覆盖的资源。这些资源可以包括布局、图像、动画、值(例如字符串、尺寸)或任何应用程序在创建用户界面时使用的资源。

结构

一个ROP包含一个反映被覆盖应用程序资源结构的目录结构。例如,如果我们想修改某个特定活动的设计,可以在ROP中放置一个修改后的布局XML文件,其路径与应用程序中的实际布局相同。

优先级

RRO有一个优先级顺序,指定了它们的应用顺序。当一个应用程序有多个覆盖时,系统按照优先级顺序使用它们,优先级高的覆盖优先。

资源匹配

当应用程序请求一个资源(例如布局文件)时,系统首先检查是否有与包名和资源名相匹配的覆盖。如果找到匹配的覆盖,并且其优先级高于其他覆盖,则使用其资源代替原始资源。

动态主题

RRO允许在不修改源代码的情况下对应用程序进行动态主题化,这意味着可以通过应用不同的覆盖来改变应用程序的外观和感觉。

AOSP中实现RRO的重要文件

需要被覆盖的用户界面资源应作为源代码的一部分添加,无论是Android应用程序还是AOSP源代码。

图片

为什么选择RRO?

在实施RRO之前,我们需要了解RRO的限制:

  • • 不能在Java源代码上使用RRO来定制功能。
  • • RRO的理念是避免修改现有资源,专注于UI定制。
  • • RRO的概念是将覆盖资源放在一个地方,原始资源放在另一个地方,这种灵活性使得设备制造商在未来更新时更加便捷。

RRO的优点

通过RRO,设备制造商和开发者可以在不更改应用程序源代码的情况下实现UI的定制。这种方法不仅提高了开发效率,还为设备制造商提供了更大的灵活性,以适应不同的市场需求。

示例代码

以下是使用RRO进行UI定制的示例代码, 为了简化练习,我们将对“Contacts”应用程序中的一个简单字符串资源进行覆盖操作。我们将把“您的联系人列表为空”替换为“没有联系人”。

在直接对AOSP源代码进行RRO操作之前,需要先下载并构建AOSP源代码。你也可以使用一个示例应用程序进行练习。下面介绍的“Android.bp”文件结构将帮助你直接在AOSP源代码中构建RRO。

在AOSP 12源代码中的联系人应用程序中有如下字符串资源:

<string name="noContacts">Your contacts list is empty</string>

在覆盖实现前,该字符串的显示值如上所示。

第一步:检查overlayable.xml文件

在选择的应用程序源代码路径“res/value/”中查找overlayable.xml文件,并确保资源在该文件中被公开。

示例:overlayable.xml

<resources>
  <overlayable name="Contacts">
    <policy type="public">
      <item type="string" name="noContacts"/>
    </policy>
  </overlayable>
</resources>

若应用程序默认已公开覆盖资源,可以在res目录或其子目录中找到overlayable.xml文件。

可能存在以下情况:

  1. 1. overlayable.xml文件不存在。
  2. 2. overlayable.xml文件存在,但资源未被公开用于覆盖。

注意:在这些情况下,覆盖必须预装在系统镜像中,或覆盖必须与目标包使用相同的签名。在“联系人”应用程序的案例中,overlayable.xml文件不存在,因此我们将使用与目标应用程序相同的签名构建覆盖。

第二步:创建覆盖结构和必要文件

现在,我们将创建一个覆盖包结构。按照前述说明,准备结构和所有文件,并将覆盖结构包放置在AOSP源代码中的任意合适位置。

第三步:准备AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.android.contacts.rro">
    <overlay
        android:priority="1"
        android:targetName="Contacts"
        android:targetPackage="com.android.contacts"
        android:isStatic="true"
        android:resourcesMap="@xml/overlays"
    />
</manifest>
  • • targetName:RRO意图覆盖的包名。
  • • targetPackage:RRO意图覆盖的目标包。
  • • isStatic:定义RRO是否应为可变的。如果isStatic设置为true,则RRO在运行时不可动态启用或禁用,且在启动时默认启用。
  • • resourceMap:此标签包含overlay.xml,指定RRO包与目标应用程序或框架资源包的资源映射。这些资源ID将被映射,IdMap文件将根据资源映射为RRO生成。
  • • priority:当多个RRO覆盖同一目标包时,优先级最高的覆盖将被应用。
  • • package:命名空间,如“com.android.contacts.rro”。通常通过在目标包名后添加.rro扩展来命名RRO包。

第四步:准备Android.bp

android_app {
    name: "testcustomerro",
    resource_dirs: ["res"],
    certificate: "shared",
    product_specific: true,
    privileged: true,
    sdk_version: "system_current",
    min_sdk_version: "21",
    manifest: "AndroidManifest.xml",
    aaptflags: [
        "--no-resource-deduping",
        "--no-resource-removal",
     ]
}

第五步:准备overlays.xml

<overlay>
    <item target="string/noContacts" value="@string/noContacts"/>
</overlay>

第六步:准备res文件

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <string name="noContacts">No Contacts available</string>
</resources>

一旦所有文件按上述方式配置,我们就可以使用AOSP源代码构建RRO包。在运行联系人应用程序时,RRO包将被安装。

结论

运行时资源覆盖(RRO)为Android开发者和设备制造商提供了一种强大的工具,使他们能够在不修改原始代码的情况下定制应用程序的UI。通过理解RRO的工作原理和实现机制,我们可以更好地利用这一特性,为用户提供更加个性化和动态的体验。

通过本文的实践指南,我们详细讲解了如何在AOSP中实现运行时资源覆盖(RRO)。RRO提供了一种强大的工具,使开发者和设备制造商能够在不修改原始代码的情况下实现应用程序UI的动态定制。

RRO不仅提升了UI定制的灵活性,还为设备制造商的未来更新提供了便利。如果你正在开发一个需要高度定制化的Android应用程序或设备,不妨尝试一下RRO,体验其带来的便利和优势。

希望本文能帮助你更好地理解和应用RRO,为你的Android开发带来新的思路和灵感。

声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/417621.html

(0)
联系我们
联系我们
分享本页
返回顶部