Abwärtskompatibilität für die SDK-Laufzeit

In diesem Dokument wird eine neue Jetpack-Bibliothek vorgeschlagen, die Entwicklern bei der Migration zur SDK Runtime helfen soll. Darin wird erläutert, wie die SDK Runtime für frühere Android-Plattformversionen unterstützt wird (von der Erstellung bis zur Ausführung) und welche Unterschiede oder Einschränkungen in der Laufzeitumgebung Entwickler erwarten können. Mit dieser Bibliothek können Entwickler eine einzige Version ihrer App oder ihres SDKs erstellen, die auf Geräten mit oder ohne SDK-Laufzeitunterstützung ausgeführt werden kann.

Die Abwärtskompatibilität wird durch die folgenden Komponenten erreicht:

  • Android-Gradle-Plug-in (AGP) + Bundletool erstellen eine App-Variante für Geräte ohne SDK Runtime-Unterstützung, indem sie die SDK Runtime in das APK einbinden.

  • Die SDK-Laufzeit-Clientbibliothek (androidx.privacysandbox.sdkruntime:sdkruntime-client) lädt das gebündelte SDK aus App-Assets und emuliert die SDK-Laufzeit auf Geräten ohne SDK-Laufzeitunterstützung.

  • Die SDK Runtime-Anbieterbibliothek (androidx.privacysandbox.sdkruntime:sdkruntime-provider) bietet eine API für SDKs, die das Laden aus der SDK Runtime-Clientbibliothek ermöglicht.

SDK-Bereitstellung mit Bundletool

Auf Geräten, die die SDK-Laufzeit unterstützen, werden SDKs als separate Pakete bereitgestellt und installiert.

Zur Unterstützung von Plattformversionen, die keine SDK-Laufzeit unterstützen, erstellt Bundletool eine oder mehrere Varianten des App-APK-Sets, die alle SDKs enthalten, von denen die App abhängt. Jedes SDK wird als separater APK-Split verpackt. Außerdem werden die folgenden Transformationen durchgeführt:

  1. Kopieren Sie SDK-Bytecode-Dateien (DEX) als Assets in den SDK-Split.
  2. Kopieren Sie die Java-Ressourcen des SDK als Assets in den SDK-Split.
  3. SDK-Ressourcen neu zuordnen und mit App-Ressourcen zusammenführen
  4. Konfigurationen für die SDK Runtime-Clientbibliothek generieren

SDKs mit der SDK Runtime-Clientbibliothek laden

Die SDK Runtime-Clientbibliothek bietet APIs, die Plattform-APIs ähneln, aber sowohl SDKs in der SDK Runtime-Umgebung als auch SDKs unterstützen, die mit der Variant-App gebündelt sind.

Wenn Sie die SDK Runtime-Clientbibliothek verwenden möchten, fügen Sie die Abhängigkeit androidx.privacysandbox.sdkruntime:sdkruntime-client hinzu und verwenden Sie SdkSandboxManagerCompat anstelle von SdkSandboxManager.

Wenn eine App versucht, ein SDK zu laden, prüft die Bibliothek zuerst, ob das SDK während des Builds mit der App gebündelt wurde. Wenn sie gebündelt wurde, wird das SDK aus dem SDK-Split extrahiert und in den App-Prozess geladen. Wenn das SDK nicht in die App eingebunden wurde, delegiert die Bibliothek die Plattform-API zum Laden des SDK.

SDK aus Assets extrahieren

Wenn eine App versucht, ein gebündeltes SDK zu laden, prüft die SDK Runtime-Clientbibliothek, ob die DEX-Dateien des SDK bereits in den Gerätespeicher (code_cache) extrahiert wurden. Wenn nicht, werden sie aus den Assets extrahiert.

Die Bibliothek extrahiert Dateien normalerweise nur einmal nach der Installation oder Aktualisierung einer App.

Wenn der verfügbare Speicherplatz unter dem zulässigen Grenzwert (derzeit 100 MB) liegt und keine DEX-Dateien extrahiert werden, versucht die Bibliothek, das SDK auf unterstützten Geräten (API 27+) direkt aus Assets zu laden. Dies führt zu einem größeren Speicherbedarf.

Klassenlader für SDK-Klassen

Um Konflikte zwischen SDKs und App-Klassen zu vermeiden, werden alle SDK-Klassen mit einem separaten Classloader geladen, der völlig unabhängig vom Classloader der Haupt-App ist.

Im aktuellen SDK Runtime-Design erfolgt die gesamte Kommunikation zwischen einer App und SDKs über Binder-IPC-Aufrufe. Für gebündelte SDKs werden dieselben SDK-Binder-Objekte verwendet. Durch die Serialisierung von Binder-Transaktionen können App-Entwickler SDK-Binder-Objekte auf der App-Seite in SDK-Binder-Schnittstellen umwandeln.

Für andere interne Interaktionen (z. B. Initialisieren eines SDK, Bereitstellen einer Controller-API für ein SDK usw.) verwendet die Bibliothek Reflection und Dynamic Proxies, um mit verschiedenen Classloadern zu arbeiten.

SDK-Umgebung

Die SDKRuntime Provider-Bibliothek stellt APIs für SDK-Entwickler bereit. Diese APIs ähneln Plattform-APIs, ermöglichen aber, dass SDKs sowohl von der SDK Runtime-Umgebung als auch von der SDKRuntime Client-Bibliothek geladen werden.

Wenn Sie das Bibliotheks-SDK verwenden möchten, müssen Sie die androidx.privacysandbox.sdkruntime:sdkruntime-provider-Abhängigkeit hinzufügen und SandboxedSdkProviderCompat anstelle von SandboxedSdkProvider erweitern.

Außerdem müssen Sie SandboxedSdkProviderAdapter als SDK-Anbieter verwenden, damit der Compat-Anbieter in der SDK-Laufzeitumgebung geladen werden kann.

SdkSandboxControllerCompat wird an die Plattform-API delegiert, wenn das SDK in der SDK-Laufzeit geladen wird, oder an die SDKRuntime-Clientbibliothek, wenn das SDK als gebündeltes SDK geladen wird.

Bei gebündelten SDKs ändert die Bibliothek die SDK-Umgebung so, dass das Verhalten der SDK-Laufzeitumgebung nachempfunden wird.

In den folgenden Abschnitten wird das erwartete Verhalten beschrieben, wenn das SDK von der SDKRuntime-Clientbibliothek geladen wird.

SDK-Ressourcen

SDK-Ressourcen (res/) werden unterstützt, wenn das SDK im App-Prozess geladen wird. Bundletool führt alle SDK-Ressourcen mit App-Ressourcen zusammen.

Um Konflikte zu vermeiden, werden SDK-Ressourcen neu zugeordnet, indem das Präfix packageId in allen Ressourcen-IDs geändert wird.

Wenn das SDK von der SDKRuntime-Clientbibliothek geladen wird, wird packageId in der Laufzeit aktualisiert, damit neu zugeordnete Ressourcen über die R-Klasse adressiert werden können.

Java-Ressourcen

Java-Ressourcen werden unterstützt, wenn das SDK im App-Prozess geladen wird. Bundletool kopiert alle Java-Ressourcen des SDK in ein spezielles Verzeichnis in den App-Assets. Die SDKRuntime-Clientbibliothek verwendet einen Zwischen-Klassenlader, um alle Java-Ressourcenaufrufe an das neue Stammverzeichnis umzuleiten.

SDK-Assets

SDK-Assets werden ohne Neuzuordnung mit App-Assets zusammengeführt.

SDK-Speicher

Zur Unterstützung von SDK-Speicher wird mit der SDK Runtime-Clientbibliothek für jedes gebündelte SDK im App-Speicher ein separates Stammverzeichnis erstellt. Außerdem wird ein spezieller Kontext bereitgestellt, in dem dieses Verzeichnis als Speicherstamm verwendet wird.

Dieser Kontext kann über SandboxedSdkProviderCompat#getContext abgerufen werden.

Unterstützte speicherbezogene Methoden:

  • getDataDir
  • getCacheDir
  • getCodeCacheDir
  • getNoBackupFilesDir
  • getDir
  • getFilesDir
  • openFileInput
  • openFileOutput
  • deleteFile
  • getFileStreamPath
  • fileList
  • getDatabasePath
  • openOrCreateDatabase
  • moveDatabaseFrom – nur zwischen SDK-Kontexten
  • deleteDatabase
  • databaseList
  • getSharedPreferences
  • moveSharedPreferencesFrom – nur zwischen SDK-Kontexten
  • deleteSharedPreferences

Ein durch ein Gerät geschützter Speicherkontext kann durch Aufrufen von createDeviceProtectedStorageContext() für diesen Kontext erstellt werden.

SdkSandboxControllerCompat

Die SDKRuntime-Clientbibliothek stellt die SdkSandboxControllerCompat-Implementierung für gebündelte SDKs bereit, die im App-Prozess geladen werden.

Wenn APIs von der Clientbibliothek nicht unterstützt werden (z. B. bei einem SDK, das mit einer neueren Version der Bibliothek als der App-Version erstellt wurde), wird der am besten geeignete Fallback verwendet (keine Operation oder Ausnahme).

Versionsverwaltung

Wenn die SDKRuntime-Clientbibliothek ein gebündeltes SDK lädt, führt sie einen Handshake mit der SDKRuntime-Providerbibliothek im SDK durch. Während des Handshake tauschen die Bibliotheken ihre Versionen aus und passen das Verhalten an, um nicht verfügbare APIs durch den am besten geeigneten Fallback (No-Op oder Ausnahme) zu ersetzen.

Die Verwendung der neuesten Version der Bibliothek wird sowohl für App- als auch für SDK-Entwickler dringend empfohlen, da sonst Funktionen, die Unterstützung in beiden Teilen erfordern, möglicherweise nicht verfügbar sind.

Mit jeder Version der SDKRuntime-Clientbibliothek kann ein SDK mit jeder Version der SDKRuntime-Anbieterbibliothek geladen werden und umgekehrt.

In Zukunft wird dies in die minimale Clientbibliotheksversion geändert, die zum Laden des SDK mit einer bestimmten Version der Anbieterbibliothek erforderlich ist.

So wird die Fragmentierung minimiert und es wird sichergestellt, dass die meisten APIs unterstützt werden, wenn das gebündelte SDK erfolgreich geladen wurde.