自定义应用

现在,车载设备界面库组件和资源已内置于应用中,为了自定义这些应用,原始设备制造商 (OEM) 必须提供两个叠加层:

  • 构建时叠加层。此叠加层会添加 RRO 所需的任何资源。其中包括:

    • 可绘制对象
    • 样式(例如文本外观)
    • 共享资源(例如颜色)

  • RRO 叠加层。此文件夹包含用于为每个目标应用生成一个 RRO 的资源。这些资源只能引用:

    • 同一 RRO 中定义的值(例如,对颜色而言,此值是一个十六进制值)。
    • Android 框架资源(例如 @android:color/accent)。
    • 上述构建时叠加层中定义的资源。

常规结构

提议的自定义叠加层结构如下所示:

  • <path-to-OEM-overlays>/

    • overlay/framework/base/core/res/:构建时叠加层资源。

    • rro/

      • Android.mk:用于根据此文件夹中包含的资源为每个目标软件包生成 RRO 的 Makefile。

      • AndroidManifest.xml:上述 Makefile 使用的清单文件模板。

      • res/:应用于所有目标应用的运行时叠加层。

OEM 可以有多个上述结构,具体取决于他们希望在单个 build 目标中处理的品牌数(请参阅处理多个品牌)。

运行时资源叠加层

OEM 叠加层文件夹中的 RRO 文件夹应包含要应用于所有目标应用的资源。RRO 存在一些局限性,影响了其叠加复合资源的能力。总的来说,RRO:

  • 不能引用目标 APK 或 RRO 本身中定义的资源标识符。这意味着 RRO 无法添加新的标识符,例如新的可绘制对象、颜色或样式。

  • 可以引用框架中定义的资源标识符,无论这些资源是在 /frameworks/base/core/res 中定义的,还是通过构建时叠加层定义的。必须使用 android: 命名空间引用这些标识符:

    • 对于公共资源 DeviceDefault RRO,请使用 android
      例如 @android:style/TextAppearance.DeviceDefault.Large

    • 对于所有其他资源(非公共资源或通过构建时叠加层添加的资源),请使用 *android
      例如 @*android/style:TextAppearance.OEM.Brand1.Title

除资源外,RRO 文件夹还必须包含:

  • AndroidManifest.xml:在以下示例中,RRO_PACKAGE_NAMETARGET_PACKAGE_NAME 是 Makefile 的占位符:

    <?xml version=1.0 encoding=utf-8?>
    <manifest xmlns:android=http://schemas.android.com/apk/res/android”
        package={{RRO_PACKAGE_NAME}} />
        <application android:hasCode=false />
        <overlay android:priority=10
            Android:targetPackage={{TARGET_PACKAGE_NAME}}
            Android:requiredSystemPropertyName=ro.product.sku
            Android:requiredSystemPropertyValue=<your-product-sku> />
    </manifest>
  • Android.mk:在其中,以下 Makefile 中的 oem 定义了所有生成的 RRO 都会具有的前缀。
      LOCAL_PATH := $(call my-dir)
      include $(CLEAR_VARS)
      CAR_UI_RRO_SET_NAME := oem
      CAR_UI_RESOURCE_DIR := $(LOCAL_PATH)/res
      CAR_UI_RRO_TARGETS := $(CAR_UI_RRO_PACKAGE_NAMES)
      include packages/apps/Car/libs/car-ui-lib/generate_rros.mk
      

配置 RRO 叠加层

您可以使用现在支持的新配置文件 overlayable.xml 定义访问权限控制。例如,您可以指定谁能叠加资源以及可叠加哪些资源。因此,您现在可以采用不同的方式对资源进行分组,使其可供不同的 RRO 进行叠加。

如需设置 RRO 访问权限控制,请执行以下操作:

  1. res/values 文件夹中,创建 overlayable.xml
  2. 创建 <overlayable> 资源标记。
  3. <overlayable> 标记定义 name 属性,该属性必须在软件包中具有唯一性。每个叠加层只能以一个可叠加组为目标。
  4. <overlayable> 内定义 <policy> 标记。
  5. 定义可以叠加的资源组。例如:
      <resources>
          <overlayable name="OverlayableResources">
              <policy type="public">
                  <item type="string" name="app_title" />
              </policy>
          </overlayable>
      </resources>
      

如需将以下更改应用到您的 RRO 项目,请执行以下操作:

  1. res/xml 文件夹中,创建 overlays.xml。请参阅以下代码示例中的 overlay 相关条目。
  2. 定义要替换的资源。
  3. android:resourcesMap="@xml/overlays" 添加到 AndroidManifest.xml 中的 <overlay> 标记。如需查看示例,请参阅以下代码示例中的 <overlay> 相关条目。
  4. 设置 android:isStatic=”true” 以便设置一个静态叠加层。每个叠加层只能以一个可叠加的组为目标。

请参考以下示例。第一部分属于 AndroidManifest.xml,而第二部分与 overlays.xml 相关。

  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.android.car.ui.rro"
      android:versionCode="1"
      android:versionName="1.0">
      <overlay android:targetName="OverlayableResources"
               android:resourcesMap="@xml/overlays"
               android:targetPackage="com.android.car.ui"
               android:priority="1"
               android:isStatic="false" />
  </manifest>
  <overlay>
      <item target="string/app_title" value="@ string/app_title" />
  </overlay>
  

提醒一点,在 Android 10 中,先前已有的 RRO 将继续运行。需要注意的是,如需使用 PackageManagerRRO 进行安装,软件包必须预先安装或使用与目标应用相同的密钥进行签名。在 Android 10 中,可以叠加布局文件。不过,这样做需要在获取视图时使用 requireViewById() 而不是 findViewById()。在 Android 10 中,已对 car-ui-lib 实现此变更以支持布局叠加层。

Android 的下一个主要版本将允许您叠加布局文件、在 RRO 软件包中定义新的资源并在内部引用这些资源。

添加 OEM 专属资源

为了克服无法添加 OEM 资源的 RRO 局限性,请执行以下操作:

  • 使用构建时叠加层扩展 frameworks/base,添加所有必要的资源。
  • 使用 *android: 命名空间从 OEM RRO 引用这些资源。

例如,您可以通过以下方式添加一个 OEM 专属可绘制对象并将其用于 RRO 中:

  • <path-to-OEM-overlays>

    • overlay/framework/base/core/res/res/drawable/

      • oem_background_drawable.xml

    • rro/res/values

      • drawables.xml

        <resources>
            <item type="drawable" name="car_ui_toolbar_background">
                @*android:drawable/oem_background_drawable
            </item>
        </resources>

处理多个品牌

RRO 清单文件包含相应语法以使这些清单文件可以根据系统属性有条件地应用。如需在一个系统映像中处理多个品牌,OEM 可以如下使用此语法(请参阅常规结构)。

<?xml version=1.0 encoding=utf-8?>
<manifest xmlns:android=http://schemas.android.com/apk/res/android”
    package={{RRO_PACKAGE_NAME}}/>
    <application android:hasCode=false/>
    <overlay android:priority=10
        Android:targetPackage={{TARGET_PACKAGE_NAME}}
        Android:requiredSystemPropertyName=ro.product.sku
        Android:requiredSystemPropertyValue=<your-product-sku>/>
</manifest>

仅当相应的系统属性与所提供的值匹配时,android:requiredSystemPropertyNameandroid:requiredSystemPropertyValue 的语法才能使此 RRO 获得启用。然后,OEM 可以定义多个此类 RRO,这些 RRO 全部静态启用,并且一次只能有一个 RRO 处于激活状态。

将车载设备界面库添加到目标

如需将车载设备界面库纳入 Android 目标中,您必须添加以下代码段:

# Include build-time overlays
    PRODUCT_PACKAGE_OVERLAYS += \
      <path-to-oem-overlays>/overlay
    # Define package names to generate RROs for
    CAR_UI_RRO_PACKAGE_NAMES += \
      com.android.car.ui.paintbooth \
      com.android.car.media \
      com.android.car.dialer \
      com.android.car.linkviewer \
      com.android.car.settings \
      com.android.car.systemupdater \
      com.google.android.apps.automotive.inputmethod \
      com.google.android.apps.automotive.templates.host \
      ...
    # Include generated RROs
    PRODUCT_PACKAGES += \
      oem-com-android-car-ui-paintbooth \
      oem-com-android-car-media \
      oem-com-android-car-dialer \
      oem-com-android-car-linkviewer \
      oem-com-android-car-settings \
      oem-com-android-car-systemupdater \
      oem-com-google-android-apps-automotive-inputmethod \
      oem-com-google-android-apps-automotive-templates-host \
      ...
  • 使 <path-to-OEM-overlays>/rro/Android.mkCAR_UI_RRO_PACKAGE_NAMES 中指出名称的每个软件包生成一个 RRO。

  • PRODUCT_PACKAGES 中包含生成的 RRO。

  • PRODUCT_PACKAGE_OVERLAYS 中包含构建时叠加层,用于添加 OEM 专属资源。

如需了解哪些软件包支持 car-ui-lib,请查看 car-ui-lib 支持的软件包