Наложение ресурсов времени выполнения (RRO) — это пакет, который изменяет значения ресурсов целевого пакета во время выполнения. Например, приложение, установленное в образе системы, может изменять своё поведение в зависимости от значения ресурса. Вместо того, чтобы жёстко задавать значение ресурса во время сборки, RRO, установленный в другом разделе, может изменять значения ресурсов приложения во время выполнения.
RRO можно включить или отключить. Вы можете программно включить/выключить RRO, чтобы включить/выключить возможность RRO изменять значения ресурсов. RRO отключены по умолчанию (однако статические RRO включены по умолчанию).
Наложение ресурсов
Оверлеи работают, сопоставляя ресурсы, определённые в пакете оверлея, с ресурсами, определёнными в целевом пакете. Когда приложение пытается получить значение ресурса в целевом пакете, вместо этого возвращается значение ресурса оверлея, с которым сопоставлен целевой ресурс.
Настройте манифест
Пакет считается пакетом RRO, если он содержит тег <overlay>
как дочерний элемент тега <manifest>
.
Значение обязательного атрибута
android:targetPackage
указывает имя пакета, который RRO намеревается наложить.Значение необязательного атрибута
android:targetName
указывает имя накладываемого подмножества ресурсов целевого пакета, который RRO намеревается наложить. Если целевой объект не определяет накладываемый набор ресурсов, этот атрибут не должен присутствовать.
В следующем коде показан пример наложения AndroidManifest.xml
.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.overlay">
<application android:hasCode="false" />
<overlay android:targetPackage="com.example.target"
android:targetName="OverlayableResources"/>
</manifest>
Оверлеи не могут накладывать код, поэтому у них не может быть DEX-файлов. Кроме того, атрибут android:hasCode
тега <application
в манифесте должен быть установлен в false
.
Определить карту ресурсов
В Android 11 и выше рекомендуемый механизм определения карты ресурсов наложения заключается в создании файла в каталоге res/xml
пакета наложения, перечислении целевых ресурсов, которые должны быть наложены, и их заменяющих значений, а затем установке значения атрибута android:resourcesMap
тега манифеста <overlay>
на ссылку на файл карты ресурсов.
Следующий код показывает пример файла res/xml/overlays.xml
.
<?xml version="1.0" encoding="utf-8"?>
<overlay xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- Overlays string/config1 and string/config2 with the same resource. -->
<item target="string/config1" value="@string/overlay1" />
<item target="string/config2" value="@string/overlay1" />
<!-- Overlays string/config3 with the string "yes". -->
<item target="string/config3" value="@android:string/yes" />
<!-- Overlays string/config4 with the string "Hardcoded string". -->
<item target="string/config4" value="Hardcoded string" />
<!-- Overlays integer/config5 with the integer "42". -->
<item target="integer/config5" value="42" />
</overlay>
В следующем коде показан пример манифеста наложения.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.overlay">
<application android:hasCode="false" />
<overlay android:targetPackage="com.example.target"
android:targetName="OverlayableResources"
android:resourcesMap="@xml/overlays"/>
</manifest>
Собрать пакет
Android 11 и выше поддерживает правило сборки Soong для оверлеев, которое запрещает Android Asset Packaging Tool 2 (AAPT2) пытаться дедуплицировать конфигурации ресурсов с одинаковыми значениями ( --no-resource-deduping
) и удалять ресурсы без конфигураций по умолчанию ( --no-resource-removal
). Следующий код демонстрирует пример файла Android.bp
.
runtime_resource_overlay {
name: "ExampleOverlay",
sdk_version: "current",
}
Решить ресурсы
Если для целевого ресурса или ресурса наложения определено несколько конфигураций, среда выполнения ресурсов возвращает значение конфигурации, наиболее соответствующей конфигурации устройства. Чтобы определить, какая конфигурация является наиболее подходящей, объедините набор конфигураций ресурсов наложения с набором конфигураций целевых ресурсов, а затем следуйте стандартному процессу разрешения ресурсов (подробнее см. в статье «Как Android находит наиболее подходящий ресурс »).
Например, если наложение определяет значение для конфигурации drawable-en
, а целевой объект определяет значение для drawable-en-port
, drawable-en-port
имеет лучшее соответствие, поэтому значение целевой конфигурации drawable-en-port
выбирается во время выполнения. Чтобы наложить все конфигурации drawable-en
, наложение должно определить значение для каждой конфигурации drawable-en
определяемой целевой объектом.
Оверлеи могут ссылаться на собственные ресурсы, при этом поведение может различаться в зависимости от версии Android.
В Android 11 и более поздних версиях каждое наложение имеет собственное зарезервированное пространство идентификаторов ресурсов, которое не перекрывает пространство идентификаторов целевых ресурсов или другие пространства идентификаторов ресурсов наложения, поэтому наложения, ссылающиеся на свои собственные ресурсы, работают так, как и ожидалось.
В Android 10 и ниже оверлеи и целевые пакеты используют одно и то же пространство идентификаторов ресурсов, что может приводить к конфликтам и неожиданному поведению при попытке ссылаться на собственные ресурсы с помощью синтаксиса
@type/name
.
Включить/отключить наложения
Наложения можно включать/отключать вручную и программно.
Отключите или включите наложения вручную
Чтобы вручную включить и проверить RRO, выполните:
adb shell cmd overlay enable --user current com.example.carrro
adb shell cmd overlay list --user current | grep -i com.example com.example.carrro
Это включает RRO для системного пользователя ( userId = 0
), которому принадлежит SystemUI. Эта инструкция не влияет на приложения, запущенные пользователем активного режима ( userId = 10
). Чтобы включить RRO для пользователя активного режима, используйте параметр -–user 10
:
adb shell cmd overlay enable --user 10 com.example.carrro
Программное включение или отключение наложений
Используйте API OverlayManager
для включения и отключения изменяемых оверлеев (получите интерфейс API с помощью Context#getSystemService(Context.OVERLAY_SERVICE)
). Оверлей может быть включен только пакетом, на который он нацелен, или пакетом с разрешением android.permission.CHANGE_OVERLAY_PACKAGES
. При включении или отключении оверлея события изменения конфигурации распространяются на целевой пакет, и целевые активности перезапускаются.
Ограничить накладываемые ресурсы
В Android 10 и более поздних версиях XML-тег <overlayable>
предоставляет набор ресурсов, которые RRO разрешено накладывать. В следующем примере файла res/values/overlayable.xml
string/foo
и integer/bar
— это ресурсы, используемые для оформления внешнего вида устройства; для наложения этих ресурсов наложение должно явно указывать на коллекцию накладываемых ресурсов по имени.
<!-- 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>
В APK-файле можно определить несколько тегов <overlayable>
, но каждый тег должен иметь уникальное имя в пределах пакета. Например:
Допустимо, чтобы два разных пакета определяли
<overlayable name="foo">
.Недопустимо, чтобы в одном APK было два блока
<overlayable name="foo">
.
В следующем коде показан пример наложения в файле AndroidManifest.xml
.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.my.theme.overlay">
<application android:hasCode="false" />
<!-- This overlay will override the ThemeResources resources -->
<overlay android:targetPackage="android" android:targetName="ThemeResources">
</manifest>
Когда приложение определяет тег <overlayable>
, наложения, ориентированные на это приложение:
Необходимо указать
targetName
.Можно накладывать только ресурсы, перечисленные в теге
<overlayable>
.Можно выбрать только одно
<overlayable>
имя.
Невозможно включить наложение, нацеленное на пакет, который предоставляет накладываемые ресурсы, но не использует android:targetName
для нацеливания на определенный тег <overlayable>
.
Ограничить политики
Используйте тег <policy>
для применения ограничений к накладываемым ресурсам. Атрибут type
определяет, каким политикам должно соответствовать наложение, чтобы переопределить включенные ресурсы. Поддерживаются следующие типы:
-
public
. Любое наложение может переопределить ресурс. -
system
. Любое наложение на системный раздел может переопределить ресурсы. -
vendor
. Любое наложение на раздел поставщика может переопределить ресурсы. -
product
. Любое наложение на раздел продукта может переопределить ресурсы. -
oem
. Любое наложение на раздел oem может переопределить ресурсы. -
odm
. Любое наложение на раздел ODM может переопределить ресурсы. -
signature
. Любое наложение, подписанное той же подписью, что и целевой APK, может переопределить ресурсы. -
actor
. Любой оверлей, подписанный той же подписью, что и APK-файл Actor, может переопределить ресурсы. Actor объявлен в теге named-actor в системной конфигурации. -
config_signature
. Любой оверлей, подписанный той же подписью, что и APK-файл overlay-config, может переопределить ресурсы. Конфигурация overlay-config объявлена в теге overlay-config-signature в системной конфигурации.
В следующем коде показан пример тега <policy>
в файле res/values/overlayable.xml
.
<overlayable name="ThemeResources">
<policy type="vendor" >
<item type="string" name="foo" />
</policy>
<policy type="product|signature" >
<item type="string" name="bar" />
<item type="string" name="baz" />
</policy>
</overlayable>
Чтобы указать несколько политик, используйте вертикальные черты (|) в качестве разделителей. При указании нескольких политик наложение должно соответствовать только одной из них, чтобы переопределить ресурсы, перечисленные в теге <policy>
.
Настроить наложения
Android поддерживает различные механизмы настройки изменчивости, состояния по умолчанию и приоритета наложений в зависимости от версии Android.
Устройства под управлением Android 11 и более поздних версий могут использовать файл
OverlayConfig
(config.xml
) вместо атрибутов манифеста. Для наложений рекомендуется использовать файл OverlayConfig.Все устройства могут использовать атрибуты манифеста (
android:isStatic
иandroid:priority
) для настройки статических RRO.
Использовать OverlayConfig
В Android 11 и более поздних версиях можно использовать OverlayConfig
для настройки изменяемости, состояния по умолчанию и приоритета оверлеев. Чтобы настроить оверлей, создайте или измените файл partition/overlay/config/config.xml
, где partition
— это раздел настраиваемого оверлея. Для настройки оверлей должен находиться в каталоге overlay/
раздела, в котором он настроен. В следующем коде показан пример файла product/overlay/config/config.xml
.
<config>
<merge path="OEM-common-rros-config.xml" />
<overlay package="com.oem.overlay.device" mutable="false" enabled="true" />
<overlay package="com.oem.green.theme" enabled="true" />
</config>"
Тег <overlay>
требует атрибута package
, указывающего, какой пакет оверлея настраивается. Необязательный атрибут enabled
управляет тем, включен ли оверлей по умолчанию (значение по умолчанию — false
). Необязательный атрибут mutable
управляет тем, является ли оверлей изменяемым и может ли его состояние быть изменено программно во время выполнения (значение по умолчанию — true
). Оверлеи, не указанные в файле конфигурации, являются изменяемыми и отключены по умолчанию.
Приоритет наложения
Когда несколько оверлеев переопределяют одни и те же ресурсы, порядок оверлеев важен. Оверлей имеет больший приоритет, чем оверлеи с конфигурациями, предшествующими его собственной. Порядок приоритета оверлеев в разных разделах (от наименьшего к наибольшему) следующий.
-
system
-
vendor
-
odm
-
oem
-
product
-
system_ext
Объединить файлы
Использование тегов <merge>
позволяет объединять другие файлы конфигурации в указанном месте с файлом конфигурации. Атрибут path
тега представляет собой путь к объединяемому файлу относительно каталога, содержащего файлы конфигурации оверлея.
Использовать атрибуты манифеста/статические RRO
В Android 10 и ниже неизменность и приоритет наложения настраиваются с помощью следующих атрибутов манифеста.
android:isStatic
. Если значение этого логического атрибута равноtrue
, наложение включено по умолчанию и является неизменяемым, что предотвращает его отключение.android:priority
. Значение этого числового атрибута (влияющего только на статические наложения) определяет приоритет наложения, когда несколько статических наложений используют одно и то же значение ресурса. Чем больше число, тем выше приоритет.
В следующем коде показан пример AndroidManifest.xml
.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.overlay">
<application android:hasCode="false" />
<overlay android:targetPackage="com.example.target"
android:isStatic="true"
android:priority="5"/>
</manifest>
Изменения в Android 11
В Android 11 и более поздних версиях, если файл конфигурации находится в partition/overlay/config/config.xml
, оверлеи настраиваются с использованием этого файла, а android:isStatic
и android:priority
не влияют на оверлеи, расположенные в этом разделе. Определение файла конфигурации оверлея в любом разделе обеспечивает приоритет раздела оверлея.
Кроме того, в Android 11 и более поздних версиях отсутствует возможность использования статических оверлеев для изменения значений ресурсов, считываемых во время установки пакета. Для распространённого варианта использования статических оверлеев для изменения значений логических переменных, определяющих состояние включённого компонента, используйте тег SystemConfig
<component-override>
(новый в Android 11).
Отладочные наложения
Чтобы вручную включить, отключить и сбросить оверлеи, используйте следующую команду оболочки менеджера оверлеев.
adb shell cmd overlay
Использование enable
без указания пользователя влияет на текущего пользователя, то есть системного пользователя ( userId = 0
), которому принадлежит системный интерфейс. Это не влияет на пользователя переднего плана ( userId = 10
), которому принадлежат приложения. Чтобы включить RRO для пользователя переднего плана, используйте параметр –-user 10
:
adb shell cmd overlay enable --user 10 com.example.carrro
OverlayManagerService
использует idmap2
для сопоставления идентификаторов ресурсов в целевом пакете с идентификаторами ресурсов в пакете оверлея. Сгенерированные сопоставления идентификаторов хранятся в /data/resource-cache/
. Если ваш оверлей работает некорректно, найдите соответствующий файл idmap
для вашего оверлея в /data/resource-cache/
и выполните следующую команду.
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