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

In diesem Dokument wird eine neue Jetpack-Bibliothek vorgeschlagen, um Entwickler bei der Migration zur SDK-Laufzeit zu unterstützen. Es wird erläutert, wie die SDK-Laufzeit für frühere Versionen der Android-Plattform (vom Build bis zur Ausführung) unterstützt wird und welche Unterschiede oder Einschränkungen in der Laufzeitumgebung für Entwickler zu erwarten sind. Mit dieser Bibliothek können Entwickler eine einzelne 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 folgende Komponenten erreicht:

  • Mit Android Gradle Plugin (AGP) + Bundletool wird eine App-Variante für Geräte ohne Unterstützung der SDK-Laufzeit erstellt. Dazu wird die SDK-Laufzeit im APK bündelt.

  • 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 Unterstützung der SDK-Laufzeit.

  • Die SDK-Laufzeitanbieterbibliothek (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 mit SDK-Laufzeitunterstützung 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ängig ist. Jedes SDK wird als separate APK-Aufteilung gepackt. Außerdem werden die folgenden Transformationen ausgeführt:

  1. Kopieren Sie SDK-Bytecode-Dateien (DEX) als Assets in das SDK-Split-Format.
  2. SDK-Java-Ressourcen als Assets in die SDK-Aufteilung kopieren.
  3. Ordnen Sie SDK-Ressourcen neu zu und führen Sie sie mit App-Ressourcen zusammen.
  4. Konfigurationen für die SDK-Laufzeit-Clientbibliothek generieren

SDKs mit der SDK Runtime-Clientbibliothek laden

Die Clientbibliothek der SDK-Laufzeit bietet APIs, die den Plattform-APIs ähneln. Sie unterstützt jedoch sowohl SDKs in der SDK-Laufzeitumgebung als auch SDKs, die in der Varianten-App enthalten 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 es gebündelt ist, extrahiert die Bibliothek das SDK aus dem SDK-Split und lädt es in den App-Prozess. Wenn das SDK nicht mit der App gebündelt ist, delegiert die Bibliothek die Plattform-API, um das SDK zu laden.

SDK aus Assets extrahieren

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

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

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

Classloader für SDK-Klassen

Um Konflikte zwischen SDKs und App-Klassen zu vermeiden, werden alle SDK-Klassen mit einem separaten Classloader geladen, der vollständig unabhängig vom Haupt-Classloader der 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. Mit der Binder-Transaktionsserialisierung können App-Entwickler SDK Binder-Objekte in SDK Binder Interfaces auf der App-Seite umwandeln.

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

SDK-Umgebung

Die SDKRuntime-Anbieterbibliothek stellt SDK-Entwicklern APIs zur Verfügung. Diese APIs ähneln den Plattform-APIs, ermöglichen jedoch das Laden von SDKs sowohl über die SDK-Laufzeitumgebung als auch über die SDKRuntime-Clientbibliothek.

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

Außerdem müssen Sie SandboxedSdkProviderAdapter als SDK-Anbieter verwenden, damit der kompatible Anbieter in die 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 delegiert, wenn das SDK als gebündeltes SDK geladen wird.

Bei gebündelten SDKs ändert die Bibliothek die SDK-Umgebung auf eine Weise, die ein Verhalten ähnlich wie die SDK-Laufzeitumgebung emuliert.

In den nächsten 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 während des App-Prozesses geladen wird. Bundletool führt alle SDKs-Ressourcen mit App-Ressourcen zusammen.

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

Wenn das SDK von der SDKRuntime-Clientbibliothek geladen wird, wird packageId in der Laufzeit aktualisiert, um die Adressierung neu zugeordneter Ressourcen mithilfe der R-Klasse zu ermöglichen.

Java-Ressourcen

Java-Ressourcen werden unterstützt, wenn das SDK während des Anwendungsprozesses geladen wird. Bundletool kopiert alle SDK-Java-Ressourcen in ein spezielles Verzeichnis in App-Assets. Die SDKRuntime-Clientbibliothek verwendet einen zwischengeschalteten Classloader, um alle ressourcenbezogenen Aufrufe von Java an das neue Stammverzeichnis umzuleiten.

SDK-Assets

SDK-Assets werden ohne neue Zuordnung mit App-Assets zusammengeführt.

SDK-Speicher

Zur Unterstützung von SDK Storage erstellt die SDK-Laufzeit-Clientbibliothek ein eigenes Stammverzeichnis für jedes SDK im App-Speicher und stellt einen speziellen Kontext bereit, der dieses Verzeichnis als Stammverzeichnis für die Speicherung verwendet.

Dieser Kontext kann aus 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 gerätegeschü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 Anwendungsprozess geladen werden.

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

Versionsverwaltung

Wenn die SDKRuntime-Clientbibliothek ein gebündeltes SDK lädt, wird ein Handshake mit der SDKRuntime Provider-Bibliothek im SDK durchgeführt. Während des Handshakes tauschen Bibliotheken ihre Versionen aus und passen das Verhalten so an, dass nicht verfügbare APIs durch den am besten geeigneten Fallback ersetzt werden (kein Vorgang oder Ausnahme).

Die Verwendung der neuesten Version der Bibliothek wird sowohl für App- als auch für SDK-Entwickler dringend empfohlen. Andernfalls sind Funktionen, die in beiden Bereichen unterstützt werden müssen, möglicherweise nicht verfügbar.

Jede Version der SDKRuntime-Clientbibliothek kann ein SDK mit jeder Version der SDKRuntime Provider-Bibliothek laden und umgekehrt.

Künftig wird diese Version in die minimale Version der Clientbibliothek geändert, die zum Laden des SDK mit einer bestimmten Version der Anbieterbibliothek erforderlich ist.

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