Mentre leggi la documentazione di Privacy Sandbox su Android, utilizza il pulsante Anteprima per sviluppatori o Beta per selezionare la versione del programma che stai utilizzando, poiché le istruzioni possono variare.
SDK Runtime consente l'esecuzione degli SDK in una sandbox dedicata, separata dall'app chiamante. SDK Runtime fornisce salvaguardie e garanzie avanzate per la raccolta dei dati utente. Ciò avviene attraverso un ambiente di esecuzione modificato che limita i diritti di accesso ai dati e l'insieme di autorizzazioni consentite. Scopri di più su SDK Runtime nella proposta di progettazione.
I passaggi in questa pagina illustrano la procedura di creazione di un SDK abilitato per runtime che definisce una vista basata sul web di cui è possibile eseguire il rendering da remoto in un'app per chiamate.
Limitazioni note
Per un elenco delle funzionalità in corso per SDK Runtime, visualizza le note di rilascio.
Le seguenti limitazioni dovrebbero essere risolte nella prossima release principale della piattaforma Android.
- Rendering dell'annuncio in una visualizzazione scorrevole. Ad esempio,
RecyclerView
non funziona correttamente.- Potresti riscontrare rallentamenti al momento del ridimensionamento.
- Gli eventi di scorrimento al tocco dell'utente non vengono trasmessi correttamente al runtime.
- API Storage
- Lo spazio di archiviazione per SDK non è disponibile su Android 13.
Il seguente problema verrà risolto nel 2023:
- Le API
getAdId
egetAppSetId
non funzionano ancora correttamente perché il relativo supporto non è ancora stato attivato.
Prima di iniziare
Prima di iniziare, completa i seguenti passaggi:
Configura il tuo ambiente di sviluppo per Privacy Sandbox su Android. Gli strumenti per il supporto di SDK Runtime sono in fase di sviluppo attivo, pertanto questa guida richiede l'utilizzo dell'ultima versione canary di Android Studio. Puoi eseguire questa versione di Android Studio in parallelo ad altre versioni che utilizzi, quindi contattaci se questo requisito non funziona per te.
Installa un'immagine di sistema su un dispositivo supportato o configura un emulatore che includa il supporto di Privacy Sandbox su Android.
Configurare il progetto in Android Studio
Per provare SDK Runtime, utilizza un modello simile al modello client-server. La differenza principale è che le app (il client) e gli SDK (il "server") vengono eseguiti sullo stesso dispositivo.
- Aggiungi un modulo dell'app al tuo progetto. Questo modulo funge da client che gestisce l'SDK.
- Nel modulo dell'app, attiva SDK Runtime, dichiara le autorizzazioni necessarie e configura i servizi pubblicitari specifici per l'API.
- Aggiungi un modulo della libreria al tuo progetto. Questo modulo contiene il tuo codice SDK.
- Nel modulo SDK, dichiara le autorizzazioni necessarie. In questo modulo non è necessario configurare i servizi pubblicitari specifici dell'API.
- Rimuovi
dependencies
dal filebuild.gradle
del modulo della libreria che non utilizza il tuo SDK. Nella maggior parte dei casi, puoi rimuovere tutte le dipendenze. Puoi farlo creando una nuova directory il cui nome corrisponde a quello del tuo SDK. Crea manualmente un nuovo modulo utilizzando il tipo
com.android.privacy-sandbox-sdk
. Questo codice viene fornito insieme al codice SDK per creare un APK che può essere implementato sul tuo dispositivo. Puoi farlo creando una nuova directory il cui nome corrisponde al tuo SDK. Aggiungi un filebuild.gradle
vuoto. I contenuti di questo file verranno completati più avanti in questa guida.Aggiungi il seguente snippet al tuo file
gradle.properties
:android.experimental.privacysandboxsdk.enable=true
Scarica l'immagine dell'emulatore TiramisuPrivacySandbox e crea un emulatore con questa immagine che includa il Play Store.
A seconda che tu sia uno sviluppatore di SDK o di app, potresti avere una configurazione finale diversa da quella descritta nel paragrafo precedente.
Installa l'SDK su un dispositivo di test, utilizzando Android Studio o Android Debug Bridge (ADB) in modo simile a come installeresti un'app. Per aiutarti a iniziare, abbiamo creato app di esempio nei linguaggi di programmazione Kotlin e Java, che puoi trovare in questo repository di GitHub. Il file README e il file manifest contengono commenti che descrivono cosa deve essere modificato per eseguire l'esempio nelle versioni stabili di Android Studio.
Prepara l'SDK
Crea manualmente una directory a livello di modulo. Questo serve da wrapper intorno al codice di implementazione per creare l'APK dell'SDK. Nella nuova directory, aggiungi un file
build.gradle
e compilalo con il seguente snippet. Utilizza un nome univoco per il tuo SDK (RE-SDK) abilitato per il runtime e fornisci una versione. Includi il modulo della tua libreria nella sezionedependencies
.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>') }
Crea una classe nella libreria di implementazione da utilizzare come punto di ingresso per l'SDK. Il nome della classe deve essere mappato al valore di
sdkProviderClassName
ed estendereSandboxedSdkProvider
.
Il punto di ingresso per il tuo SDK estende SandboxedSdkProvider
. SandboxedSdkProvider
contiene un oggetto Context
per il tuo SDK, a cui puoi accedere chiamando getContext()
. È possibile accedere a questo contesto solo dopo aver richiamato onLoadSdk()
.
Per completare la compilazione dell'app SDK, devi eseguire l'override dei metodi per gestire il ciclo di vita dell'SDK:
onLoadSdk()
Carica l'SDK nella sandbox e avvisa l'app chiamante quando è pronto a gestire le richieste passando la propria interfaccia come un oggetto
IBinder
aggregato all'interno di un nuovo oggettoSandboxedSdk
. La guida ai servizi associati offre diversi modi per fornireIBinder
. Puoi scegliere la modalità che preferisci, ma deve essere coerente per l'SDK e l'app per le chiamate.Utilizzando AIDL come esempio, dovresti definire un file AIDL per presentare
IBinder
, che sarà condiviso e utilizzato dall'app:// ISdkInterface.aidl interface ISdkInterface { // the public functions to share with the App. int doSomething(); }
getView()
Crea e imposta la visualizzazione per l'annuncio, inizializzala come qualsiasi altra visualizzazione Android e restituisce la visualizzazione da eseguire in remoto in una finestra con una determinata larghezza e altezza in pixel.
Lo snippet di codice riportato di seguito mostra come eseguire l'override di questi metodi:
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
è un wrapper di servizio di sistema basato sul contesto disponibile
per gli SDK. Può essere recuperato dagli SDK utilizzando il contesto ricevuto da SandboxedSdkProvider#getContext()
e richiamando context.getSystemService(SdkSandboxController.class)
in questo contesto. Il controller dispone di API che consentono agli SDK di interagire con Privacy Sandbox e ottenerne informazioni.
La maggior parte delle API nel controller genera eccezioni se SandboxedSdkContext
non è il contesto utilizzato per accedere. Prevediamo di rendere il wrapper del servizio non disponibile
in altri contesti. SdkSandboxController
è destinato all'utilizzo da parte dei provider di SDK e non è consigliato per gli sviluppatori di app.
Comunicazione tra SDK e SDK
Gli SDK nel runtime devono essere in grado di comunicare tra loro per supportare la mediazione e i relativi casi d'uso. Il set di strumenti descritto qui fornisce un'interfaccia per lavorare con gli SDK resi disponibili ad altri SDK nella sandbox. Questa implementazione di SDK Runtime è un primo passo per consentire la comunicazione tra SDK e SDK e potrebbe non riguardare ancora tutti i casi d'uso per la mediazione in Privacy Sandbox.
L'API getSandboxedSdks()
in SdkSandboxController
fornisce una
classe SandboxedSdk
per tutti gli SDK caricati in Privacy Sandbox. L'oggetto SandboxedSdk
contiene dettagli sull'SDK e un oggetto sdkInterface
per consentire ai client di comunicare con l'SDK.
Gli SDK in Privacy Sandbox dovrebbero utilizzare snippet di codice simili ai seguenti per comunicare con altri SDK. Supponi che questo codice sia scritto per consentire a "SDK1" di comunicare con "SDK2", entrambi caricati dall'app in 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);
}
Nell'esempio precedente, SDK1 aggiunge la libreria AIDL di SDK2 come dipendenza. Questo SDK client contiene il codice Binder generato dall'AIDL. Entrambi gli SDK devono esportare questa libreria AIDL. Questa operazione è identica a quella che le app dovrebbero fare quando comunicano con gli SDK in Privacy Sandbox.
Il supporto di un modo generato automaticamente per condividere le interfacce tra SDK verrà aggiunto in un aggiornamento futuro.
Gli SDK nel runtime potrebbero dover comunicare con le dipendenze dell'app e con gli SDK per gli annunci non ancora abilitati per il runtime.
L'API registerAppOwnedSdkSandboxInterface()
in SdkSandboxManager
consente agli SDK non abilitati per il runtime di registrare le proprie interfacce con la piattaforma. L'API getAppOwnedSdkSandboxInterfaces()
in SdkSandboxController
fornisce AppOwnedSdkSandboxInterface
per tutti gli SDK registrati e collegati in modo statico.
L'esempio seguente illustra come registrare le interfacce per renderle disponibili per la comunicazione con SDK abilitata per il runtime:
// Register AppOwnedSdkSandboxInterface
mSdkSandboxManager.registerAppOwnedSdkSandboxInterface(
new AppOwnedSdkSandboxInterface(
APP_OWNED_SDK_NAME, (long) APP_OWNED_SDK_VERSION, new AppOwnedSdkApi())
);
Questo esempio mostra come instrumentare la comunicazione con SDK non abilitati per il runtime:
// 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();
Poiché gli SDK di annunci che non sono abilitati per il runtime potrebbero non essere in grado di registrarsi se stessi, proponiamo la creazione di un SDK mediatore che gestisca la registrazione e includa SDK dei partner o delle app come dipendenze dirette. Questo SDK mediatore stabilisce la comunicazione tra SDK e dipendenze non abilitati per il runtime e il mediatore abilitato per runtime che funge da adattatore.
Supporto per le attività
Gli SDK abilitati per il runtime non possono aggiungere un tag attività al file manifest e non possono avviare direttamente le proprie attività. L'accesso all'oggetto Activity
viene fornito registrando un SdkSandboxActivityHandler
e avviando l'attività della sandbox:
1. Registra un SdkSandboxActivityHandler
Registra un'istanza di SdkSandboxActivityHandler
utilizzando
SdkSandboxController#registerSdkSandboxActivityHandler(SandboxedActivityHandler)
L'API registra l'oggetto e restituisce un oggetto IBinder
che identifica
il valore SdkSandboxActivityHandler
passato.
public interface SdkSandboxActivityHandler {
void onActivityCreated(Activity activity);
}
L'API registra l'oggetto e restituisce un oggetto IBinder
che identifica
il valore SdkSandboxActivityHandler
passato.
2. Avvia l'attività Sandbox
L'SDK passa il token restituito per identificare il SdkSandboxActivityHandler
registrato all'app client. L'app client chiama quindi SdkSandboxManager#startSdkSandboxActivity(Activity, Binder)
, passando un'attività da cui avviare la sandbox e un token che identifica il SdkSandboxActivityHandler
registrato.
Questo passaggio avvia una nuova attività della piattaforma che viene eseguita nello stesso SDK Runtime dell'SDK richiedente.
Quando l'attività inizia, l'SDK riceve una notifica tramite una chiamata a
SdkSandboxActivityHandler#onActivityCreated(Activity)
nell'ambito dell'esecuzione
di Activity#OnCreate(Bundle)
.
Ad esempio, con l'accesso all'oggetto Activity
e il chiamante può impostare
contentView
una visualizzazione chiamando Activity#setContentView(View)
.
Per registrare i callback del ciclo di vita, utilizza
Activity#registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks)
.
Per registrare OnBackInvokedCallback
nell'attività superata, utilizza
Activity#getOnBackInvokedDispatcher().registerOnBackInvokedCallback(Int,
OnBackInvokedCallback)
.
Testare i video player in SDK Runtime
Oltre a supportare gli annunci banner, Privacy Sandbox si impegna a supportare i video player in esecuzione all'interno di SDK Runtime.
La procedura per testare i video player è simile a quella per gli annunci banner. Modifica il
metodo getView()
del punto di ingresso dell'SDK per includere un video player nell'oggetto View
restituito. Testa tutti i flussi del video player che ti aspetti siano supportati da Privacy Sandbox. Tieni presente che la comunicazione tra l'SDK e l'app client sul ciclo di vita del video non rientra nell'ambito, quindi il feedback non è ancora necessario per questa funzionalità.
I tuoi test e feedback garantiranno che SDK Runtime supporti tutti i casi d'uso del tuo video player preferito.
Il seguente snippet di codice mostra come restituire una visualizzazione di video semplice che venga caricata da un 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; } }
Utilizzo delle API di archiviazione nell'SDK
Gli SDK in SDK Runtime non possono più accedere, leggere o scrivere nella archiviazione interna di un'app e viceversa. A SDK Runtime verrà allocata una propria area di archiviazione interna, che sarà garantita come separata dall'app.
Gli SDK potranno accedere a questa archiviazione interna separata utilizzando le API per l'archiviazione dei file nell'oggetto Context
restituito da SandboxedSdkProvider#getContext()
. Gli SDK possono utilizzare solo l'archiviazione interna, pertanto funzioneranno solo le API di archiviazione interna, come Context.getFilesDir()
o Context.getCacheDir()
. Guarda altri esempi in Accesso dallo spazio di archiviazione interno.
L'accesso all'unità di archiviazione esterna da SDK Runtime non è supportato. La chiamata alle API per accedere all'unità di archiviazione esterna genererà un'eccezione o restituirà null
. Alcuni esempi:
- L'accesso ai file mediante Storage Access Framework genera un elemento
SecurityException
. getExternalFilsDir()
restituirà semprenull
.
In Android 13, tutti gli SDK in SDK Runtime condivideranno la memoria interna allocata per SDK Runtime. Lo spazio di archiviazione rimarrà mantenuto fino alla disinstallazione dell'app client o fino alla pulizia dei dati dell'app client.
Devi utilizzare il valore Context
restituito da SandboxedSdkProvider.getContext()
per l'archiviazione. L'utilizzo dell'API di archiviazione file su qualsiasi altra istanza di oggetto Context
, come il contesto dell'applicazione, non garantisce il funzionamento previsto in tutte le situazioni o in futuro.
Il seguente snippet di codice mostra come utilizzare lo spazio di archiviazione in 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); } } }
Spazio di archiviazione per SDK
All'interno della memoria interna separata per ogni SDK Runtime, ogni SDK dispone della propria directory di archiviazione. L'archiviazione per SDK è una segregazione logica della memoria interna di SDK Runtime che aiuta a tenere conto della quantità di spazio di archiviazione utilizzata da ogni SDK.
In Android 13, solo un'API restituisce un percorso di archiviazione per SDK:
Context#getDataDir()
.
In Android 14, tutte le API di archiviazione interna nell'oggetto Context
restituiscono un percorso di archiviazione per ogni SDK. Potrebbe essere necessario abilitare questa funzionalità eseguendo il seguente comando adb:
adb shell device_config put adservices sdksandbox_customized_sdk_context_enabled true
Lettura del SharedPreferences
del client
Le app client possono scegliere di condividere un set di chiavi da SharedPreferences
con
SdkSandbox
. Gli SDK possono leggere i dati sincronizzati dall'app client utilizzando
l'API SdkSanboxController#getClientSharedPreferences()
. I SharedPreferences
restituiti da questa API sono di sola lettura. Non dovresti scrivere.
Accedi all'ID pubblicità fornito da Google Play Services
Se il tuo SDK deve accedere all'ID pubblicità fornito da Google Play Services:
- Dichiara l'autorizzazione
android.permission.ACCESS_ADSERVICES_AD_ID
nel manifest dell'SDK. - Utilizza
AdIdManager#getAdId()
per recuperare il valore in modo asincrono.
Accedere all'ID set di app fornito da Google Play Services
Se il tuo SDK deve accedere all'ID set di app fornito da Google Play Services:
- Utilizza
AppSetIdManager#getAppSetId()
per recuperare il valore in modo asincrono.
Aggiorna le app client
Per chiamare un SDK in esecuzione in SDK Runtime, apporta le seguenti modifiche all'app client chiamante:
Aggiungi le autorizzazioni
INTERNET
eACCESS_NETWORK_STATE
al file manifest dell'app:<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Nell'attività della tua app che include un annuncio, dichiara un riferimento a
SdkSandboxManager
, un valore booleano per sapere se l'SDK è stato caricato e un oggettoSurfaceView
per il rendering remoto: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;
Controlla se il processo di SDK Runtime è disponibile sul dispositivo.
Controlla la costante
SdkSandboxState
(getSdkSandboxState()
).SDK_SANDBOX_STATE_ENABLED_PROCESS_ISOLATION
indica che il runtime SDK è disponibile.Verifica che la chiamata al numero
loadSdk()
sia riuscita. L'operazione ha esito positivo se non vengono generate eccezioni e il destinatario è l'istanza diSandboxedSdk
.Chiama
loadSdk()
dal primo piano. Se viene chiamato dallo sfondo, viene generato un valoreSecurityException
.Controlla il
OutcomeReceiver
per un'istanza diSandboxedSdk
per verificare se è stato generato unLoadSdkException
. Un'eccezione indica che SDK Runtime potrebbe non essere disponibile.
Se la chiamata
SdkSandboxState
oloadSdk
ha esito negativo, SDK Runtime non è disponibile e la chiamata dovrebbe ricorrere all'SDK esistente.Definisci una classe di callback implementando
OutcomeReceiver
per interagire con l'SDK nel runtime dopo che è stato caricato. Nell'esempio seguente, il client utilizza un callback per attendere che l'SDK venga caricato correttamente, quindi tenta di eseguire il rendering di una visualizzazione web dall'SDK. I callback vengono definiti più avanti in questo passaggio.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. } } Per ottenere una visualizzazione remota dall'SDK nel runtime durante la chiamata a
requestSurfacePackage()
, implementa l'interfacciaOutcomeReceiver<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 } } Quando hai finito di mostrare la visualizzazione, ricordati di rilasciare
SurfacePackage
chiamando:surfacePackage.notifyDetachedFromWindow()
In
onCreate()
, inizializzaSdkSandboxManager
, i callback necessari, quindi una richiesta per caricare l'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); }
L'app può scegliere di condividere determinate chiavi del suo valore predefinito
SharedPreferences
con la sandbox. Per farlo, possono chiamare il metodoSdkSandboxManager#addSyncedSharedPreferencesKeys(Set<String>keys)
su qualsiasi istanza del gestore diSdkSandbox
. Quando l'app comunica aSdkSandboxManager
le chiavi da sincronizzare,SdkSandboxManager
ne sincronizzerà i valori nella sandbox e gli SDK potranno leggerli utilizzandoSdkSandboxController#getClientSharedPreferences
. Per ulteriori informazioni, consulta Lettura di SharedPreferences del client.Il set di chiavi da sincronizzare non è persistente durante il riavvio dell'app e i dati sincronizzati nella sandbox vengono cancellati al riavvio della sandbox. Di conseguenza, è essenziale che l'app avvii la sincronizzazione chiamando
addSyncedSharedPreferencesKeys
a ogni avvio.Puoi modificare il set di chiavi da sincronizzare chiamando
SdkSandboxManager#removeSyncedSharedPreferencesKeys(Set<String>keys)
per rimuovere le chiavi. Per visualizzare il set di chiavi attualmente in fase di sincronizzazione, usaSdkSandboxManager#getSyncedSharedPreferencesKeys()
.Ti consigliamo di mantenere il set di chiavi il più piccolo possibile e di utilizzarlo solo se necessario. Se vuoi passare informazioni agli SDK per uso generico, comunica direttamente con l'SDK utilizzando l'interfaccia
SandboxedSdk
. Un possibile scenario per l'utilizzo di queste API è che, se l'app utilizza un SDK della piattaforma di gestione del consenso (CMP), gli SDK all'interno della sandbox sarebbero interessati a leggere i dati archiviati dall'SDK CMP in modo predefinitoSharedPreferences
.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")); }
Per gestire il caso in cui il processo sandbox dell'SDK termina in modo imprevisto, definisci un'implementazione per l'interfaccia
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); } }
Per registrare questo callback e ricevere informazioni sul termine della sandbox dell'SDK, aggiungi la seguente riga in qualsiasi momento:
Kotlin
mSdkSandboxManager.addSdkSandboxProcessDeathCallback({ obj: Runnable -> obj.run() }, SdkSandboxLifecycleCallbackImpl())
Java
mSdkSandboxManager.addSdkSandboxProcessDeathCallback(Runnable::run, new SdkSandboxLifecycleCallbackImpl());
Poiché lo stato della sandbox va perso al termine del processo, le viste di cui l'SDK ha eseguito il rendering in remoto potrebbero non funzionare più correttamente. Per continuare a interagire con gli SDK, è necessario caricare di nuovo queste viste per avviare un nuovo processo sandbox.
Aggiungi una dipendenza al modulo SDK a
build.gradle
dell'app client:dependencies { ... implementation project(':<your-sdk-module>') ... }
Testare le app
Per eseguire l'app client, installa l'app SDK e l'app client sul dispositivo di test utilizzando Android Studio o la riga di comando.
Implementazione tramite Android Studio
Quando esegui il deployment tramite Android Studio, completa i seguenti passaggi:
- Apri il progetto Android Studio per l'app client.
- Vai a Esegui > Modifica configurazioni. Viene visualizzata la finestra Esegui/configura il debug.
- Sotto Opzioni di avvio, imposta Avvia su Attività specificata.
- Fai clic sul menu con tre puntini accanto ad Attività e seleziona l'Attività principale per il tuo cliente.
- Fai clic su Applica, quindi su OK.
- Fai clic su Esegui
per installare l'app client e l'SDK sul tuo dispositivo di test.
Esegui il deployment dalla riga di comando
Quando esegui il deployment utilizzando la riga di comando, completa i passaggi nell'elenco seguente.
Questa sezione presuppone che il nome del modulo dell'app SDK sia sdk-app
e che il nome del modulo dell'app client sia client-app
.
Da un terminale a riga di comando, crea gli APK dell'SDK Privacy Sandbox:
./gradlew :client-app:buildPrivacySandboxSdkApksForDebug
Verrà restituita la posizione per gli APK generati. Questi APK sono firmati con la chiave di debug locale. Questo percorso è necessario nel comando successivo.
Installa l'APK sul dispositivo:
adb install -t /path/to/your/standalone.apk
In Android Studio, fai clic su Esegui > Modifica configurazioni. Viene visualizzata la finestra Configurazione esecuzione/debug.
In Opzioni di installazione, imposta Esegui il deployment su APK predefinito.
Fai clic su Applica, quindi su OK.
Fai clic su Esegui per installare il pacchetto APK sul dispositivo di test.
Esegui il debug delle tue app
Per eseguire il debug dell'app client, fai clic sul pulsante Debug
in Android Studio.
Per eseguire il debug dell'app SDK, vai a Esegui > Allega a processo; viene visualizzata una schermata popup (mostrata di seguito). Seleziona la casella Mostra tutti i processi. Nell'elenco visualizzato, cerca un processo chiamato CLIENT_APP_PROCESS_sdk_sandbox
. Seleziona questa opzione e aggiungi punti di interruzione nel codice dell'app SDK per iniziare il debug dell'SDK.
![Il processo dell'app SDK viene visualizzato in una visualizzazione elenco nella parte inferiore della finestra di dialogo](https://developers-dot-devsite-v2-prod.appspot.com/static/privacy-sandbox/assets/images/android/debug-sdk-app.png?authuser=7&hl=it)
Avvia e interrompi il runtime dell'SDK dalla riga di comando
Per avviare il processo di runtime dell'SDK per la tua app, utilizza il seguente comando shell:
adb shell cmd sdk_sandbox start [--user <USER_ID> | current] <CLIENT_APP_PACKAGE>
Analogamente, per interrompere il processo di runtime dell'SDK, esegui questo comando:
adb shell cmd sdk_sandbox stop [--user <USER_ID> | current] <CLIENT_APP_PACKAGE>
Verifica quali SDK sono attualmente caricati
Puoi verificare quali SDK sono attualmente caricati utilizzando la funzionalità getSandboxedSdks
all'interno di SdkSandboxManager
.
Limitazioni
Per un elenco delle funzionalità in corso per SDK Runtime, consulta le note di rilascio.
Esempi di codice
Il repository di API SDK Runtime e Privacy Conserveing su GitHub contiene un set di singoli progetti Android Studio per aiutarti a iniziare, inclusi esempi che mostrano come inizializzare e chiamare l'SDK Runtime.Segnala bug e problemi
Il tuo feedback è una parte fondamentale di Privacy Sandbox su Android. Comunicaci eventuali problemi riscontrati o idee per migliorare Privacy Sandbox su Android.
Consigliati per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Runtime SDK
- Note di rilascio
- Guida per gli sviluppatori sull'API Protected Audience su Android