ランタイム リソース オーバーレイ(RRO)

Android 10 以降では、Android Asset Packaging Tool 2(AAPT2)を使用することで、ランタイム リソース オーバーレイ(RRO)で APK を通じて実行時にオーバーレイできるリソースを定義できます。

RRO の実装

Android 10 では、共通の名前でまとめてオーバーレイする必要があるリソースを集約する新しい <overlayable> XML タグが導入されています。以下の例の string/foointeger/bar は、デバイスの表示のテーマ設定に使用するリソースです。これらのリソースをオーバーレイするには、オーバーレイ可能なリソースのコレクションを名前別に明示的にオーバーレイのターゲットにする必要があります。

1 つの APK で複数の <overlayable> タグを定義できますが、各タグの名前はパッケージ内で一意である必要があります。たとえば、次のように定義します。

  • 2 つの異なるパッケージの両方で <overlayable name="foo"> を定義することは可能です。

  • 1 つの APK で 2 つの <overlayable name="foo"> ブロックを定義することはできません。

res/values/overlayable.xml ファイルの例:

<!-- The collection of resources for theming the appearance of the device -->
<overlayable name=”ThemeResources”>
       <policy type=”public”>
               <item type=”string” name=”foo/” />
               <item type=”integer” name=”bar/” />
       </policy>
       ...
</overlayable>

AndroidManifest.xmlファイル内のオーバーレイの例:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="com.my.theme.overlay">

       <!-- This overlay will override the ThemeResources resources -->
       <overlay android:targetPackage="android" android:targetName="ThemeResources">
</manifest>

アプリで <overlayable> タグを定義する場合、そのアプリをターゲットにするオーバーレイは次のようになります。

  • 「targetName」を指定する必要があります。

  • タグ内にリストされたリソースのみをオーバーレイできます。

  • 1 つの <overlayable> の名前のみをターゲットにすることができます。

パッケージでオーバーレイ可能なリソースを公開するが、特定の <overlayable> タグをターゲットにするために android:targetName を使用しない場合、そのパッケージをターゲットにするオーバーレイは有効にできません。

ポリシーの制限

<policy> タグを使用すると、オーバーレイ可能なリソースに対して制限を適用できます。type 属性では、指定されたリソースをオーバーライドするためにオーバーレイで遵守する必要があるポリシーを指定します。サポートされるタイプは次のとおりです。

  • public - 任意のオーバーレイでリソースをオーバーライドできます。

  • system - システム パーティション上の任意のオーバーレイでリソースをオーバーライドできます。

  • vendor - ベンダー パーティション上の任意のオーバーレイでリソースをオーバーライドできます。

  • product - プロダクト パーティション上の任意のオーバーレイでリソースをオーバーライドできます。

  • signature - ターゲット APK と同じ署名で署名された任意のオーバーレイでリソースをオーバーライドできます。

res/values/overlayable.xml ファイル内の <policy> タグの例:

<overlayable name=”ThemeResources”>
   <policy type=“product” >
       <item type=”string” name=”foo” />
   </policy>
   <policy type=“system|signature”  >
       <item type=”string” name=”bar” />
       <item type=”string” name=”baz” />
   </policy>
</overlayable>

複数のポリシーを指定するには、区切り文字として縦棒(|)を使用します。 複数のポリシーを指定した場合、オーバーレイでは、<policy> タグ内にリストされたリソースをオーバーライドするための 1 つのポリシーのみを遵守する必要があります。

RRO の管理

  • オーバーレイの有効化、無効化、並べ替えを行うには、CHANGE_OVERLAY_PACKAGES 権限が必要です。

  • 現在のユーザー以外のユーザー用にオーバーレイを有効にするには、INTERACT_ACROSS_USERS 権限が必要です。

コンプライアンス

フレームワークのリソースのオーバーレイ可能宣言は、特定の SDK レベルのすべての Android デバイスで一貫している必要があります。フレームワーク リソースのオーバーレイ可能定義に影響するすべての追加、削除、ポリシー変更、およびその他の変更は、すべての Android デバイスで一貫性を保つために、AOSP に統合する必要があります。CTS テストは、Android フレームワークのオーバーレイ可能な API が、AOSP で定義されているオーバーレイ可能定義から逸脱しないようにします。

RRO のインストール

Android 9 以前では、オーバーレイをプリインストールするか、プラットフォーム署名で署名して、PackageManagerService によってインストールする必要があります。Android 9 を搭載したデバイス上のオーバーレイは、デバイスを Android 10 にアップグレードした後も正常に機能し続けます。

Android 10 以降では、プラットフォーム署名で署名されていないオーバーレイをデータ パーティション上にインストールできます。オーバーレイ可能なリソースを宣言していないパッケージをターゲットとするオーバーレイは、ターゲット パッケージと同じ署名で署名するか、プリインストールして有効にする必要があります。

デバッグ

次のコマンドを使用してオーバーレイをインストールし、アプリのターゲットをデバイスに設定します。

adb install

オーバーレイの有効化、無効化、ダンプを手動で行うには、オーバーレイ マネージャーの次のシェルコマンドを使用します。

adb shell cmd overlay

OverlayManagerServiceidmap 2 を使用して、ターゲット パッケージのリソース ID をオーバーレイ パッケージのリソース ID にマッピングします。生成された ID のマッピングは /data/resource-cache/ に格納されます。

オーバーレイが正常に機能しない場合は、/data/resource-cache/ でオーバーレイの対応する idmap ファイルを探して、次のコマンドを実行します。

adb shell idmap2 dump --idmap-path [file]

このコマンドは、次のようなリソースのマッピングを出力します。

[target res id] - > [overlay res id] [resource name]
0x01040151 -> 0x01050001 string/config_dozeComponent
0x01040152 -> 0x01050002 string/config_dozeDoubleTapSensorType
0x01040153 -> 0x01050003 string/config_dozeLongPressSensorType
...

オーバーレイ可能な XML スキーマ

<?xml version="1.0" encoding="UTF-8"?>

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
 elementFormDefault="qualified">

 <xs:element name="overlayable">
   <xs:complexType>
     <xs:sequence>
       <xs:element maxOccurs="unbounded" ref="policy"/>
     </xs:sequence>
     <xs:attribute name="actor" type="xs:anyURI"/>
     <xs:attribute name="name" use="required" type="xs:NCName"/>
   </xs:complexType>
 </xs:element>

 <xs:element name="policy">
   <xs:complexType>
     <xs:sequence>
       <xs:element maxOccurs="unbounded" ref="item"/>
     </xs:sequence>
     <xs:attribute name="type" use="required"/>
   </xs:complexType>
 </xs:element>

 <xs:element name="item">
   <xs:complexType>
     <xs:attribute name="name" use="required"/>
     <xs:attribute name="type" use="required" type="xs:NCName"/>
   </xs:complexType>
 </xs:element>
</xs:schema>