Zmień wartość zasobów aplikacji w czasie wykonywania

Zadbaj o dobrą organizację dzięki kolekcji Zapisuj i kategoryzuj treści zgodnie ze swoimi preferencjami.

Nakładka zasobów środowiska wykonawczego (RRO) to pakiet, który zmienia wartości zasobów pakietu docelowego w czasie wykonywania. Na przykład aplikacja zainstalowana w obrazie systemu może zmienić swoje zachowanie w zależności od wartości zasobu. Zamiast zakodować na stałe wartość zasobu w czasie kompilacji, RRO zainstalowane na innej partycji może zmienić wartości zasobów aplikacji w czasie wykonywania.

RRO można włączyć lub wyłączyć. Możesz programowo ustawić stan włączenia/wyłączenia, aby przełączać zdolność RRO do zmiany wartości zasobów. RRO są domyślnie wyłączone (jednak statyczne RRO są domyślnie włączone).

Nakładanie się zasobów

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, na który jest mapowany zasób docelowy.

Konfigurowanie manifestu

Pakiet jest uważany za pakiet RRO, jeśli zawiera znacznik <overlay> jako element podrzędny znacznika <manifest> .

  • Wartość wymaganego atrybutu android:targetPackage określa nazwę pakietu, który RRO zamierza nałożyć.

  • Wartość opcjonalnego atrybutu android:targetName określa nazwę możliwego do nałożenia podzbioru zasobów pakietu docelowego, który RRO zamierza nałożyć. Jeśli element docelowy nie definiuje zestawu zasobów, które można nakładać, ten atrybut nie powinien być obecny.

Poniższy kod przedstawia 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ć kodu, więc nie mogą zawierać plików DEX. Ponadto atrybut android:hasCode znacznika <application > w manifeście musi mieć wartość false .

Definiowanie mapy zasobów

W systemie Android 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ą zostać nałożone, oraz ich wartości zastępcze, a następnie ustawienie wartości android:resourcesMap atrybut 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 manifest 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>

Budowanie 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 usuwanie zasobów bez domyślnych konfiguracji ( --no-resource-removal ). Poniższy kod przedstawia przykładowy plik Android.bp .

runtime_resource_overlay {
    name: "ExampleOverlay",
    sdk_version: "current",
}

Rozwiązywanie zasobów

Jeśli zasób docelowy lub zasób nakładkowy ma zdefiniowane wiele konfiguracji dla zasobu, którego dotyczy zapytanie, środowisko uruchomieniowe 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ładkowych z zestawem konfiguracji zasobów docelowych, a następnie postępuj zgodnie ze zwykłym przepływem rozstrzygania zasobów (szczegółowe informacje zawiera artykuł Jak system Android znajduje najlepiej pasujący zasób ).

Na przykład, jeśli nakładka definiuje wartość dla konfiguracji drawable-en , a cel definiuje wartość dla drawable-en-port , drawable-en-port ma lepsze dopasowanie, więc wartość konfiguracji docelowej drawable-en-port to wybrany w czasie wykonywania. Aby nałożyć wszystkie konfiguracje drawable-en , nakładka musi definiować wartość dla każdej konfiguracji do drawable-en którą definiuje cel.

Nakładki mogą odwoływać się do własnych zasobów, z różnymi zachowaniami w różnych wersjach Androida.

  • W systemie Android 11 lub nowszym każda nakładka ma własne zarezerwowane miejsce na identyfikator zasobu, które nie nakłada się na docelowe miejsce na identyfikator zasobu ani na inne nakładki na identyfikatory zasobów, więc nakładki odwołujące się do własnych zasobów działają zgodnie z oczekiwaniami.

  • W systemie Android 10 lub starszym nakładki i pakiety docelowe współdzielą tę samą przestrzeń identyfikatora zasobu, co może powodować kolizje i nieoczekiwane zachowanie, gdy próbują odwoływać się do własnych zasobów przy użyciu składni @type/name .

Włączanie/wyłączanie nakładek

Użyj interfejsu API OverlayManager , aby włączyć i wyłączyć modyfikowalne nakładki (pobierz interfejs API za pomocą Context#getSystemService(Context.OVERLAY_SERVICE) ). Nakładkę można włączyć tylko przez pakiet, do którego jest skierowana, lub przez pakiet z uprawnieniem android.permission.CHANGE_OVERLAY_PACKAGES . Gdy nakładka jest włączona lub wyłączona, zdarzenia zmiany konfiguracji są propagowane do pakietu docelowego, a działania docelowe są ponownie uruchamiane.

Ograniczanie zasobów, które można nakładać

W systemie Android 10 lub nowszym tag XML <overlayable> udostępnia zestaw zasobów, które RRO mogą nakładać. W poniższym przykładzie plik res/values/overlayable.xml , string/foo i integer/bar to zasoby używane do tworzenia motywów wyglądu urządzenia; aby nałożyć te zasoby, nakładka musi jawnie kierować się nazwą zbioru zasobów, które można nakładać.

<!-- 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ć unikalną nazwę w ramach pakietu. Na przykład jest to:

  • OK dla dwóch różnych pakietów do zdefiniowania <overlayable name="foo"> .

  • Niedopuszczalne jest, aby jeden plik APK miał dwa <overlayable name="foo"> .

Poniższy kod przedstawia 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 są kierowane na tę aplikację:

  • Należy określić targetName .

  • Może nakładać tylko zasoby wymienione w tagu <overlayable> .

  • Można kierować tylko na jedną nazwę <overlayable> .

Nie można włączyć nakładki ukierunkowanej na pakiet, który udostępnia zasoby, które można nakładać, ale nie używa android:targetName do kierowania na konkretny tag <overlayable> .

Zasady ograniczające

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ć dołączone zasoby. Obsługiwane typy obejmują następujące.

  • 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 partycji dostawcy może zastąpić zasoby.
  • product . Każda nakładka na partycji produktu może zastąpić zasoby.
  • oem . Każda nakładka na partycji OEM może zastąpić zasoby.
  • odm . Każda nakładka na partycji 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 znaczniku nazwanego aktora w konfiguracji systemu.
  • config_signature . Każda nakładka podpisana tym samym podpisem co apk overlay-config może zastąpić zasoby. Overlay-config jest zadeklarowany w znaczniku overlay-config-signature w konfiguracji systemu.

Poniższy kod przedstawia 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 znaków rozdzielających. Jeśli określono wiele zasad, nakładka musi spełniać tylko jedną zasadę, 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 systemu Android.

  • Urządzenia z systemem Android 11 lub nowszym mogą używać pliku OverlayConfig ( config.xml ) zamiast atrybutów manifestu. W przypadku nakładek zalecaną metodą jest użycie pliku nakładki.

  • Wszystkie urządzenia mogą używać atrybutów manifestu ( android:isStatic i android:priority ) do konfigurowania statycznych RRO.

Korzystanie z OverlayConfig

W Androidzie 11 lub nowszym możesz użyć OverlayConfig do skonfigurowania zmienności, stanu domyślnego i priorytetu nakładek. Aby skonfigurować nakładkę, utwórz lub zmodyfikuj plik znajdujący się w pliku partition/overlay/config/config.xml , gdzie partition to partycja nakładki do skonfigurowania. Aby można było skonfigurować nakładkę, musi ona znajdować się w katalogu overlay/ partycji, w której została skonfigurowana. Poniższy kod przedstawia przykładowy 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>"

Znacznik <overlay> wymaga atrybutu package wskazującego, który pakiet nakładki jest konfigurowany. Opcjonalny atrybut enable kontroluje, czy nakładka jest domyślnie enabled (wartość domyślna to false ). Opcjonalny atrybut mutable kontroluje, czy nakładka jest zmienna i czy jej włączony stan może zostać zmieniony programowo w czasie wykonywania (wartość domyślna to true ). Nakładki niewymienione w pliku konfiguracyjnym są modyfikowalne i domyślnie wyłączone.

Pierwszeństwo nakładek

Gdy wiele nakładek zastępuje te same zasoby, ważna jest kolejność nakładek. Nakładka ma wyższy priorytet niż nakładki z konfiguracjami poprzedzającymi własną konfigurację. Kolejność nakładek w różnych partycjach (od najmniejszego do największego) jest następująca.

  • system
  • vendor
  • odm
  • oem
  • product
  • system_ext

Scalanie plików

Używanie <merge> umożliwia scalanie innych plików konfiguracyjnych w określonej pozycji w pliku konfiguracyjnym. Atrybut path znacznika reprezentuje ścieżkę pliku do scalenia względem katalogu zawierającego pliki konfiguracyjne nakładek.

Używanie atrybutów manifestu (statyczne RRO)

W systemie Android 10 lub starszym niezmienność nakładek i pierwszeństwo są konfigurowane przy użyciu następujących atrybutów manifestu.

  • android:isStatic . Gdy wartość tego atrybutu logicznego jest ustawiona na true , nakładka jest domyślnie włączona i jest niezmienna, co zapobiega wyłączeniu nakładki.

  • android:priority . Wartość tego atrybutu liczbowego (który ma wpływ tylko na nakładki statyczne) konfiguruje pierwszeństwo nakładki, gdy wiele nakładek statycznych dotyczy tej samej wartości zasobu. Wyższa liczba oznacza wyższy priorytet.

Poniższy kod przedstawia 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

W systemie Android 11 lub nowszym, jeśli plik konfiguracyjny znajduje się w pliku 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.

Ponadto Android 11 lub nowszy usuwa możliwość stosowania statycznych nakładek wpływających na wartości zasobów odczytywanych podczas instalacji pakietu. W typowym przypadku użycia nakładek statycznych do zmiany wartości logicznych, które konfigurują stan włączenia składnika, użyj tagu SystemConfig <component-override> (nowość w systemie Android 11).

Debugowanie nakładek

Aby ręcznie włączyć, wyłączyć i zrzucić nakładki, użyj następującego polecenia powłoki menedżera nakładek.

adb shell cmd overlay

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 poprawnie, znajdź odpowiedni plik idmap dla nakładki w /data/resource-cache/ , a następnie uruchom następujące polecenie.

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

To polecenie drukuje 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