Wählen Sie beim Lesen der Dokumentation zur Privacy Sandbox für Android über die Schaltfläche Entwicklervorschau oder Beta die Programmversion aus, mit der Sie arbeiten. Die genaue Vorgehensweise kann variieren.
Mit der SDK-Laufzeit können SDKs in einer dedizierten Sandbox ausgeführt werden, die von der aufrufenden App getrennt ist. Die SDK-Laufzeit bietet erweiterte Absicherungen und Garantien für die Erhebung von Nutzerdaten. Dies erfolgt über eine modifizierte Ausführungsumgebung, die die Datenzugriffsrechte und die zulässigen Berechtigungen einschränkt. Weitere Informationen zur SDK-Laufzeit finden Sie im Designvorschlag.
In den Schritten auf dieser Seite wird beschrieben, wie Sie ein laufzeitfähiges SDK erstellen, das eine webbasierte Ansicht definiert, die per Remote-Zugriff in eine aufrufende App gerendert werden kann.
Bekannte Einschränkungen
In den Versionshinweisen finden Sie eine Liste der aktuell verfügbaren Funktionen der SDK-Laufzeit.
Die folgenden Einschränkungen werden voraussichtlich in der nächsten größeren Android-Plattformversion behoben.
- Anzeigen-Rendering innerhalb einer scrollbaren Ansicht Beispielsweise funktioniert
RecyclerView
nicht richtig.- Es kann zu einer Verzögerung bei der Größenanpassung kommen.
- Die Scroll-Ereignisse, die durch Tippen auf den Nutzer ausgelöst werden, werden nicht korrekt an die Laufzeit übergeben.
- Storage API
- Speicherplatz pro SDK ist unter Android 13 nicht verfügbar.
Das folgende Problem wird 2023 behoben:
- Die APIs
getAdId
undgetAppSetId
funktionieren noch nicht richtig, da die Unterstützung für diese APIs noch nicht aktiviert wurde.
Hinweis
Führen Sie die folgenden Schritte aus, bevor Sie beginnen:
Richten Sie Ihre Entwicklungsumgebung für die Privacy Sandbox für Android ein. Die Tools zur Unterstützung der SDK-Laufzeit befinden sich noch in der Entwicklungsphase. Daher müssen Sie für diesen Leitfaden die neueste Canary-Version von Android Studio verwenden. Sie können diese Version von Android Studio parallel zu anderen von Ihnen verwendeten Versionen ausführen. Teilen Sie uns daher bitte mit, wenn diese Anforderung für Sie nicht funktioniert.
Installieren Sie entweder ein System-Image auf einem unterstützten Gerät oder richten Sie einen Emulator ein, der die Privacy Sandbox für Android unterstützt.
Projekt in Android Studio einrichten
Verwenden Sie zum Testen der SDK-Laufzeit ein Modell, das dem Client-Server-Modell ähnelt. Der Hauptunterschied besteht darin, dass Apps (der Client) und SDKs (der „Server“) auf demselben Gerät ausgeführt werden.
- Fügen Sie Ihrem Projekt ein App-Modul hinzu. Dieses Modul dient als Client, der das SDK steuert.
- Aktivieren Sie die SDK-Laufzeit in Ihrem App-Modul, deklarieren Sie die erforderlichen Berechtigungen und konfigurieren Sie API-spezifische Werbedienste.
- Fügen Sie Ihrem Projekt ein Bibliotheksmodul hinzu. Dieses Modul enthält deinen SDK-Code.
- Deklarieren Sie in Ihrem SDK-Modul die erforderlichen Berechtigungen. In diesem Modul müssen Sie keine API-spezifischen Anzeigendienste konfigurieren.
- Entferne das
dependencies
in der Dateibuild.gradle
deines Bibliotheksmoduls, das nicht von deinem SDK verwendet wird. In den meisten Fällen können Sie alle Abhängigkeiten entfernen. Dazu erstellen Sie ein neues Verzeichnis, dessen Name Ihrem SDK entspricht. Erstellen Sie manuell ein neues Modul mit dem Typ
com.android.privacy-sandbox-sdk
. Diese wird mit dem SDK-Code gebündelt, um ein APK zu erstellen, das auf Ihrem Gerät bereitgestellt werden kann. Dazu erstellen Sie ein neues Verzeichnis, dessen Name Ihrem SDK entspricht. Fügen Sie eine leerebuild.gradle
-Datei hinzu. Der Inhalt dieser Datei wird später in diesem Leitfaden eingefügt.Fügen Sie der Datei
gradle.properties
das folgende Snippet hinzu:android.experimental.privacysandboxsdk.enable=true
Laden Sie das Emulator-Image für TiramisuPrivacySandbox herunter und erstellen Sie einen Emulator mit diesem Image, in dem der Play Store enthalten ist.
Je nachdem, ob Sie SDK- oder App-Entwickler sind, müssen Sie möglicherweise eine andere endgültige Einrichtung haben als im vorherigen Abschnitt beschrieben.
Installieren Sie das SDK auf einem Testgerät, ähnlich wie Sie eine App installieren. Verwenden Sie dazu entweder Android Studio oder die Android Debug Bridge (ADB). Um Ihnen den Einstieg zu erleichtern, haben wir Beispielanwendungen in den Programmiersprachen Kotlin und Java erstellt, die Sie in diesem GitHub-Repository finden. Die README-Datei und die Manifestdateien enthalten Kommentare, in denen beschrieben wird, was geändert werden muss, um das Beispiel in stabilen Versionen von Android Studio auszuführen.
SDK vorbereiten
Erstellen Sie manuell ein Verzeichnis auf Modulebene. Dies dient als Wrapper um Ihren Implementierungscode, um das SDK-APK zu erstellen. Fügen Sie im neuen Verzeichnis eine
build.gradle
-Datei hinzu und füllen Sie sie mit dem folgenden Snippet aus. Verwenden Sie einen eindeutigen Namen für Ihr laufzeitfähiges SDK (RE-SDK) und geben Sie eine Version an. Fügen Sie Ihr Bibliotheksmodul im Abschnittdependencies
ein.plugins { id 'com.android.privacy-sandbox-sdk' } android { compileSdkPreview 'TiramisuPrivacySandbox' minSdkPreview 'TiramisuPrivacySandbox' namespace = "com.example.example-sdk" bundle { packageName = "com.example.privacysandbox.provider" sdkProviderClassName = "com.example.sdk_implementation.SdkProviderImpl" setVersion(1, 0, 0) } } dependencies { include project(':<your-library-here>') }
Erstellen Sie in Ihrer Implementierungsbibliothek eine Klasse, die als Einstiegspunkt für Ihr SDK dient. Der Name der Klasse sollte dem Wert von
sdkProviderClassName
entsprechen undSandboxedSdkProvider
erweitern.
Der Einstiegspunkt für Ihr SDK ist erweitert SandboxedSdkProvider
. SandboxedSdkProvider
enthält ein Context
-Objekt für dein SDK, auf das du durch Aufrufen von getContext()
zugreifen kannst. Auf diesen Kontext darf erst zugegriffen werden, nachdem onLoadSdk()
aufgerufen wurde.
Damit Ihre SDK-App kompiliert werden kann, müssen Sie Methoden zur Verarbeitung des SDK-Lebenszyklus überschreiben:
onLoadSdk()
Lädt das SDK in die Sandbox und benachrichtigt die aufrufende App, wenn das SDK für Anfragen bereit ist, indem seine Schnittstelle als
IBinder
-Objekt übergeben wird, das in ein neuesSandboxedSdk
-Objekt eingeschlossen ist. Im Leitfaden für gebundene Dienste werden verschiedene Möglichkeiten zur Bereitstellung vonIBinder
beschrieben. Sie können die Methode flexibel wählen, diese muss jedoch für das SDK und die aufrufende Anwendung einheitlich sein.Am Beispiel von AIDL sollten Sie eine AIDL-Datei definieren, um Ihre
IBinder
zu präsentieren, die von der Anwendung freigegeben und verwendet wird:// ISdkInterface.aidl interface ISdkInterface { // the public functions to share with the App. int doSomething(); }
getView()
Erstellt und richtet die Ansicht für Ihre Anzeige ein. Initialisiert die Ansicht wie jede andere Android-Ansicht und gibt die Ansicht zurück, die remote in einem Fenster einer bestimmten Breite und Höhe in Pixeln gerendert wird.
Das folgende Code-Snippet zeigt, wie diese Methoden überschrieben werden:
Kotlin
class SdkProviderImpl : SandboxedSdkProvider() { override fun onLoadSdk(params: Bundle?): SandboxedSdk { // Returns a SandboxedSdk, passed back to the client. The IBinder used // to create the SandboxedSdk object is used by the app to call into the // SDK. return SandboxedSdk(SdkInterfaceProxy()) } override fun getView(windowContext: Context, bundle: Bundle, width: Int, height: Int): View { val webView = WebView(windowContext) val layoutParams = LinearLayout.LayoutParams(width, height) webView.setLayoutParams(layoutParams) webView.loadUrl("https://developer.android.com/privacy-sandbox") return webView } private class SdkInterfaceProxy : ISdkInterface.Stub() { fun doSomething() { // Implementation of the API. } } }
Java
public class SdkProviderImpl extends SandboxedSdkProvider { @Override public SandboxedSdk onLoadSdk(Bundle params) { // Returns a SandboxedSdk, passed back to the client. The IBinder used // to create the SandboxedSdk object is used by the app to call into the // SDK. return new SandboxedSdk(new SdkInterfaceProxy()); } @Override public View getView(Context windowContext, Bundle bundle, int width, int height) { WebView webView = new WebView(windowContext); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(width, height); webView.setLayoutParams(layoutParams); webView.loadUrl("https://developer.android.com/privacy-sandbox"); return webView; } private static class SdkInterfaceProxy extends ISdkInterface.Stub { @Override public void doSomething() { // Implementation of the API. } } }
SdkSandboxController
SdkSandboxController
ist ein kontextbasierter Systemdienst-Wrapper, der für SDKs verfügbar ist. Diese kann von SDKs mit dem von SandboxedSdkProvider#getContext()
empfangenen Kontext abgerufen werden, wobei context.getSystemService(SdkSandboxController.class)
für diesen Kontext aufgerufen wird. Der Datenverantwortliche verfügt über APIs, die SDKs helfen, mit der Privacy Sandbox zu interagieren und Informationen von dieser zu erhalten.
Die meisten APIs im Controller geben Ausnahmen aus, wenn SandboxedSdkContext
nicht der Kontext ist, der für den Zugriff verwendet wird. Der Dienst-Wrapper soll in anderen Kontexten nicht mehr verfügbar sein. SdkSandboxController
ist für die Nutzung durch SDK-Anbieter vorgesehen und nicht für App-Entwickler empfohlen.
SDK-zu-SDK-Kommunikation
SDKs in der Laufzeit sollten miteinander kommunizieren können, um die Vermittlung und verwandte Anwendungsfälle zu unterstützen. Das hier beschriebene Toolset bietet eine Schnittstelle für die Arbeit mit SDKs, die anderen SDKs in der Sandbox zur Verfügung gestellt werden. Diese Implementierung der SDK Runtime ist ein erster Schritt zur Aktivierung der SDK-zu-SDK-Kommunikation und deckt möglicherweise noch nicht alle Anwendungsfälle für die Vermittlung in der Privacy Sandbox ab.
Die getSandboxedSdks()
API in der SdkSandboxController
bietet eine SandboxedSdk
-Klasse für alle geladenen SDKs in der Privacy Sandbox. Das SandboxedSdk
-Objekt enthält Details zum SDK und ein sdkInterface
-Objekt, über das Clients damit kommunizieren können.
Von SDKs in der Privacy Sandbox wird erwartet, dass sie Code-Snippets wie die folgenden verwenden, um mit anderen SDKs zu kommunizieren. Angenommen, dieser Code wurde geschrieben, um die Kommunikation von „SDK1“ mit „SDK2“ zu ermöglichen. Beide werden von der App in der Privacy Sandbox geladen.
SdkSandboxController controller = mSdkContext
.getSystemService(SdkSandboxController.class);
List<SandboxedSdk> sandboxedSdks = controller.getSandboxedSdks();
SandboxedSdk sdk2 = sandboxedSdks.stream().filter( // The SDK it wants to
// connect to, based on SDK name or SharedLibraryInfo.
try {
IBinder binder = sdk2.getInterface();
ISdkApi sdkApi = ISdkApi.Stub.asInterface(binder);
// Call API on SDK2
message = sdkApi.getMessage();
} catch (RemoteException e) {
throw new RuntimeException(e);
}
Im obigen Beispiel fügt SDK1 die AIDL-Bibliothek von SDK2 als Abhängigkeit hinzu. Dieses Client-SDK enthält Binder-Code, der von der AIDL generiert wurde. Beide SDKs sollten diese AIDL-Bibliothek exportieren. Das entspricht dem, was Apps tun sollen, wenn sie mit SDKs in der Privacy Sandbox kommunizieren.
In einem zukünftigen Update wird eine automatisch generierte Möglichkeit zum Freigeben von Schnittstellen zwischen SDKs unterstützt.
SDKs in der Laufzeit müssen möglicherweise mit App-Abhängigkeiten und Anzeigen-SDKs kommunizieren, die noch nicht laufzeitfähig sind.
Mit der registerAppOwnedSdkSandboxInterface()
API in SdkSandboxManager
können SDKs, die nicht laufzeitfähig sind, ihre Schnittstellen bei der Plattform registrieren. Die getAppOwnedSdkSandboxInterfaces()
API in SdkSandboxController
stellt die AppOwnedSdkSandboxInterface
für alle registrierten, statisch verknüpften SDKs bereit.
Das folgende Beispiel zeigt, wie Schnittstellen registriert werden, um sie für die laufzeitfähige SDK-Kommunikation verfügbar zu machen:
// Register AppOwnedSdkSandboxInterface
mSdkSandboxManager.registerAppOwnedSdkSandboxInterface(
new AppOwnedSdkSandboxInterface(
APP_OWNED_SDK_NAME, (long) APP_OWNED_SDK_VERSION, new AppOwnedSdkApi())
);
In diesem Beispiel wird gezeigt, wie die Kommunikation mit nicht laufzeitfähigen SDKs instrumentiert wird:
// Get AppOwnedSdkSandboxInterface
List<AppOwnedSdkSandboxInterface> appOwnedSdks = mSdkContext
.getSystemService(SdkSandboxController.class)
.getAppOwnedSdkSandboxInterfaces();
AppOwnedSdkSandboxInterface appOwnedSdk = appOwnedSdks.stream()
.filter(s -> s.getName().contains(APP_OWNED_SDK_NAME))
.findAny()
.get();
IAppOwnedSdkApi appOwnedSdkApi =
IAppOwnedSdkApi.Stub.asInterface(appOwnedSdk.getInterface());
message = appOwnedSdkApi.getMessage();
Anzeigen-SDKs, die nicht laufzeitfähig sind, können sich unter Umständen nicht selbst registrieren. Daher schlagen wir die Erstellung eines Mediator-SDKs vor, das die Registrierung abwickelt und Partner- oder App-SDKs als direkte Abhängigkeiten einschließt. Dieses Mediator-SDK ermöglicht die Kommunikation zwischen nicht laufzeitfähigen SDKs und Abhängigkeiten und dem laufzeitfähigen Mediator, der als Adapter agiert.
Unterstützung bei Aktivitäten
Laufzeitfähige SDKs können ihrer Manifestdatei kein Aktivitäts-Tag hinzufügen und ihre eigenen Aktivitäten nicht direkt starten. Für den Zugriff auf das Objekt Activity
wird ein SdkSandboxActivityHandler
registriert und die Sandbox-Aktivität gestartet:
1. SdkSandboxActivityHandler registrieren
Instanz von SdkSandboxActivityHandler
mit SdkSandboxController#registerSdkSandboxActivityHandler(SandboxedActivityHandler)
registrieren
Die API registriert dieses Objekt und gibt ein IBinder
-Objekt zurück, das das übergebene SdkSandboxActivityHandler
-Objekt identifiziert.
public interface SdkSandboxActivityHandler {
void onActivityCreated(Activity activity);
}
Die API registriert dieses Objekt und gibt ein IBinder
-Objekt zurück, das das übergebene SdkSandboxActivityHandler
-Objekt identifiziert.
2. Sandbox-Aktivität starten
Das SDK übergibt das zurückgegebene Token zur Identifizierung des registrierten SdkSandboxActivityHandler
an die Client-App. Die Client-App ruft dann SdkSandboxManager#startSdkSandboxActivity(Activity, Binder)
auf und übergibt eine Aktivität, mit der die Sandbox gestartet werden soll, sowie ein Token, das das registrierte SdkSandboxActivityHandler
identifiziert.
Mit diesem Schritt wird eine neue Plattformaktivität gestartet, die in derselben SDK-Laufzeit wie das anfragende SDK ausgeführt wird.
Wenn die Aktivität beginnt, wird das SDK durch einen Aufruf von SdkSandboxActivityHandler#onActivityCreated(Activity)
im Rahmen der Ausführung von Activity#OnCreate(Bundle)
benachrichtigt.
Beispiel: Mit Zugriff auf das Activity
-Objekt und der Aufrufer kann durch Aufrufen von Activity#setContentView(View)
für contentView
eine Ansicht festlegen.
Verwenden Sie Activity#registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks)
, um Lebenszyklus-Callbacks zu registrieren.
Verwenden Sie Activity#getOnBackInvokedDispatcher().registerOnBackInvokedCallback(Int,
OnBackInvokedCallback)
, um OnBackInvokedCallback
für die bestandene Aktivität zu registrieren.
Videoplayer in der SDK-Laufzeit testen
Die Privacy Sandbox unterstützt nicht nur Banneranzeigen, sondern auch für Videoplayer, die innerhalb der SDK-Laufzeit ausgeführt werden.
Der Ablauf zum Testen von Videoplayern ähnelt dem Testen von Banneranzeigen. Ändern Sie die Methode getView()
des SDK-Einstiegspunkts so, dass das zurückgegebene View
-Objekt einen Videoplayer enthält. Testen Sie alle Abläufe im Videoplayer, die voraussichtlich von der Privacy Sandbox unterstützt werden. Die Kommunikation über den Lebenszyklus des Videos zwischen dem SDK und der Client-App ist hiervon ausgenommen. Daher ist für diese Funktion noch kein Feedback erforderlich.
Durch deine Tests und dein Feedback wird sichergestellt, dass die SDK-Laufzeit alle Anwendungsfälle deines bevorzugten Videoplayers unterstützt.
Das folgende Code-Snippet zeigt, wie eine einfache Videoansicht zurückgegeben wird, die über eine URL geladen wird.
Kotlin
class SdkProviderImpl : SandboxedSdkProvider() { override fun getView(windowContext: Context, bundle: Bundle, width: Int, height: Int): View { val videoView = VideoView(windowContext) val layoutParams = LinearLayout.LayoutParams(width, height) videoView.setLayoutParams(layoutParams) videoView.setVideoURI(Uri.parse("https://test.website/video.mp4")) videoView.setOnPreparedListener { mp -> mp.start() } return videoView } }
Java
public class SdkProviderImpl extends SandboxedSdkProvider { @Override public View getView(Context windowContext, Bundle bundle, int width, int height) { VideoView videoView = new VideoView(windowContext); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(width, height); videoView.setLayoutParams(layoutParams); videoView.setVideoURI(Uri.parse("https://test.website/video.mp4")); videoView.setOnPreparedListener(mp -> { mp.start(); }); return videoView; } }
Speicher-APIs in Ihrem SDK verwenden
SDKs in der SDK-Laufzeit können nicht mehr auf den internen Speicher einer App zugreifen, diesen lesen oder schreiben und umgekehrt. Der SDK-Laufzeit wird ein eigener interner Speicherbereich zugewiesen, der unbedingt von der Anwendung getrennt ist.
SDKs können über die Dateispeicher-APIs im Context
-Objekt, das von SandboxedSdkProvider#getContext()
zurückgegeben wird, auf diesen separaten internen Speicher zugreifen. SDKs können nur internen Speicher verwenden, daher funktionieren nur interne Speicher-APIs wie Context.getFilesDir()
oder Context.getCacheDir()
. Weitere Beispiele finden Sie unter Zugriff über den internen Speicher.
Der Zugriff auf externen Speicher über die SDK-Laufzeit wird nicht unterstützt. Wenn APIs aufgerufen werden, um auf den externen Speicher zuzugreifen, wird entweder eine Ausnahme ausgelöst oder null
zurückgegeben. Hier einige Beispiele:
- Beim Zugriff auf Dateien mit dem Storage Access Framework wird ein
SecurityException
ausgegeben. getExternalFilsDir()
gibt immernull
zurück.
In Android 13 teilen sich alle SDKs in der SDK-Laufzeit den internen Speicher, der für die SDK-Laufzeit zugewiesen ist. Der Speicher bleibt bestehen, bis die Clientanwendung deinstalliert oder die Daten der Clientanwendung bereinigt werden.
Sie müssen das von SandboxedSdkProvider.getContext()
zurückgegebene Context
für den Speicher verwenden. Die Verwendung der File Storage API auf einer anderen Context
-Objektinstanz, z. B. im Anwendungskontext, funktioniert möglicherweise nicht in allen Situationen oder in Zukunft wie erwartet.
Das folgende Code-Snippet zeigt, wie Speicher in der SDK-Laufzeit verwendet wird:
Kotlin
private static class SdkInterfaceStorage extends ISdkInterface.Stub { override fun doSomething() { val filename = "myfile" val fileContents = "content" try { getContext().openFileOutput(filename, Context.MODE_PRIVATE).use { it.write(fileContents.toByteArray()) } catch (e: Exception) { throw RuntimeException(e) } } } }
Java
private static class SdkInterfaceStorage extends ISdkInterface.Stub { @Override public void doSomething() { final filename = "myFile"; final String fileContents = "content"; try (FileOutputStream fos = getContext().openFileOutput(filename, Context.MODE_PRIVATE)) { fos.write(fileContents.toByteArray()); } catch (Exception e) { throw new RuntimeException(e); } } }
Speicher pro SDK
Innerhalb des separaten internen Speichers für jede SDK-Laufzeit hat jedes SDK ein eigenes Speicherverzeichnis. Der Speicher pro SDK ist eine logische Trennung des internen Speichers der SDK-Laufzeit, der berücksichtigt, wie viel Speicherplatz von den einzelnen SDKs verwendet wird.
In Android 13 gibt nur eine API einen Pfad zum SDK-Speicher zurück: Context#getDataDir()
.
Unter Android 14 geben alle internen Speicher-APIs im Context
-Objekt einen Speicherpfad für jedes SDK zurück. Möglicherweise müssen Sie diese Funktion aktivieren, indem Sie den folgenden ADB-Befehl ausführen:
adb shell device_config put adservices sdksandbox_customized_sdk_context_enabled true
SharedPreferences
des Kunden wird gelesen
Client-Apps können einen Satz von Schlüsseln aus ihrem SharedPreferences
für SdkSandbox
freigeben. SDKs können die von der Client-App synchronisierten Daten mithilfe der SdkSanboxController#getClientSharedPreferences()
API lesen. Die von dieser API zurückgegebenen SharedPreferences
dienen nur zum Lesen. Sie sollten nicht in diese E-Mail schreiben.
Auf die Werbe-ID der Google Play-Dienste zugreifen
Wenn Ihr SDK auf die von den Google Play-Diensten bereitgestellte Werbe-ID zugreifen muss, gehen Sie so vor:
- Deklariere die Berechtigung
android.permission.ACCESS_ADSERVICES_AD_ID
im Manifest des SDK. - Verwenden Sie
AdIdManager#getAdId()
, um den Wert asynchron abzurufen.
Auf die von den Google Play-Diensten bereitgestellte App-Set-ID zugreifen
Wenn Ihr SDK Zugriff auf die von den Google Play-Diensten bereitgestellte App-Set-ID benötigt:
- Verwenden Sie
AppSetIdManager#getAppSetId()
, um den Wert asynchron abzurufen.
Client-Apps aktualisieren
Wenn Sie ein SDK aufrufen möchten, das in der SDK-Laufzeit ausgeführt wird, nehmen Sie die folgenden Änderungen an der aufrufenden Client-App vor:
Fügen Sie dem Manifest Ihrer App die Berechtigungen
INTERNET
undACCESS_NETWORK_STATE
hinzu:<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Deklarieren Sie in den Aktivitäten Ihrer App, die eine Anzeige enthalten, einen Verweis auf
SdkSandboxManager
, einen booleschen Wert, mit dem angegeben wird, ob das SDK geladen wird, und einSurfaceView
-Objekt für Remote-Rendering:Kotlin
private lateinit var mSdkSandboxManager: SdkSandboxManager private lateinit var mClientView: SurfaceView private var mSdkLoaded = false companion object { private const val SDK_NAME = "com.example.privacysandbox.provider" }
Java
private static final String SDK_NAME = "com.example.privacysandbox.provider"; private SdkSandboxManager mSdkSandboxManager; private SurfaceView mClientView; private boolean mSdkLoaded = false;
Prüfen Sie, ob der SDK-Laufzeitprozess auf dem Gerät verfügbar ist.
Prüfen Sie die
SdkSandboxState
-Konstante (getSdkSandboxState()
).SDK_SANDBOX_STATE_ENABLED_PROCESS_ISOLATION
bedeutet, dass die SDK-Laufzeit verfügbar ist.Prüfen Sie, ob
loadSdk()
aufgerufen wurde. Es ist erfolgreich, wenn keine Ausnahmen ausgelöst werden und der Empfänger die Instanz vonSandboxedSdk
ist.loadSdk()
im Vordergrund aufrufen. Wenn sie im Hintergrund aufgerufen wird, wird einSecurityException
ausgelöst.Prüfen Sie bei
OutcomeReceiver
, ob eine Instanz vonSandboxedSdk
vorhanden ist, um festzustellen, ob eineLoadSdkException
ausgelöst wurde. Eine Ausnahme weist darauf hin, dass die SDK-Laufzeit möglicherweise nicht verfügbar ist.
Wenn der
SdkSandboxState
- oderloadSdk
-Aufruf fehlschlägt, ist die SDK-Laufzeit nicht verfügbar und der Aufruf sollte auf das vorhandene SDK zurückgreifen.Definieren Sie eine Callback-Klasse, indem Sie
OutcomeReceiver
implementieren, um nach dem Laden in der Laufzeit mit dem SDK zu interagieren. Im folgenden Beispiel verwendet der Client einen Callback, um zu warten, bis das SDK erfolgreich geladen wurde, und versucht dann, eine Webansicht aus dem SDK zu rendern. Die Callbacks werden später in diesem Schritt definiert.Kotlin
private inner class LoadSdkOutcomeReceiverImpl private constructor() : OutcomeReceiver
{ override fun onResult(sandboxedSdk: SandboxedSdk) { mSdkLoaded = true val binder: IBinder = sandboxedSdk.getInterface() if (!binderInterface.isPresent()) { // SDK is not loaded anymore. return } val sdkInterface: ISdkInterface = ISdkInterface.Stub.asInterface(binder) sdkInterface.doSomething() Handler(Looper.getMainLooper()).post { val bundle = Bundle() bundle.putInt(SdkSandboxManager.EXTRA_WIDTH_IN_PIXELS, mClientView.getWidth()) bundle.putInt(SdkSandboxManager.EXTRA_HEIGHT_IN_PIXELS, mClientView.getHeight()) bundle.putInt(SdkSandboxManager.EXTRA_DISPLAY_ID, display!!.displayId) bundle.putInt(SdkSandboxManager.EXTRA_HOST_TOKEN, mClientView.getHostToken()) mSdkSandboxManager!!.requestSurfacePackage( SDK_NAME, bundle, { obj: Runnable -> obj.run() }, RequestSurfacePackageOutcomeReceiverImpl()) } } override fun onError(error: LoadSdkException) { // Log or show error. } } Java
import static android.app.sdksandbox.SdkSandboxManager.EXTRA_DISPLAY_ID; import static android.app.sdksandbox.SdkSandboxManager.EXTRA_HEIGHT_IN_PIXELS; import static android.app.sdksandbox.SdkSandboxManager.EXTRA_HOST_TOKEN; import static android.app.sdksandbox.SdkSandboxManager.EXTRA_WIDTH_IN_PIXELS; private class LoadSdkOutcomeReceiverImpl implements OutcomeReceiver
{ private LoadSdkOutcomeReceiverImpl() {} @Override public void onResult(@NonNull SandboxedSdk sandboxedSdk) { mSdkLoaded = true; IBinder binder = sandboxedSdk.getInterface(); if (!binderInterface.isPresent()) { // SDK is not loaded anymore. return; } ISdkInterface sdkInterface = ISdkInterface.Stub.asInterface(binder); sdkInterface.doSomething(); new Handler(Looper.getMainLooper()).post(() -> { Bundle bundle = new Bundle(); bundle.putInt(EXTRA_WIDTH_IN_PIXELS, mClientView.getWidth()); bundle.putInt(EXTRA_HEIGHT_IN_PIXELS, mClientView.getHeight()); bundle.putInt(EXTRA_DISPLAY_ID, getDisplay().getDisplayId()); bundle.putInt(EXTRA_HOST_TOKEN, mClientView.getHostToken()); mSdkSandboxManager.requestSurfacePackage( SDK_NAME, bundle, Runnable::run, new RequestSurfacePackageOutcomeReceiverImpl()); }); } @Override public void onError(@NonNull LoadSdkException error) { // Log or show error. } } Wenn Sie beim Aufrufen von
requestSurfacePackage()
vom SDK eine Remote-Ansicht zurückgeben möchten, implementieren Sie dieOutcomeReceiver<Bundle, RequestSurfacePackageException>
-Schnittstelle:Kotlin
private inner class RequestSurfacePackageOutcomeReceiverImpl : OutcomeReceiver
{ fun onResult(@NonNull result: Bundle) { Handler(Looper.getMainLooper()) .post { val surfacePackage: SurfacePackage = result.getParcelable( EXTRA_SURFACE_PACKAGE, SurfacePackage::class.java) mRenderedView.setChildSurfacePackage(surfacePackage) mRenderedView.setVisibility(View.VISIBLE) } } fun onError(@NonNull error: RequestSurfacePackageException?) { // Error handling } } Java
import static android.app.sdksandbox.SdkSandboxManager.EXTRA_SURFACE_PACKAGE; private class RequestSurfacePackageOutcomeReceiverImpl implements OutcomeReceiver
{ @Override public void onResult(@NonNull Bundle result) { new Handler(Looper.getMainLooper()) .post( () -> { SurfacePackage surfacePackage = result.getParcelable( EXTRA_SURFACE_PACKAGE, SurfacePackage.class); mRenderedView.setChildSurfacePackage(surfacePackage); mRenderedView.setVisibility(View.VISIBLE); }); } @Override public void onError(@NonNull RequestSurfacePackageException error) { // Error handling } } Wenn die Ansicht nicht mehr angezeigt wird, denken Sie daran,
SurfacePackage
durch folgenden Aufruf freizugeben:surfacePackage.notifyDetachedFromWindow()
Initialisieren Sie in
onCreate()
dasSdkSandboxManager
und die erforderlichen Callbacks und stellen Sie dann eine Anfrage zum Laden des SDK:Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) mSdkSandboxManager = applicationContext.getSystemService( SdkSandboxManager::class.java ) mClientView = findViewById(R.id.rendered_view) mClientView.setZOrderOnTop(true) val loadSdkCallback = LoadSdkCallbackImpl() mSdkSandboxManager.loadSdk( SDK_NAME, Bundle(), { obj: Runnable -> obj.run() }, loadSdkCallback ) }
Java
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mSdkSandboxManager = getApplicationContext().getSystemService( SdkSandboxManager.class); mClientView = findViewById(R.id.rendered_view); mClientView.setZOrderOnTop(true); LoadSdkCallbackImpl loadSdkCallback = new LoadSdkCallbackImpl(); mSdkSandboxManager.loadSdk( SDK_NAME, new Bundle(), Runnable::run, loadSdkCallback); }
Die App kann bestimmte Schlüssel des Standard-
SharedPreferences
für die Sandbox freigeben. Dazu rufen sie die MethodeSdkSandboxManager#addSyncedSharedPreferencesKeys(Set<String>keys)
in einer beliebigen Instanz vonSdkSandbox
Manager auf. Sobald die AppSdkSandboxManager
benachrichtigt, welche Schlüssel synchronisiert werden sollen, synchronisiertSdkSandboxManager
die Werte dieser Schlüssel mit der Sandbox und den SDKs und kann sie dann mitSdkSandboxController#getClientSharedPreferences
lesen. Weitere Informationen finden Sie unter SharedPreferences des Clients lesen.Die zu synchronisierenden Schlüssel werden nach einem App-Neustart nicht beibehalten und mit der Sandbox synchronisierte Daten werden beim Neustart der Sandbox gelöscht. Daher ist es wichtig, dass die Anwendung die Synchronisierung initiiert, indem sie bei jedem Start der Anwendung
addSyncedSharedPreferencesKeys
aufruft.Sie können den zu synchronisierenden Schlüsselsatz ändern, indem Sie
SdkSandboxManager#removeSyncedSharedPreferencesKeys(Set<String>keys)
aufrufen, um die Schlüssel zu entfernen. Wenn Sie den aktuell zu synchronisierenden Satz von Schlüsseln ansehen möchten, verwenden SieSdkSandboxManager#getSyncedSharedPreferencesKeys()
.Wir empfehlen, den Schlüsselsatz so klein wie möglich zu halten und nur bei Bedarf zu verwenden. Wenn du Informationen zu allgemeinen Zwecken an SDKs weitergeben möchtest, kommuniziere bitte direkt mit dem SDK über dessen
SandboxedSdk
-Schnittstelle. Ein mögliches Szenario für die Verwendung dieser APIs wäre, wenn in der App ein CMP SDK (Consent Management Platform) verwendet wird. SDKs in der Sandbox sind dann daran interessiert, die Daten aus CMP SDK-Speichern im standardmäßigenSharedPreferences
zu lesen.Kotlin
override fun onCreate(savedInstanceState: Bundle?) { … // At some point, initiate the set of keys for synchronization with sandbox mSdkSandboxManager.addSyncedSharedPreferencesKeys(Set.of("foo", "bar")); }
Java
@Override protected void onCreate(Bundle savedInstanceState) { … // At some point, initiate the set of keys for synchronization with sandbox mSdkSandboxManager.addSyncedSharedPreferencesKeys(Set.of("foo", "bar")); }
Definieren Sie eine Implementierung für die
SdkSandboxProcessDeathCallback
-Schnittstelle, um den Fall zu handhaben, dass der SDK-Sandbox-Prozess unerwartet beendet wird:Kotlin
private inner class SdkSandboxLifecycleCallbackImpl() : SdkSandboxProcessDeathCallback { override fun onSdkSandboxDied() { // The SDK runtime process has terminated. To bring back up the // sandbox and continue using SDKs, load the SDKs again. val loadSdkCallback = LoadSdkOutcomeReceiverImpl() mSdkSandboxManager.loadSdk( SDK_NAME, Bundle(), { obj: Runnable -> obj.run() }, loadSdkCallback) } }
Java
private class SdkSandboxLifecycleCallbackImpl implements SdkSandboxProcessDeathCallback { @Override public void onSdkSandboxDied() { // The SDK runtime process has terminated. To bring back up // the sandbox and continue using SDKs, load the SDKs again. LoadSdkOutcomeReceiverImpl loadSdkCallback = new LoadSdkOutcomeReceiverImpl(); mSdkSandboxManager.loadSdk( SDK_NAME, new Bundle(), Runnable::run, loadSdkCallback); } }
Du kannst diesen Callback registrieren, um Informationen darüber zu erhalten, wann die SDK-Sandbox beendet wurde. Füge dazu jederzeit die folgende Zeile hinzu:
Kotlin
mSdkSandboxManager.addSdkSandboxProcessDeathCallback({ obj: Runnable -> obj.run() }, SdkSandboxLifecycleCallbackImpl())
Java
mSdkSandboxManager.addSdkSandboxProcessDeathCallback(Runnable::run, new SdkSandboxLifecycleCallbackImpl());
Da der Status der Sandbox beim Beenden ihres Prozesses verloren geht, funktionieren Ansichten, die vom SDK remote gerendert wurden, möglicherweise nicht mehr korrekt. Um weiterhin mit SDKs interagieren zu können, müssen diese Ansichten noch einmal geladen werden, damit ein neuer Sandbox-Prozess gestartet wird.
Fügen Sie der
build.gradle
Ihrer Client-App eine Abhängigkeit von Ihrem SDK-Modul hinzu:dependencies { ... implementation project(':<your-sdk-module>') ... }
Apps testen
Installieren Sie zum Ausführen der Client-App die SDK-App und die Client-App auf dem Testgerät. Verwenden Sie dazu Android Studio oder die Befehlszeile.
Über Android Studio bereitstellen
Führen Sie bei der Bereitstellung über Android Studio die folgenden Schritte aus:
- Öffnen Sie das Android Studio-Projekt für Ihre Client-App.
- Wählen Sie Run > Edit Configurations (Ausführen > Konfigurationen bearbeiten) aus. Das Fenster Run/Debug Configuration wird angezeigt.
- Legen Sie unter Startoptionen für Start die Option Angegebene Aktivität fest.
- Klicken Sie auf das Dreipunkt-Menü neben „Aktivität“ und wählen Sie die Hauptaktivität für Ihren Client aus.
- Klicken Sie auf Übernehmen und dann auf OK.
- Klicke auf Ausführen , um die Client-App und das SDK auf deinem Testgerät zu installieren.
Über die Befehlszeile bereitstellen
Führen Sie bei der Bereitstellung über die Befehlszeile die Schritte in der folgenden Liste aus.
In diesem Abschnitt wird davon ausgegangen, dass der Name des SDK-App-Moduls sdk-app
und der Name des Client-App-Moduls client-app
lautet.
Erstellen Sie über ein Befehlszeilenterminal die Privacy Sandbox SDK-APKs:
./gradlew :client-app:buildPrivacySandboxSdkApksForDebug
Dadurch wird der Standort für die generierten APKs ausgegeben. Diese APKs sind mit Ihrem lokalen Schlüssel zur Fehlerbehebung signiert. Sie benötigen diesen Pfad im nächsten Befehl.
Installieren Sie das APK auf Ihrem Gerät:
adb install -t /path/to/your/standalone.apk
Klicken Sie in Android Studio auf Ausführen > Konfigurationen bearbeiten. Das Fenster Run/Debug Configuration wird angezeigt.
Setzen Sie unter Installationsoptionen die Option Bereitstellen auf Standard-APK.
Klicken Sie auf Übernehmen und dann auf OK.
Klicken Sie auf Ausführen, um das APK-Bundle auf Ihrem Testgerät zu installieren.
Fehler in Apps beheben
Klicken Sie zum Debuggen der Client-App in Android Studio auf die Schaltfläche Debug (Fehlerbehebung).
Um Fehler in der SDK-App zu beheben, rufen Sie Run > Attach to Process (Ausführen > An Prozess anhängen) auf, wodurch ein Pop-up-Bildschirm angezeigt wird (siehe unten). Klicken Sie das Kästchen Alle Prozesse anzeigen an. Suchen Sie in der angezeigten Liste nach einem Prozess mit dem Namen CLIENT_APP_PROCESS_sdk_sandbox
. Wählen Sie diese Option aus und fügen Sie dem Code der SDK-App Haltepunkte hinzu, um mit dem Debuggen in Ihrem SDK zu beginnen.
SDK-Laufzeit über die Befehlszeile starten und beenden
Verwenden Sie den folgenden Shell-Befehl, um den SDK-Laufzeitprozess für Ihre App zu starten:
adb shell cmd sdk_sandbox start [--user <USER_ID> | current] <CLIENT_APP_PACKAGE>
Führen Sie in ähnlicher Weise den folgenden Befehl aus, um den SDK-Laufzeitprozess zu beenden:
adb shell cmd sdk_sandbox stop [--user <USER_ID> | current] <CLIENT_APP_PACKAGE>
Prüfen, welche SDKs derzeit geladen sind
Mit der getSandboxedSdks
-Funktion in der SdkSandboxManager
können Sie prüfen, welche SDKs derzeit geladen sind.
Beschränkungen
Eine Liste der aktuell verfügbaren Funktionen der SDK-Laufzeit finden Sie in den Versionshinweisen.
Codebeispiele
Das Repository für SDK Runtime and Privacy Preserving APIs auf GitHub enthält eine Reihe einzelner Android Studio-Projekte für den Einstieg, einschließlich Beispielen, die zeigen, wie die SDK-Laufzeit initialisiert und aufgerufen wird.Fehler und Probleme melden
Dein Feedback ist wichtig für die Privacy Sandbox für Android. Teilen Sie uns bitte mit, wenn Sie Probleme finden oder Ideen zur Verbesserung der Privacy Sandbox für Android haben.
Persönliche Empfehlungen
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- SDK-Laufzeit
- Versionshinweise
- Entwicklerleitfaden für die Protected Audience API auf Android