Entwicklerleitfaden zur SDK-Laufzeit

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.


Feedback geben

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

Das folgende Problem wird 2023 behoben:

  • Die APIs getAdId und getAppSetId 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:

  1. Richte deine Entwicklungsumgebung für die Privacy Sandbox für Android ein. Die Tools zur Unterstützung der SDK-Laufzeit befinden sich noch in der Entwicklungsphase. Deshalb müssen Sie in diesem 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.

  2. 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.

  1. Fügen Sie Ihrem Projekt ein App-Modul hinzu. Dieses Modul dient als Client, der das SDK steuert.
  2. Aktivieren Sie die SDK-Laufzeit in Ihrem App-Modul, deklarieren Sie die erforderlichen Berechtigungen und konfigurieren Sie API-spezifische Werbedienste.
  3. Fügen Sie Ihrem Projekt ein Bibliotheksmodul hinzu. Dieses Modul enthält deinen SDK-Code.
  4. Deklarieren Sie in Ihrem SDK-Modul die erforderlichen Berechtigungen. In diesem Modul müssen Sie keine API-spezifischen Anzeigendienste konfigurieren.
  5. Entferne das dependencies in der Datei build.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.
  6. 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 leere build.gradle-Datei hinzu. Der Inhalt dieser Datei wird später in diesem Leitfaden eingefügt.

  7. Fügen Sie der Datei gradle.properties das folgende Snippet hinzu:

    android.experimental.privacysandboxsdk.enable=true
    

  8. Laden Sie das Emulator-Image Tiramisu (Erweiterung Level 4) 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

  1. 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 Abschnitt dependencies ein.

    plugins {
        id 'com.android.privacy-sandbox-sdk'
    }
    
    android {
        compileSdk 33
        compileSdkExtension 4
        minSdk 33
        targetSdk 33
        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>')
    }
    
  2. 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 und SandboxedSdkProvider 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 neues SandboxedSdk-Objekt eingeschlossen ist. Im Leitfaden für gebundene Dienste werden verschiedene Möglichkeiten zur Bereitstellung von IBinder 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.
        }
    }
}

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:

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

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:

  1. Fügen Sie dem Manifest Ihrer App die Berechtigungen INTERNET und ACCESS_NETWORK_STATE hinzu:

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    
  2. 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 ein SurfaceView-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;
    
  3. Prüfen Sie, ob der SDK-Laufzeitprozess auf dem Gerät verfügbar ist.

    1. Prüfen Sie die SdkSandboxState-Konstante (getSdkSandboxState()). SDK_SANDBOX_STATE_ENABLED_PROCESS_ISOLATION bedeutet, dass die SDK-Laufzeit verfügbar ist.

    2. Prüfen Sie, ob loadSdk() aufgerufen wurde. Es ist erfolgreich, wenn keine Ausnahmen ausgelöst werden und der Empfänger die Instanz von SandboxedSdk ist.

      • loadSdk() im Vordergrund aufrufen. Wenn sie im Hintergrund aufgerufen wird, wird ein SecurityException ausgelöst.

      • Prüfen Sie bei OutcomeReceiver, ob eine Instanz von SandboxedSdk vorhanden ist, um festzustellen, ob eine LoadSdkException ausgelöst wurde. Eine Ausnahme weist darauf hin, dass die SDK-Laufzeit möglicherweise nicht verfügbar ist.

    Wenn der SdkSandboxState- oder loadSdk-Aufruf fehlschlägt, ist die SDK-Laufzeit nicht verfügbar und der Aufruf sollte auf das vorhandene SDK zurückgreifen.

  4. 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 die OutcomeReceiver<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()
    
  5. Initialisieren Sie in onCreate() das SdkSandboxManager 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);
    }
    
  6. 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.

  7. 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:

  1. Öffnen Sie das Android Studio-Projekt für Ihre Client-App.
  2. Wählen Sie Run > Edit Configurations (Ausführen > Konfigurationen bearbeiten) aus. Das Fenster Run/Debug Configuration wird angezeigt.
  3. Legen Sie unter Startoptionen für Start die Option Angegebene Aktivität fest.
  4. Klicken Sie auf das Dreipunkt-Menü neben „Aktivität“ und wählen Sie die Hauptaktivität für Ihren Client aus.
  5. Klicken Sie auf Übernehmen und dann auf OK.
  6. 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.

  1. 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.

  2. Installieren Sie das APK auf Ihrem Gerät:

    adb install -t /path/to/your/standalone.apk
    
  3. Klicken Sie in Android Studio auf Ausführen > Konfigurationen bearbeiten. Das Fenster Run/Debug Configuration wird angezeigt.

  4. Setzen Sie unter Installationsoptionen die Option Bereitstellen auf Standard-APK.

  5. Klicken Sie auf Übernehmen und dann auf OK.

  6. 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.

Der SDK-App-Prozess wird in einer Listenansicht unten im Dialogfeld angezeigt
Auf dem Bildschirm Prozess auswählen können Sie die SDK-App für das Debugging auswählen.

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>

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.