Nakładka zasobów środowiska wykonawczego (RRO) to pakiet, który zmienia wartości zasobów pakietu docelowego w czasie działania. Na przykład aplikacja zainstalowana w obrazie systemu może zmieniać swoje działanie w zależności od wartości zasobu. Zamiast zakodowywać wartość zasobu na stałe w czasie kompilacji, RRO zainstalowany na innej partycji może zmieniać wartości zasobów aplikacji w czasie działania.
RRO można włączać i wyłączać. Możesz programowo ustawić stan włączenia/wyłączenia, aby przełączać możliwość zmiany wartości zasobów przez RRO. RRO są domyślnie wyłączone (jednak statyczne RRO są domyślnie włączone).
Zasoby nakładki
Nakładki działają poprzez mapowanie zasobów zdefiniowanych w pakiecie nakładki na zasoby zdefiniowane w pakiecie docelowym. Gdy aplikacja próbuje rozpoznać wartość zasobu w pakiecie docelowym, zamiast tego zwracana jest wartość zasobu nakładki, do którego jest mapowany zasób docelowy.
Konfigurowanie pliku manifestu
Pakiet jest uznawany za pakiet RRO, jeśli zawiera tag <overlay>
jako element podrzędny tagu <manifest>
.
Wartość wymaganego atrybutu
android:targetPackage
określa nazwę pakietu, który RRO ma zastąpić.Wartość opcjonalnego atrybutu
android:targetName
określa nazwę podzbioru zasobów docelowego pakietu, które można nakładać, a które RRO ma nakładać. Jeśli element docelowy nie definiuje zestawu zasobów, które można nakładać, ten atrybut nie powinien być obecny.
Poniższy kod pokazuje przykładową nakładkę 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>
Nakładki nie mogą nakładać się na kod, więc nie mogą zawierać plików DEX. Dodatkowo atrybut android:hasCode
tagu <application
> w pliku manifestu musi mieć wartość false
.
Określ mapę zasobów
W Androidzie 11 lub nowszym zalecanym mechanizmem definiowania mapy zasobów nakładki jest utworzenie pliku w katalogu res/xml
pakietu nakładki, wyliczenie docelowych zasobów, które mają być nakładane, i ich wartości zastępczych, a następnie ustawienie wartości atrybutu android:resourcesMap
tagu manifestu <overlay>
na odwołanie do pliku mapowania zasobów.
Poniższy kod przedstawia przykładowy plik 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>
Poniższy kod przedstawia przykładowy plik manifestu nakładki.
<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>
Tworzenie pakietu
Android 11 lub nowszy obsługuje regułę kompilacji Soong dla nakładek, która uniemożliwia narzędziu Android Asset Packaging Tool 2 (AAPT2) próbę deduplikacji konfiguracji zasobów o tej samej wartości (--no-resource-deduping
) i usuwania zasobów bez konfiguracji domyślnych (--no-resource-removal
). Poniższy kod przedstawia przykład pliku Android.bp
.
runtime_resource_overlay {
name: "ExampleOverlay",
sdk_version: "current",
}
Rozwiązywanie zasobów
Jeśli zasób docelowy lub zasób nakładki ma wiele konfiguracji zdefiniowanych dla zasobu, o który wysyłane jest zapytanie, środowisko wykonawcze zasobów zwraca wartość konfiguracji, która najlepiej pasuje do konfiguracji urządzenia. Aby określić, która konfiguracja jest najlepiej dopasowana, połącz zestaw konfiguracji zasobów nakładki z zestawem konfiguracji zasobów docelowych, a następnie postępuj zgodnie ze zwykłym procesem rozwiązywania zasobów (szczegółowe informacje znajdziesz w artykule Jak Android znajduje najlepiej dopasowany zasób).
Jeśli np. nakładka określa wartość konfiguracji drawable-en
, a element docelowy określa wartość drawable-en-port
, drawable-en-port
, drawable-en-port
jest lepiej dopasowany, więc w czasie działania wybierana jest wartość konfiguracji elementu docelowego drawable-en-port
. Aby zastąpić wszystkie konfiguracje drawable-en
, nakładka musi definiować wartość dla każdej konfiguracji drawable-en
, którą określa środowisko docelowe.
Nakładki mogą odwoływać się do własnych zasobów, a ich działanie może się różnić w zależności od wersji Androida.
W Androidzie 11 lub nowszym każda nakładka ma własną zarezerwowaną przestrzeń identyfikatorów zasobów, która nie pokrywa się z przestrzenią identyfikatorów zasobów docelowych ani z przestrzeniami identyfikatorów zasobów innych nakładek. Dzięki temu nakładki odwołujące się do własnych zasobów działają zgodnie z oczekiwaniami.
W Androidzie 10 lub starszym nakładki i pakiety docelowe mają tę samą przestrzeń identyfikatorów zasobów, co może powodować konflikty i nieoczekiwane działanie, gdy próbują odwoływać się do własnych zasobów za pomocą składni
@type/name
.
Włączanie i wyłączanie nakładek
Nakładki można włączać i wyłączać ręcznie oraz programowo.
Ręczne wyłączanie i włączanie nakładek
Aby ręcznie włączyć i zweryfikować RRO, uruchom to polecenie:
adb shell cmd overlay enable --user current com.example.carrro
adb shell cmd overlay list --user current | grep -i com.example com.example.carrro
Umożliwia to RRO dla użytkownika systemu (userId = 0
), który jest właścicielem SystemUI.
Ta instrukcja nie ma wpływu na aplikacje uruchamiane przez użytkownika na pierwszym planie (userId = 10
). Aby włączyć RRO dla użytkownika na pierwszym planie, użyj parametru -–user 10
:
adb shell cmd overlay enable --user 10 com.example.carrro
Programowe włączanie i wyłączanie nakładek
Użyj interfejsu OverlayManager
API, aby włączać i wyłączać nakładki modyfikowalne (pobierz interfejs API za pomocą Context#getSystemService(Context.OVERLAY_SERVICE)
). Nakładkę może włączyć tylko pakiet, do którego jest kierowana, lub pakiet z uprawnieniem android.permission.CHANGE_OVERLAY_PACKAGES
. Gdy nakładka jest włączana lub wyłączana, zdarzenia zmiany konfiguracji są propagowane do pakietu docelowego, a aktywności docelowe są ponownie uruchamiane.
Ograniczanie zasobów, które można nakładać
W Androidzie 10 lub nowszym tag XML <overlayable>
udostępnia zestaw zasobów, które mogą być zastępowane przez nakładki RRO. W tym przykładzie plikures/values/overlayable.xml
zasoby string/foo
i integer/bar
służą do określania wyglądu urządzenia. Aby nałożyć te zasoby, nakładka musi wyraźnie kierować na zbiór zasobów, które można nałożyć, według nazwy.
<!-- 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>
Plik APK może definiować wiele tagów <overlayable>
, ale każdy tag musi mieć w pakiecie unikalną nazwę. Na przykład:
Dwa różne pakiety mogą definiować
<overlayable name="foo">
.Nie można mieć 2 bloków
<overlayable name="foo">
w jednym pliku APK.
Poniższy kod pokazuje przykład nakładki w pliku 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>
Gdy aplikacja definiuje tag <overlayable>
, nakładki kierowane na tę aplikację:
Musisz podać wartość
targetName
.Może nakładać tylko zasoby wymienione w tagu
<overlayable>
.Możesz kierować reklamy tylko na 1 nazwę
<overlayable>
.
Nie możesz włączyć nakładki kierowanej na pakiet, który udostępnia zasoby z możliwością nakładania, ale nie używa tagu android:targetName
do kierowania na konkretny tag <overlayable>
.
Ograniczanie zasad
Użyj tagu <policy>
, aby wymusić ograniczenia dotyczące zasobów, które można nakładać. Atrybut
type
określa, które zasady musi spełniać nakładka, aby zastąpić uwzględnione zasoby. Obsługiwane typy obejmują:
public
. Każda nakładka może zastąpić zasób.system
. Każda nakładka na partycji systemowej może zastąpić zasoby.vendor
. Każda nakładka na partycję dostawcy może zastąpić zasoby.product
. Każda nakładka na podział produktów może zastąpić zasoby.oem
. Każda nakładka na partycji OEM może zastąpić zasoby.odm
. Każda nakładka na partycję odm może zastąpić zasoby.signature
. Każda nakładka podpisana tym samym podpisem co docelowy plik APK może zastąpić zasoby.actor
. Każda nakładka podpisana tym samym podpisem co plik APK aktora może zastąpić zasoby. Aktor jest zadeklarowany w tagu named-actor w pliku system config.config_signature
. Każda nakładka podpisana tym samym podpisem co plik APK overlay-config może zastąpić zasoby. Konfiguracja nakładki jest zadeklarowana w tagu overlay-config-signature w konfiguracji systemu.
Poniższy kod pokazuje przykładowy tag <policy>
w pliku 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>
Aby określić wiele zasad, użyj pionowych kresek (|) jako separatorów.
Jeśli określono wiele zasad, nakładka musi spełniać tylko jedne z nich, aby zastąpić zasoby wymienione w tagu <policy>
.
Konfigurowanie nakładek
Android obsługuje różne mechanizmy konfigurowania zmienności, stanu domyślnego i priorytetu nakładek w zależności od wersji Androida.
Urządzenia z Androidem 11 lub nowszym mogą używać pliku
OverlayConfig
(config.xml
) zamiast atrybutów pliku manifestu. Używanie pliku nakładki to zalecana metoda w przypadku nakładek.Wszystkie urządzenia mogą używać atrybutów pliku manifestu (
android:isStatic
iandroid:priority
) do konfigurowania statycznych nakładek RRO.
Używanie obiektu OverlayConfig
W Androidzie 11 lub nowszym możesz użyć OverlayConfig
, aby skonfigurować możliwość zmiany, stan domyślny i priorytet nakładek. Aby skonfigurować nakładkę, utwórz lub zmodyfikuj plik znajdujący się w lokalizacji partition/overlay/config/config.xml
, gdzie partition
to partycja nakładki, którą chcesz skonfigurować. Aby można było skonfigurować nakładkę, musi ona znajdować się w katalogu overlay/
partycji, w której jest konfigurowana. Poniższy kod zawiera przykład 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>"
Tag <overlay>
wymaga atrybutu package
, który wskazuje, który pakiet nakładek jest konfigurowany. Opcjonalny atrybut enabled
określa, czy nakładka jest domyślnie włączona (domyślnie false
). Opcjonalny atrybut mutable
określa, czy nakładka jest modyfikowalna i czy jej stan włączenia można zmienić programowo w czasie wykonywania (domyślnie true
). Nakładki, które nie są wymienione w pliku konfiguracyjnym, są modyfikowalne i domyślnie wyłączone.
Pierwszeństwo nakładki
Gdy kilka nakładek zastępuje te same zasoby, kolejność nakładek ma znaczenie. Nakładka ma wyższy priorytet niż nakładki z konfiguracjami poprzedzającymi jej własną konfigurację. Kolejność pierwszeństwa nakładek w różnych partycjach (od najmniejszego do największego pierwszeństwa) jest następująca:
system
vendor
odm
oem
product
system_ext
Scalanie plików
Użycie tagów <merge>
umożliwia scalenie innych plików konfiguracji w pliku konfiguracji w określonym miejscu. Atrybut path
tagu reprezentuje ścieżkę do pliku do scalenia względem katalogu zawierającego pliki konfiguracji nakładki.
Używanie atrybutów pliku manifestu lub statycznych nakładek RRO
W Androidzie 10 i starszych wersjach niezmienność i pierwszeństwo nakładki są konfigurowane za pomocą tych atrybutów manifestu:
android:isStatic
. Jeśli wartość tego atrybutu logicznego jest ustawiona natrue
, nakładka jest domyślnie włączona i nie można jej zmienić, co uniemożliwia jej wyłączenie.android:priority
. Wartość tego atrybutu liczbowego (który wpływa tylko na statyczne nakładki) określa priorytet nakładki, gdy wiele statycznych nakładek jest kierowanych na tę samą wartość zasobu. Im wyższa liczba, tym wyższy priorytet.
Poniższy kod zawiera przykład 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>
Zmiany w Androidzie 11
Jeśli w Androidzie 11 lub nowszym plik konfiguracji znajduje się w partition/overlay/config/config.xml
, nakładki są konfigurowane przy użyciu tego pliku, a android:isStatic
i android:priority
nie mają wpływu na nakładki znajdujące się w partycji. Zdefiniowanie pliku konfiguracyjnego nakładki w dowolnej partycji wymusza pierwszeństwo partycji nakładki.
Dodatkowo Android 11 lub nowszy usuwa możliwość używania statycznych nakładek do wpływania na wartości zasobów odczytywanych podczas instalacji pakietu. W przypadku typowego zastosowania statycznych nakładek do zmiany wartości zmiennych logicznych, które konfigurują stan włączenia komponentu, użyj tagu <component-override>
SystemConfig
(nowość w Androidzie 11).
Nakładki debugowania
Aby ręcznie włączać, wyłączać i zrzucać nakładki, użyj tego polecenia powłoki menedżera nakładek.
adb shell cmd overlay
Użycie enable
bez określenia użytkownika wpływa na bieżącego użytkownika, czyli użytkownika systemu (userId = 0
), który jest właścicielem interfejsu systemu. Nie ma to wpływu na użytkownika pierwszego planu (userId = 10
), który jest właścicielem aplikacji. Aby włączyć RRO dla użytkownika na pierwszym planie, użyj parametru –-user 10
:
adb shell cmd overlay enable --user 10 com.example.carrro
OverlayManagerService
używa idmap2
do mapowania identyfikatorów zasobów w pakiecie docelowym na identyfikatory zasobów w pakiecie nakładki. Wygenerowane mapowania identyfikatorów są przechowywane w /data/resource-cache/
. Jeśli nakładka nie działa prawidłowo, znajdź odpowiedni plik idmap
w folderze /data/resource-cache/
, a następnie uruchom to polecenie.
adb shell idmap2 dump --idmap-path [file]
To polecenie wyświetla mapowanie zasobów, jak pokazano poniżej.
[target res id] - > [overlay res id] [resource name]
0x01040151 -> 0x01050001 string/config_dozeComponent
0x01040152 -> 0x01050002 string/config_dozeDoubleTapSensorType
0x01040153 -> 0x01050003 string/config_dozeLongPressSensorType