Guide du développeur pour le SDK Runtime

Lorsque vous lisez la documentation concernant la Privacy Sandbox sur Android, cliquez sur le bouton Preview développeur ou Bêta pour sélectionner la version du programme que vous utilisez, car les instructions peuvent varier.


Envoyer un commentaire

Le SDK Runtime permet aux SDK de s'exécuter dans un bac à sable dédié distinct de l'application appelante. Il offre des protections et des garanties améliorées concernant la collecte des données utilisateur. Pour cela, il utilise un environnement d'exécution modifié qui limite les droits d'accès aux données et l'ensemble des autorisations définies. Pour en savoir plus sur SDK Runtime, consultez la proposition de conception.

Cette page vous guide tout au long du processus de création d'un SDK compatible avec l'environnement d'exécution et qui définit une vue Web pouvant être affichée à distance dans une application appelante.

Limites connues

Pour obtenir la liste des fonctionnalités en cours de développement pour le SDK Runtime, consultez les notes de version.

Les limites suivantes devraient être corrigées dans la prochaine version majeure de la plate-forme Android.

  • Rendu des annonces dans une vue déroulante Par exemple, RecyclerView ne fonctionne pas comme prévu.
    • Vous risquez de rencontrer des à-coups lors du redimensionnement.
    • Les événements de défilement tactile de l'utilisateur ne sont pas correctement transmis dans l'environnement d'exécution.
  • API Storage

Le problème suivant sera résolu en 2023 :

  • Les API getAdId et getAppSetId ne fonctionnent pas encore correctement, car leur prise en charge n'a pas encore été activée.

Avant de commencer

Avant de commencer, procédez comme suit :

  1. Configurez votre environnement de développement pour la Privacy Sandbox sur Android. Les outils qui prennent en charge le SDK Runtime évoluent en permanence. Vous devez donc utiliser la dernière version Canary d'Android Studio. Vous pouvez exécuter cette version d'Android Studio parallèlement aux autres versions dont vous disposez. Toutefois, veuillez nous contacter si vous ne parvenez pas à remplir cette condition.

  2. Installez une image système sur un appareil compatible ou configurez un émulateur prenant en charge la Privacy Sandbox sur Android.

Configurer votre projet dans Android Studio

Pour tester le SDK Runtime, utilisez un modèle semblable au modèle client/serveur. La principale différence réside dans le fait que les applications (le "client") et les SDK (le "serveur") s'exécutent sur le même appareil.

  1. Ajoutez un module d'application à votre projet. Ce module servira de client pour piloter le SDK.
  2. Dans votre module d'application, activez le SDK Runtime, déclarez les autorisations nécessaires et configurez les services publicitaires spécifiques à l'API.
  3. Ajoutez un module de bibliothèque à votre projet. Ce module contient le code de votre SDK.
  4. Dans le module de votre SDK, déclarez les autorisations nécessaires. Vous n'avez pas besoin d'y configurer de services publicitaires spécifiques aux API.
  5. Supprimez les dependencies du fichier build.gradle du module de bibliothèque que le SDK n'utilise pas. Dans la plupart des cas, vous pouvez supprimer toutes les dépendances. Pour ce faire, créez un répertoire dont le nom correspond au SDK.
  6. Créez manuellement un module à l'aide du type com.android.privacy-sandbox-sdk. Fourni avec le code du SDK, il permet de générer un fichier APK qui pourra être déployé sur votre appareil. Pour ce faire, créez un répertoire dont le nom correspond au SDK. Ajoutez un fichier build.gradle vide. Le contenu de ce fichier sera renseigné plus loin dans ce guide.

  7. Ajoutez l'extrait suivant à votre fichier gradle.properties :

    android.experimental.privacysandboxsdk.enable=true
    
  8. Téléchargez l'image de l'émulateur TiramisuPrivacySandbox, puis créez un émulateur incluant le Play Store avec cette image.

Selon que vous êtes développeur de SDK ou d'application, la configuration finale peut être différente de celle décrite dans le paragraphe précédent.

Installez le SDK sur un appareil de test, comme vous le feriez pour une application, à l'aide d'Android Studio ou d'Android Debug Bridge (ADB). Pour vous aider à faire vos premiers pas, nous avons créé des applications exemples dans les langages de programmation Kotlin et Java. Vous les trouverez dans ce dépôt GitHub. Le fichier README et les fichiers manifestes contiennent des commentaires décrivant les éléments à modifier pour exécuter l'exemple dans les versions stables d'Android Studio.

Préparer votre SDK

  1. Créez manuellement un répertoire au niveau du module. Il servira de wrapper au code d'implémentation qui permettra de créer le fichier APK du SDK. Dans le nouveau répertoire, insérez un fichier build.gradle et ajoutez-lui l'extrait de code suivant. Attribuez un nom unique à votre SDK compatible avec l'environnement d'exécution (RE-SDK), puis indiquez une version. Incluez le module de bibliothèque dans la section dependencies.

    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>')
    }
    
  2. Créez une classe dans la bibliothèque d'implémentation. Celle-ci servira de point d'entrée pour votre SDK. Le nom de la classe doit correspondre à la valeur de sdkProviderClassName et doit étendre SandboxedSdkProvider.

Le point d'entrée de votre SDK étend SandboxedSdkProvider. L'élément SandboxedSdkProvider contient un objet Context pour votre SDK, auquel vous pouvez accéder en appelant getContext(). Ce contexte ne doit être accessible qu'une fois qu'onLoadSdk() a été appelé.

Pour que votre application SDK effectue la compilation, vous devez remplacer les méthodes de gestion du cycle de vie du SDK :

onLoadSdk()

Charge le SDK dans le bac à sable et informe l'application appelante qu'il est prêt à gérer les requêtes en transmettant son interface en tant qu'objet IBinder encapsulé dans un nouvel objet SandboxedSdk. Le guide des services liés propose différentes manières de renvoyer un objet IBinder. Vous êtes libre de choisir votre méthode, mais elle doit être cohérente avec le SDK et l'application appelante.

En utilisant AIDL comme exemple, vous devez définir un fichier AIDL pour présenter l'objet IBinder qui sera partagé et utilisé par l'appli :

// ISdkInterface.aidl
interface ISdkInterface {
    // the public functions to share with the App.
    int doSomething();
}
getView()

Crée et configure la vue pour votre annonce, l'initialise de la même manière que les autres vues Android, puis la renvoie pour qu'elle s'affiche à distance dans une fenêtre d'une largeur et d'une hauteur données en pixels.

L'extrait de code suivant montre comment remplacer ces méthodes :

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 est un wrapper de service système contextuel disponible pour les SDK. Il peut être récupéré par les SDK à l'aide du contexte reçu de SandboxedSdkProvider#getContext() et en appelant context.getSystemService(SdkSandboxController.class) au niveau de ce contexte. Le contrôleur dispose d'API qui permettent aux SDK d'interagir avec la Privacy Sandbox et d'obtenir des informations la concernant.

La plupart des API du contrôleur génèrent des exceptions si SandboxedSdkContext n'est pas le contexte utilisé. C'est pourquoi nous prévoyons de rendre bientôt le wrapper de service indisponible dans les autres contextes. SdkSandboxController est destiné aux fournisseurs de SDK et n'est pas recommandé aux développeurs d'applications.

Communication entre SDK

Les SDK dans l'environnement d'exécution doivent pouvoir communiquer entre eux pour permettre la médiation et les cas d'utilisation associés. L'ensemble d'outils décrit ici fournit une interface permettant de travailler avec les SDK mis à la disposition des autres SDK dans le bac à sable. Cette implémentation du SDK Runtime est une première étape vers la mise en œuvre de la communication entre SDK et peut ne pas couvrir tous les cas d'utilisation de la médiation dans la Privacy Sandbox.

L'API getSandboxedSdks() dans SdkSandboxController fournit une classe SandboxedSdk pour tous les SDK chargés dans la Privacy Sandbox. L'objet SandboxedSdk contient des informations sur le SDK et un élément sdkInterface permettant aux clients de communiquer avec lui.

Les SDK de la Privacy Sandbox devraient utiliser des extraits de code semblables à ceux indiqués ci-dessous pour communiquer avec d'autres SDK. Supposons que ce code soit écrit pour permettre à "SDK1" de communiquer avec "SDK2", qui sont chargés par l'application dans la Privacy Sandbox.

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);
}

Dans l'exemple ci-dessus, SDK1 ajoute la bibliothèque AIDL de SDK2 en tant que dépendance. Ce SDK client contient du code Binder généré par AIDL. Les deux SDK doivent exporter cette bibliothèque AIDL. Ce scénario est identique à ce que les applications doivent faire lorsqu'elles communiquent avec les SDK de la Privacy Sandbox.

Une fonctionnalité de partage automatique des interfaces entre les SDK sera bientôt disponible.

Les SDK dans l'environnement d'exécution ont parfois besoin de communiquer avec les dépendances d'applications et les SDK publicitaires qui ne sont pas encore compatibles avec cet environnement.

L'API registerAppOwnedSdkSandboxInterface() dans SdkSandboxManager permet aux SDK qui ne sont pas compatibles avec l'environnement d'exécution d'enregistrer leurs interfaces auprès de la plate-forme. L'API getAppOwnedSdkSandboxInterfaces() dans SdkSandboxController fournit le AppOwnedSdkSandboxInterface pour tous les SDK associés de manière statique et enregistrés.

L'exemple suivant montre comment enregistrer des interfaces pour qu'elles puissent communiquer avec les SDK compatibles avec l'environnement d'exécution :

// Register AppOwnedSdkSandboxInterface
mSdkSandboxManager.registerAppOwnedSdkSandboxInterface(
    new AppOwnedSdkSandboxInterface(
        APP_OWNED_SDK_NAME, (long) APP_OWNED_SDK_VERSION, new AppOwnedSdkApi())
    );

Cet exemple montre comment instrumenter la communication avec les SDK non compatibles avec l'environnement d'exécution :

// 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();

Étant donné que les SDK publicitaires incompatibles avec l'environnement d'exécution ne peuvent pas toujours s'enregistrer eux-mêmes, nous proposons de créer un SDK de médiation qui gère l'enregistrement et inclut les SDK de partenaire ou d'application en tant que dépendances directes. Ce SDK de médiation établira la communication entre les SDK et les dépendances qui ne sont pas compatibles avec l'environnement d'exécution et le médiateur compatible avec l'environnement d'exécution qui joue le rôle d'adaptateur.

Prise en charge des activités

Les SDK compatibles avec l'environnement d'exécution ne peuvent pas ajouter de balise d'activité à leur fichier manifeste ni démarrer leurs propres activités directement. Pour accéder à l'objet Activity, enregistrez un SdkSandboxActivityHandler et démarrez l'activité de bac à sable :

1. Enregistrer un SdkSandboxActivityHandler

Enregistrez une instance de SdkSandboxActivityHandler à l'aide de SdkSandboxController#registerSdkSandboxActivityHandler(SandboxedActivityHandler).

L'API enregistre cet objet et affiche un objet IBinder qui identifie le SdkSandboxActivityHandler transmis.

public interface SdkSandboxActivityHandler {
    void onActivityCreated(Activity activity);
}

L'API enregistre cet objet et affiche un objet IBinder qui identifie le SdkSandboxActivityHandler transmis.

2. Lancer l'activité de bac à sable

Le SDK transmet le jeton affiché à l'application cliente pour identifier le SdkSandboxActivityHandler enregistré. L'application cliente appelle ensuite SdkSandboxManager#startSdkSandboxActivity(Activity, Binder), en transmettant une activité à partir de laquelle le bac à sable peut être lancé et un jeton qui identifie le SdkSandboxActivityHandler enregistré.

Cette étape lance une nouvelle activité de plate-forme qui s'exécute dans le même SDK Runtime que le SDK à l'origine de la demande.

Lorsque l'activité commence, le SDK est averti via un appel à SdkSandboxActivityHandler#onActivityCreated(Activity) lors de l'exécution de Activity#OnCreate(Bundle).

Par exemple, avec un accès à l'objet Activity, l'appelant peut définir la contentView pour une vue en appelant Activity#setContentView(View).

Pour enregistrer des rappels de cycle de vie, utilisez Activity#registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks).

Pour enregistrer OnBackInvokedCallback dans l'activité transmise, utilisez Activity#getOnBackInvokedDispatcher().registerOnBackInvokedCallback(Int, OnBackInvokedCallback).

Tester les lecteurs vidéo dans le SDK Runtime

En plus de prendre en charge les bannières publicitaires, la Privacy Sandbox vise à permettre l'exécution des lecteurs vidéo dans le SDK Runtime.

La procédure de test des lecteurs vidéo est semblable à celle des bannières. Modifiez la méthode getView() du point d'entrée de votre SDK pour inclure un lecteur vidéo dans l'objet View renvoyé. Testez tous les flux du lecteur vidéo qui devraient être pris en charge par la Privacy Sandbox. Notez que la communication entre le SDK et l'application cliente concernant le cycle de vie de la vidéo n'est pas prise en compte. Nous n'avons donc pas encore besoin de commentaires sur cette fonctionnalité.

Vos tests et vos retours permettent d'assurer que le SDK Runtime couvrira tous les cas d'utilisation de votre lecteur vidéo de prédilection.

L'extrait de code suivant montre comment renvoyer une vue simple d'une vidéo qui se charge depuis une URL.

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;
        }
    }

Utiliser des API de stockage dans votre SDK

Les SDK exécutés dans le SDK Runtime ne peuvent plus accéder à la mémoire de stockage interne d'une application, et inversement. La lecture et l'écriture n'y sont pas possibles non plus. Le SDK Runtime dispose de sa propre zone de stockage interne. La séparation de l'application est donc garantie.

Les SDK accèdent à cette mémoire de stockage interne distincte à l'aide des API de stockage de fichiers au niveau de l'objet Context renvoyé par SandboxedSdkProvider#getContext(). Les SDK ne peuvent utiliser que la mémoire de stockage interne. Par conséquent, seules les API de stockage interne, telles que Context.getFilesDir() ou Context.getCacheDir(), fonctionnent. Consultez d'autres exemples dans la section Accès depuis la mémoire de stockage interne.

L'accès au stockage externe à partir du SDK Runtime n'est pas possible. L'appel d'API pour accéder à un stockage externe génère une exception ou renvoie null. Voici plusieurs exemples :

Dans Android 13, tous les SDK de SDK Runtime partagent la mémoire de stockage interne allouée à SDK Runtime. Le stockage est conservé jusqu'à ce que l'application cliente soit désinstallée ou que les données de l'application cliente soient nettoyées.

Vous devez utiliser l'objet Context renvoyé par SandboxedSdkProvider.getContext() pour le stockage. L'utilisation de l'API de stockage de fichiers sur une autre instance d'objet Context, telle que le contexte de l'application, ne fonctionnera pas forcément dans toutes les situations. De même, rien ne garantit qu'elle continuera à fonctionner à l'avenir.

L'extrait de code suivant montre comment utiliser le stockage dans SDK Runtime :

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);
        }
    }

}

    

Stockage par SDK

Dans la mémoire de stockage interne distincte de chaque SDK Runtime, chaque SDK dispose de son propre répertoire de stockage. Le stockage par SDK est une séparation logique de la mémoire de stockage interne du SDK Runtime, qui permet de prendre en compte la quantité d'espace de stockage utilisée par chaque SDK.

Sur Android 13, une seule API affiche un chemin d'accès vers le stockage par SDK : Context#getDataDir().

Sur Android 14, toutes les API de stockage interne de l'objet Context affichent un chemin de stockage pour chaque SDK. Vous devrez peut-être activer cette fonctionnalité en exécutant la commande adb suivante :

adb shell device_config put adservices sdksandbox_customized_sdk_context_enabled true

Lire les SharedPreferences du client

Les applications clientes peuvent choisir de partager un ensemble de clés de leurs SharedPreferences avec SdkSandbox. Les SDK peuvent lire les données synchronisées à partir de l'application cliente à l'aide de l'API SdkSanboxController#getClientSharedPreferences(). Les SharedPreferences renvoyées par cette API sont en lecture seule. Vous ne devez pas les modifier.

Accéder à l'identifiant publicitaire fourni par les services Google Play

Si votre SDK a besoin d'accéder à l'identifiant publicitaire fourni par les services Google Play :

  • Déclarez l'autorisation android.permission.ACCESS_ADSERVICES_AD_ID dans le fichier manifeste du SDK.
  • Utilisez AdIdManager#getAdId() pour récupérer la valeur de manière asynchrone.

Accéder à l'ID du groupe d'applications fourni par les services Google Play

Si votre SDK a besoin d'accéder à l'ID du groupe d'applications fourni par les services Google Play :

  • Utilisez AppSetIdManager#getAppSetId() pour récupérer la valeur de manière asynchrone.

Mettre à jour les applications clientes

Pour appeler un SDK qui s'exécute dans le SDK Runtime, apportez les modifications suivantes à l'application cliente appelante :

  1. Ajoutez les autorisations INTERNET et ACCESS_NETWORK_STATE au fichier manifeste de votre application :

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    
  2. Dans l'activité de votre application qui inclut une annonce, déclarez une référence à SdkSandboxManager, une valeur booléenne permettant de savoir si le SDK est chargé, et un objet SurfaceView pour l'affichage à distance :

    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. Déterminez si SDK Runtime est disponible sur l'appareil.

    1. Vérifiez la constante SdkSandboxState (getSdkSandboxState()). SDK_SANDBOX_STATE_ENABLED_PROCESS_ISOLATION signifie que le SDK Runtime est disponible.

    2. Vérifiez que l'appel de loadSdk() a réussi. L'appel aboutit si aucune exception n'est générée et que le destinataire est l'instance de SandboxedSdk.

      • Appelez loadSdk() au premier plan. Si vous l'appelez en arrière-plan, une exception SecurityException sera générée.

      • Recherchez une instance de SandboxedSdk dans OutcomeReceiver pour vérifier si une exception LoadSdkException a été générée. Une exception peut indiquer que SDK Runtime n'est pas disponible.

    Si l'appel de SdkSandboxState ou loadSdk échoue, SDK Runtime n'est pas disponible, et l'appel devrait être renvoyé au SDK existant.

  4. Pour définir une classe de rappel, implémentez OutcomeReceiver afin de permettre l'interaction avec le SDK dans l'environnement d'exécution après son chargement. Dans l'exemple suivant, le client utilise un rappel pour attendre le chargement complet du SDK, puis tente d'afficher une vue Web à partir du SDK. Les rappels seront définis ultérieurement dans cette étape.

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

    Pour récupérer une vue à distance à partir du SDK dans l'environnement d'exécution tout en appelant requestSurfacePackage(), implémentez l'interface OutcomeReceiver<Bundle, RequestSurfacePackageException> :

    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
            }
        }
    

    Lorsque vous avez terminé d'afficher la vue, n'oubliez pas de libérer SurfacePackage en appelant la méthode suivante :

    surfacePackage.notifyDetachedFromWindow()
    
  5. Dans onCreate(), initialisez SdkSandboxManager, les rappels nécessaires, puis exécutez une requête pour charger le 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. L'application peut choisir de partager certaines clés de ses SharedPreferences par défaut avec le bac à sable. Pour ce faire, elles peuvent appeler la méthode SdkSandboxManager#addSyncedSharedPreferencesKeys(Set<String>keys) sur n'importe quelle instance du gestionnaire SdkSandbox. Une fois que l'application indique à SdkSandboxManager les clés à synchroniser, SdkSandboxManager synchronise les valeurs de ces clés dans le bac à sable, et les SDK peuvent alors les lire à l'aide de SdkSandboxController#getClientSharedPreferences. Pour en savoir plus, consultez la section Lire les SharedPreferences du client.

    L'ensemble de clés en cours de synchronisation n'est pas conservé lors du redémarrage de l'application, et les données synchronisées avec le bac à sable sont effacées au redémarrage de ce dernier. Par conséquent, il est essentiel que l'application lance la synchronisation en appelant addSyncedSharedPreferencesKeys à chaque fois qu'elle démarre.

    Pour modifier l'ensemble de clés en cours de synchronisation, appelez SdkSandboxManager#removeSyncedSharedPreferencesKeys(Set<String>keys) afin de supprimer des clés. Pour afficher l'ensemble de clés en cours de synchronisation, utilisez SdkSandboxManager#getSyncedSharedPreferencesKeys().

    Nous vous suggérons de réduire au maximum l'ensemble de clés et de ne l'utiliser que si nécessaire. Si vous souhaitez transmettre des informations aux SDK à des fins générales, veuillez communiquer directement avec le SDK via son interface SandboxedSdk. L'un des scénarios dans lesquels ces API pourraient être utilisées est celui d'une application qui reposerait sur le SDK d'une plate-forme de gestion du consentement (PGC) et où les SDK dans le bac à sable souhaiteraient lire les magasins de données du SDK CMP dans l'élément SharedPreferences par défaut.

    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"));
    }
    
    
  7. Pour gérer les cas où le processus du bac à sable du SDK se termine de manière inattendue, définissez une implémentation pour l'interface SdkSandboxProcessDeathCallback :

    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);
              }
          }
    

    Pour enregistrer ce rappel afin de recevoir des informations sur l'arrêt du bac à sable du SDK, ajoutez la ligne suivante à tout moment :

    Kotlin

        mSdkSandboxManager.addSdkSandboxProcessDeathCallback({ obj: Runnable -> obj.run() },
                SdkSandboxLifecycleCallbackImpl())
    

    Java

        mSdkSandboxManager.addSdkSandboxProcessDeathCallback(Runnable::run,
                new SdkSandboxLifecycleCallbackImpl());
    

    Comme l'état du bac à sable est perdu lors de l'arrêt de son processus, les vues affichées à distance par le SDK peuvent ne plus fonctionner correctement. Pour continuer à interagir avec les SDK, ces vues doivent être chargées à nouveau afin qu'un nouveau processus de bac à sable soit lancé.

  8. Ajoutez une dépendance au niveau du module SDK dans le fichier build.gradle de votre application cliente :

    dependencies {
        ...
        implementation project(':<your-sdk-module>')
        ...
    }

Tester vos applications

Pour exécuter votre application cliente, installez l'application SDK et l'application cliente sur l'appareil de test à l'aide d'Android Studio ou de la ligne de commande.

Effectuer un déploiement via Android Studio

Lors du déploiement via Android Studio, procédez comme suit :

  1. Ouvrez le projet Android Studio pour votre application cliente.
  2. Accédez à Run > Edit Configurations (Exécuter > Modifier les configurations). La fenêtre Run/Debug Configuration (Configuration d'exécution/de débogage) s'affiche.
  3. Sous Launch Options (Options de lancement), définissez Launch (Lancer) sur Specified Activity (Activité spécifiée).
  4. Cliquez sur le menu à trois points à côté de l'option "Activity" (Activité), puis sélectionnez Main Activity (Activité principale) pour votre client.
  5. Cliquez sur Apply (Appliquer), puis sur OK.
  6. Cliquez sur Run (Exécuter) pour installer l'application cliente et le SDK sur l'appareil de test.

Effectuer un déploiement via la ligne de commande

Lors du déploiement à l'aide de la ligne de commande, procédez comme indiqué dans la liste suivante. Cette section suppose que le nom du module d'application SDK est sdk-app et que celui du module d'application cliente est client-app.

  1. À partir d'un terminal de ligne de commande, créez les fichiers APK du SDK Privacy Sandbox :

    ./gradlew :client-app:buildPrivacySandboxSdkApksForDebug
    

    Cette commande indique l'emplacement des fichiers APK générés. Ces fichiers APK sont signés avec votre clé de débogage locale. Vous aurez besoin de ce chemin dans la commande suivante.

  2. Installez le fichier APK sur votre appareil :

    adb install -t /path/to/your/standalone.apk
    
  3. Dans Android Studio, sélectionnez Run > Edit Configurations (Exécuter > Modifier les configurations). La fenêtre Run/Debug Configuration (Configuration d'exécution/de débogage) s'affiche.

  4. Sous Installation Options (Options d'installation), définissez Déploy (Déployer) sur Default APK (APK par défaut).

  5. Cliquez sur Apply (Appliquer), puis sur OK.

  6. Cliquez sur Run (Exécuter) pour installer le fichier APK sur votre appareil de test.

Déboguer vos applications

Pour déboguer l'application cliente, cliquez sur le bouton Debug (Déboguer) dans Android Studio.

Pour déboguer l'application SDK, accédez à Run > Attach to Process (Exécuter > Joindre au processus), qui affiche un écran pop-up (illustré ci-dessous). Cochez l'option Show all processes (Afficher tous les processus). Dans la liste qui s'affiche, recherchez un processus appelé CLIENT_APP_PROCESS_sdk_sandbox. Sélectionnez cette option et ajoutez des points d'arrêt dans le code de l'application SDK pour commencer à déboguer le SDK.

Le processus de l&#39;application SDK s&#39;affiche sous forme de liste en bas de la boîte de dialogue
Écran Choose process (Sélectionner un processus), où vous pouvez sélectionner l'application SDK à déboguer.

Démarrer et arrêter le SDK Runtime à partir de la ligne de commande

Pour lancer le processus du SDK Runtime pour votre application, utilisez la commande shell suivante :

adb shell cmd sdk_sandbox start [--user <USER_ID> | current] <CLIENT_APP_PACKAGE>

De même, pour arrêter le SDK Runtime, exécutez la commande suivante :

adb shell cmd sdk_sandbox stop [--user <USER_ID> | current] <CLIENT_APP_PACKAGE>

Vérifier quels SDK sont chargés

Pour vérifier quels SDK sont chargés, utilisez la fonctionnalité getSandboxedSdks dans SdkSandboxManager.

Limites

Pour obtenir la liste des fonctionnalités en cours de développement pour le SDK Runtime, consultez les notes de version.

Exemples de code

Pour vous aider à faire vos premiers pas, le dépôt des API de protection de la confidentialité et du SDK Runtime sur GitHub contient un ensemble de projets Android Studio individuels, y compris des exemples qui montrent comment initialiser et appeler le SDK Runtime.

Signaler des bugs et des problèmes

Vos commentaires sont essentiels pour la Privacy Sandbox sur Android. Signalez-nous les problèmes que vous rencontrez et vos idées pour améliorer Privacy Sandbox sur Android.