A medida que leas la documentación de Privacy Sandbox en Android, usa el botón Versión preliminar para desarrolladores o Beta para seleccionar la versión del programa con la que estás trabajando, ya que las instrucciones pueden variar.
El entorno de ejecución de SDK permite que los SDKs se ejecuten en una zona de pruebas dedicada independiente de la app que realiza la llamada. El entorno de ejecución de SDK proporciona mejores protecciones y garantías en cuanto a la recopilación de datos del usuario. Esto se hace a través de un entorno de ejecución modificado que limita los derechos de acceso a los datos y el conjunto de permisos que pueden otorgarse. Obtén más información sobre el entorno de ejecución del SDK en la propuesta de diseño.
Los pasos que se indican en esta página te guiarán a través del proceso de creación de un SDK habilitado para el entorno de ejecución que define una vista basada en la Web que se puede renderizar, de forma remota, en una app que realiza la llamada.
Limitaciones conocidas
Si quieres ver una lista de las funciones en curso para el entorno de ejecución de SDK, consulta las notas de la versión.
Se espera que las siguientes limitaciones se corrijan en la próxima actualización importante de la plataforma de Android.
- Renderización de anuncios dentro de una vista que admite desplazamiento (por ejemplo,
RecyclerView
no funciona correctamente)- Es posible que experimentes bloqueos al cambiar el tamaño.
- Los eventos de desplazamiento táctil del usuario no se pasan correctamente al entorno de ejecución.
- API de Storage
- El almacenamiento por SDK no está disponible en Android 13.
El siguiente problema se corregirá en 2023:
- Las APIs de
getAdId
ygetAppSetId
aún no funcionan correctamente, ya que todavía se está trabajando en la compatibilidad.
Antes de comenzar
Antes de comenzar, completa los siguientes pasos:
Configura tu entorno de desarrollo para Privacy Sandbox en Android. Las herramientas para admitir el entorno de ejecución de SDK están en desarrollo activo, por lo que en esta guía deberás usar la versión Canary de Android Studio más reciente. Puedes ejecutar esta versión de Android Studio en paralelo a otras versiones que uses; te pedimos que nos cuentes si este requisito no funciona en tu caso.
Instala una imagen del sistema en un dispositivo compatible o configura un emulador que incluya compatibilidad con Privacy Sandbox en Android.
Configura tu proyecto en Android Studio
Para probar el entorno de ejecución de SDK, usa un modelo similar al modelo cliente-servidor. La principal diferencia es que las apps (el cliente) y los SDKs (el "servidor") se ejecutan en el mismo dispositivo.
- Agrega un módulo de app a tu proyecto. Este módulo funciona como el cliente que controla el SDK.
- En el módulo de tu app, habilita el entorno de ejecución de SDK, declara los permisos necesarios y configura los servicios de anuncios específicos de la API.
- Agrega un módulo de biblioteca a tu proyecto. Este módulo contiene tu código del SDK.
- En el módulo del SDK, declara los permisos necesarios. No necesitas configurar servicios de anuncios específicos de APIs en este módulo.
- Quita las
dependencies
del archivobuild.gradle
del módulo de la biblioteca que no usa el SDK. En la mayoría de los casos, puedes quitar todas las dependencias. Puedes hacerlo creando un directorio nuevo cuyo nombre corresponda a tu SDK. Crea manualmente un módulo nuevo con el tipo
com.android.privacy-sandbox-sdk
. Este se incluye con el código del SDK para crear un APK que se pueda implementar en tu dispositivo. Puedes hacerlo creando un directorio nuevo cuyo nombre corresponda a tu SDK. Agrega un archivobuild.gradle
vacío. El contenido de este archivo se completará más adelante en esta guía.Agrega el siguiente fragmento a tu archivo
gradle.properties
:android.experimental.privacysandboxsdk.enable=true
Descarga la imagen del emulador TiramisuPrivacySandbox y crea un emulador con esta imagen que incluya Play Store.
En función de si eres un desarrollador de SDKs o de apps, es posible que tengas una configuración final diferente a la que se describe en el párrafo anterior.
Instala el SDK en un dispositivo de prueba, de manera similar a como instalarías una app, con Android Studio o Android Debug Bridge (ADB). Para ayudarte a comenzar, creamos apps de ejemplo en los lenguajes de programación Kotlin y Java, que puedes encontrar en este repositorio de GitHub. Los archivos de manifiesto y readme contienen comentarios que describen qué se debe cambiar para ejecutar las apps de ejemplo en versiones estables de Android Studio.
Prepara el SDK
Crea un directorio de nivel de módulo de forma manual. Esto sirve como wrapper del código de implementación para compilar el APK del SDK. Agrega un archivo
build.gradle
en el directorio nuevo e incluye en él el siguiente fragmento. Usa un nombre único para el SDK habilitado para el entorno de ejecución y proporciona una versión. Incluye el módulo de biblioteca en la seccióndependencies
.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 clase en la biblioteca de implementación de modo que funcione como punto de entrada para el SDK. Se le debe asignar el valor de
sdkProviderClassName
al nombre y extenderSandboxedSdkProvider
.
El punto de entrada de tu SDK extiende SandboxedSdkProvider
. SandboxedSdkProvider
contiene un objeto Context
para tu SDK, al que puedes acceder si llamas a getContext()
. Solo se debe acceder a este contexto una vez que se invocó onLoadSdk()
.
Para que se compile tu app del SDK, debes anular métodos para controlar el ciclo de vida del SDK:
onLoadSdk()
Carga el SDK en la zona de pruebas y notifica a la app que realiza la llamada cuando este esté listo para controlar las solicitudes pasando su interfaz como un objeto
IBinder
que está unido a un nuevo objetoSandboxedSdk
. En la guía de servicios vinculados, se detallan diferentes formas de proporcionarIBinder
. Puedes elegir la que prefieras, pero debe haber coherencia entre el SDK y la app que realiza la llamada.Con AIDL como ejemplo, debes definir un archivo AIDL para presentar tu
IBinder
, que la app compartirá y usará:// ISdkInterface.aidl interface ISdkInterface { // the public functions to share with the App. int doSomething(); }
getView()
Crea y configura la vista de tu anuncio, inicializa la vista de la misma manera que cualquier otra vista de Android y muestra la vista de modo que se renderice de forma remota en una ventana de un ancho y una altura determinados en píxeles.
En el siguiente fragmento de código, se muestra cómo anular estos métodos:
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
es un wrapper del servicio del sistema basado en el contexto, disponible para los SDK. Los SDKs pueden recuperarlo a través del contexto recibido de SandboxedSdkProvider#getContext()
y, luego, invocar a context.getSystemService(SdkSandboxController.class)
en este contexto. El controlador tiene APIs que ayudan a los SDKs a interactuar con Privacy Sandbox y a obtener información de ella.
La mayoría de las APIs del controlador arrojan excepciones si SandboxedSdkContext
no es el contexto que se usa para acceder. Planeamos hacer que el wrapper del servicio no esté disponible para otros contextos. SdkSandboxController
se diseñó para que lo usen proveedores de SDK, por lo que no te recomendamos que lo usen los desarrolladores de apps.
Comunicación de SDK a SDK
Los SDKs del entorno de ejecución deberían poder comunicarse entre sí para admitir la mediación y los casos de uso relacionados. El conjunto de herramientas que se describe aquí proporciona una interfaz para trabajar con los SDKs que están disponibles para otros SDKs dentro de la zona de pruebas. Esta implementación del entorno de ejecución de SDK es un primer paso para habilitar la comunicación de SDK a SDK y es posible que aún no abarque todos los casos de uso de mediación en Privacy Sandbox.
La API de getSandboxedSdks()
en SdkSandboxController
proporciona una clase SandboxedSdk
para todos los SDKs cargados en Privacy Sandbox. El objeto SandboxedSdk
tiene detalles sobre el SDK y una sdkInterface
para que los clientes se comuniquen con él.
Se espera que los SDKs de Privacy Sandbox usen fragmentos de código similares al siguiente para comunicarse con otros SDKs. Supongamos que este código está escrito para permitir que "SDK1" se comunique con "SDK2" (la app carga ambos en 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);
}
En el ejemplo anterior, SDK1 agrega la biblioteca AIDL del SDK2 como dependencia. Este SDK de cliente contiene código de Binder generado por el AIDL. Ambos SDKs deben exportar esta biblioteca de AIDL. Esto es idéntico a lo que se espera que hagan las apps cuando se comunican con los SDKs en Privacy Sandbox.
En una actualización futura, se agregará compatibilidad para compartir interfaces entre SDKs de una manera generada automáticamente.
Es posible que los SDK del entorno de ejecución deban comunicarse con dependencias de apps y SDK de anuncios que aún no están habilitados para el entorno de ejecución.
La API de registerAppOwnedSdkSandboxInterface()
en SdkSandboxManager
proporciona una forma para que los SDKs que no están habilitados para el entorno de ejecución registren sus interfaces con la plataforma. La API de getAppOwnedSdkSandboxInterfaces()
en SdkSandboxController
proporciona la AppOwnedSdkSandboxInterface
para todos los SDKs registrados y vinculados de forma estática.
En el siguiente ejemplo, se muestra cómo registrar interfaces de modo que estén disponibles para la comunicación del SDK habilitado para el entorno de ejecución:
// Register AppOwnedSdkSandboxInterface
mSdkSandboxManager.registerAppOwnedSdkSandboxInterface(
new AppOwnedSdkSandboxInterface(
APP_OWNED_SDK_NAME, (long) APP_OWNED_SDK_VERSION, new AppOwnedSdkApi())
);
En este ejemplo, se muestra cómo instrumentar la comunicación con SDK no habilitados para el entorno de ejecución:
// 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();
Dado que es posible que los SDKs de anuncios que no están habilitados para el entorno de ejecución no puedan registrarse, proponemos la creación de un SDK de mediador que controle el registro y que incluya SDKs de socios o de apps como dependencias directas. Este SDK de mediador establece comunicación entre los SDKs y las dependencias que no están habilitados para el entorno de ejecución y el mediador habilitado para el entorno de ejecución que actúa como adaptador.
Compatibilidad con actividades
Los SDK habilitados para el entorno de ejecución no pueden agregar una etiqueta de actividad a su archivo de manifiesto ni pueden iniciar sus propias actividades directamente. Para proporcionar el acceso al objeto Activity
, se registra un SdkSandboxActivityHandler
y se inicia la actividad de la zona de pruebas:
1. Registra un SdkSandboxActivityHandler
Registra una instancia de SdkSandboxActivityHandler
con SdkSandboxController#registerSdkSandboxActivityHandler(SandboxedActivityHandler)
.
La API registra ese objeto y muestra un objeto IBinder
que identifica el SdkSandboxActivityHandler
pasado.
public interface SdkSandboxActivityHandler {
void onActivityCreated(Activity activity);
}
La API registra ese objeto y muestra un objeto IBinder
que identifica el SdkSandboxActivityHandler
pasado.
2. Inicia la actividad de la zona de pruebas
El SDK pasa el token que se muestra para identificar el SdkSandboxActivityHandler
registrado a la app cliente. Luego, la app cliente llama a SdkSandboxManager#startSdkSandboxActivity(Activity, Binder)
y pasa una actividad desde la que se inicia la zona de pruebas y un token que identifica el SdkSandboxActivityHandler
registrado.
Este paso inicia una nueva actividad de plataforma que se ejecuta en el mismo entorno de ejecución de SDK que el SDK solicitante.
Cuando se inicia la actividad, el SDK recibe una notificación a través de una llamada a SdkSandboxActivityHandler#onActivityCreated(Activity)
como parte de la ejecución de Activity#OnCreate(Bundle)
.
Por ejemplo, con acceso al objeto Activity
, y el llamador puede establecer la vista de contentView
llamando a Activity#setContentView(View)
.
Para registrar devoluciones de llamada de ciclo de vida, usa Activity#registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks)
.
Para registrar OnBackInvokedCallback
en la actividad pasada, usa Activity#getOnBackInvokedDispatcher().registerOnBackInvokedCallback(Int,
OnBackInvokedCallback)
.
Cómo probar reproductores de video en el entorno de ejecución de SDK
Además de admitir anuncios de banner, Privacy Sandbox se compromete a admitir los reproductores de video que se ejecutan dentro del entorno de ejecución de SDK.
El flujo para probar reproductores de video es similar al de probar anuncios de banner. Cambia el método getView()
del punto de entrada de tu SDK para incluir un reproductor de video en el objeto View
que se muestra. Prueba todos los flujos del reproductor de video que esperas que sean compatibles con Privacy Sandbox. Ten en cuenta que la comunicación entre el SDK y la app cliente sobre el ciclo de vida del video está fuera del alcance, por lo que aún no se requieren comentarios para esta funcionalidad.
Tus pruebas y comentarios garantizarán que el entorno de ejecución de SDK sea compatible con todos los casos de uso de tu reproductor de video preferido.
En el siguiente fragmento de código, se demuestra cómo mostrar una vista de video simple que se carga desde una 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; } }
Uso de las APIs de Storage en tu SDK
Los SDKs en el entorno de ejecución del SDK ya no pueden acceder al almacenamiento interno de una app, ni viceversa, ni leer o escribir en él. Al entorno de ejecución de SDK se le asignará su propia área de almacenamiento interno, que será independiente de la app.
Los SDKs podrán acceder a este almacenamiento interno independiente con las APIs de almacenamiento de archivos en el objeto Context
que muestra SandboxedSdkProvider#getContext()
. Los SDKs solo pueden usar el almacenamiento interno, por lo que solo funcionarán las APIs de almacenamiento interno, como Context.getFilesDir()
o Context.getCacheDir()
. Puedes ver más ejemplos en Acceso desde el almacenamiento interno.
No se admite el acceso al almacenamiento externo desde el entorno de ejecución del SDK. Llamar a las APIs para que accedan al almacenamiento externo arrojará una excepción o mostrará null
. Varios ejemplos:
- El acceso a los archivos mediante el framework de acceso al almacenamiento arrojará una
SecurityException
. getExternalFilsDir()
siempre mostraránull
.
En Android 13, todos los SDKs en el entorno de ejecución de SDK compartirán el almacenamiento interno asignado para ese entorno. El almacenamiento se conservará hasta que se desinstale la app cliente o cuando se borren los datos de ella.
Debes usar el Context
que muestra SandboxedSdkProvider.getContext()
para el almacenamiento. El uso de la API de almacenamiento de archivos en cualquier otra instancia de objeto Context
, como el contexto de la aplicación, no se garantiza que funcione como se espera en todas las situaciones o en el futuro.
En el siguiente fragmento de código, se muestra el modo de uso del almacenamiento en el entorno de ejecución del SDK:
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); } } }
Almacenamiento por SDK
Dentro del almacenamiento interno independiente para cada entorno de ejecución de SDK, cada SDK tiene su propio directorio de almacenamiento. El almacenamiento por SDK es una separación lógica del almacenamiento interno del entorno de ejecución de SDK que ayuda a conocer la cantidad de almacenamiento que usa cada uno.
En Android 13, solo una API muestra una ruta de acceso al almacenamiento por SDK: Context#getDataDir()
.
En Android 14, todas las APIs de almacenamiento interno del objeto Context
muestran una ruta de almacenamiento para cada SDK. Es posible que debas habilitar esta función ejecutando el siguiente comando adb:
adb shell device_config put adservices sdksandbox_customized_sdk_context_enabled true
Lectura del objeto SharedPreferences
del cliente
En las apps cliente, se puede optar por compartir un conjunto de claves de su SharedPreferences
con SdkSandbox
. Los SDKs pueden leer los datos sincronizados desde la app cliente con la API de SdkSanboxController#getClientSharedPreferences()
. Los objetos SharedPreferences
que muestra esta API son de solo lectura. No debes escribir en ellos.
Accede al ID de publicidad que brindan los Servicios de Google Play
Si tu SDK necesita acceder al ID de publicidad que brindan los Servicios de Google Play, haz lo siguiente:
- Declara el permiso
android.permission.ACCESS_ADSERVICES_AD_ID
en el manifiesto del SDK. - Usa
AdIdManager#getAdId()
para recuperar el valor de forma asíncrona.
Accede al ID del conjunto de apps que brindan los Servicios de Google Play
Si tu SDK necesita acceder al ID del conjunto de apps que brindan los Servicios de Google Play, haz lo siguiente:
- Usa
AppSetIdManager#getAppSetId()
para recuperar el valor de forma asíncrona.
Actualiza las apps cliente
Para llamar a un SDK que se ejecuta en el entorno de ejecución de SDK, realiza los siguientes cambios en la app cliente que realiza la llamada:
Agrega los permisos
INTERNET
yACCESS_NETWORK_STATE
al manifiesto de tu app:<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
En la actividad de la app que incluye un anuncio, declara una referencia a
SdkSandboxManager
, un valor booleano para saber si se cargó el SDK, y a un objetoSurfaceView
para la renderización remota: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;
Comprueba si el proceso del entorno de ejecución del SDK está disponible en el dispositivo.
Verifica la constante
SdkSandboxState
(getSdkSandboxState()
).SDK_SANDBOX_STATE_ENABLED_PROCESS_ISOLATION
significa que el entorno de ejecución del SDK está disponible.Comprueba que la llamada a
loadSdk()
se haya realizado correctamente. Es exitosa si no se producen excepciones y el receptor es la instancia delSandboxedSdk
.Llama a
loadSdk()
desde el primer plano. Si se llama en segundo plano, se arroja unaSecurityException
.Verifica el
OutcomeReceiver
para ver una instancia deSandboxedSdk
y comprobar si se arrojó unaLoadSdkException
. Una excepción indica que el entorno de ejecución del SDK puede no estar disponible.
Si la llamada a
loadSdk
o elSdkSandboxState
fallan, el entorno de ejecución del SDK no está disponible y la llamada debería recurrir al SDK existente.Para definir una clase de devolución de llamada, implementa
OutcomeReceiver
para interactuar con el SDK en el entorno de ejecución después de que se haya cargado: En el siguiente ejemplo, el cliente usa una devolución de llamada para esperar hasta que el SDK se cargue de forma correcta y, luego, intenta renderizar una vista web desde el SDK. Las devoluciones de llamada se definen más adelante en este paso.Kotlin
private inner class LoadSdkOutcomeReceiverImpl private constructor() : OutcomeReceiver<SandboxedSdk?, LoadSdkException?> { 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<LoadSdkResponse, LoadSdkException> { 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. } }
Para recuperar una vista remota del SDK en el entorno de ejecución mientras llamas a
requestSurfacePackage()
, implementa la interfazOutcomeReceiver<Bundle, RequestSurfacePackageException>
:Kotlin
private inner class RequestSurfacePackageOutcomeReceiverImpl : OutcomeReceiver<Bundle, RequestSurfacePackageException> { 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<Bundle, RequestSurfacePackageException> { @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 } }
Cuando termines de mostrar la vista, recuerda liberar a
SurfacePackage
con un llamado al siguiente comando:surfacePackage.notifyDetachedFromWindow()
En
onCreate()
, inicializaSdkSandboxManager
, las devoluciones de llamada necesarias y, luego, realiza una solicitud para cargar el 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); }
La app puede elegir compartir determinadas claves del objeto
SharedPreferences
predeterminado con la zona de pruebas. Para ello, se puede llamar al métodoSdkSandboxManager#addSyncedSharedPreferencesKeys(Set<String>keys)
en cualquier instancia del administrador deSdkSandbox
. Una vez que la app notifica aSdkSandboxManager
qué claves sincronizar,SdkSandboxManager
sincronizará los valores de esas claves en la zona de pruebas, y los SDKs podrán leerlos conSdkSandboxController#getClientSharedPreferences
. Consulta Cómo leer el objeto SharedPreferences del cliente para obtener más información.El conjunto de claves que se sincroniza no persiste durante el reinicio de la app, y los datos sincronizados con la zona de pruebas se borran cuando esta se reinicia. Por lo tanto, es esencial que la app inicie la sincronización llamando a
addSyncedSharedPreferencesKeys
cada vez que se inicia.Si quieres modificar el conjunto de claves que se sincroniza, llama a
SdkSandboxManager#removeSyncedSharedPreferencesKeys(Set<String>keys)
para quitar claves. Si deseas ver el conjunto actual de claves que se están sincronizando, usaSdkSandboxManager#getSyncedSharedPreferencesKeys()
.Te recomendamos que mantengas el conjunto de claves lo más pequeño posible y lo uses solo si es necesario. Si quieres pasar información a los SDKs para un uso general, comunícate con el SDK directamente a través de su interfaz
SandboxedSdk
. Una situación posible para utilizar estas APIs sería si la app usara un SDK de plataforma de administración de consentimiento (CMP), por lo que a los SDKs dentro de la zona de pruebas les interesaría leer los datos que el SDK de CMP almacena en el objetoSharedPreferences
predeterminado.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")); }
Para manejar el caso cuando el proceso de la zona de pruebas del SDK finaliza de forma inesperada, define una implementación para la interfaz
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); } }
Para registrar esta devolución de llamada para recibir información sobre cuándo se cerró la zona de pruebas del SDK, agrega la siguiente línea en cualquier momento:
Kotlin
mSdkSandboxManager.addSdkSandboxProcessDeathCallback({ obj: Runnable -> obj.run() }, SdkSandboxLifecycleCallbackImpl())
Java
mSdkSandboxManager.addSdkSandboxProcessDeathCallback(Runnable::run, new SdkSandboxLifecycleCallbackImpl());
Debido a que el estado de la zona de pruebas se pierde cuando finaliza su proceso, es posible que las vistas que haya renderizado el SDK de forma remota ya no funcionen correctamente. Para seguir interactuando con los SDKs, se deben volver a cargar estas vistas para que se inicie un nuevo proceso de zona de pruebas.
Agrega una dependencia en el módulo del SDK al
build.gradle
de tu app cliente:dependencies { ... implementation project(':<your-sdk-module>') ... }
Prueba tus apps
Para ejecutar tu app cliente, instala la app del SDK y la app cliente en tu dispositivo de prueba mediante Android Studio o la línea de comandos.
Cómo implementar mediante Android Studio
Cuando realices implementaciones mediante Android Studio, sigue estos pasos:
- Abre el proyecto de Android Studio de tu app cliente.
- Ve a Run > Edit Configurations. Aparecerá la ventana Run/Debug Configuration.
- En Launch Options, establece Launch en Specified Activity.
- Haz clic en el menú de tres puntos junto a Activity y selecciona Main Activity para tu cliente.
- Haz clic en Apply y, luego, en OK.
- Haz clic en Run
para instalar la app cliente y el SDK en tu dispositivo de prueba.
Cómo implementar mediante la línea de comandos
Cuando realices implementaciones con la línea de comandos, completa los pasos de la siguiente lista.
En esta sección, se supone que el nombre del módulo de tu app del SDK es sdk-app
y que el nombre del módulo de tu app cliente es client-app
.
Compila los APK del SDK de Privacy Sandbox desde la terminal de la línea de comandos:
./gradlew :client-app:buildPrivacySandboxSdkApksForDebug
Esto genera la ubicación para los APKs generados. Estos APKs están firmados con tu clave de depuración local. Necesitarás esta ruta de acceso en el siguiente comando.
Instala el APK en tu dispositivo:
adb install -t /path/to/your/standalone.apk
En Android Studio, haz clic en Run > Edit Configurations. Aparecerá la ventana Run/Debug Configuration.
En Installation Options, configura Deploy como Default APK.
Haz clic en Apply y, luego, en OK.
Haz clic en Run para instalar el paquete de APK en el dispositivo de prueba.
Depura tus apps
Para depurar la app cliente, haz clic en el botón Debug en Android Studio.
Para depurar la app del SDK, ve a Run > Attach to Process, que muestra una ventana emergente.
(que se muestra a continuación). Marca la casilla Show all processes. En la lista que aparece, busca un proceso con el nombre CLIENT_APP_PROCESS_sdk_sandbox
. Selecciona esta opción y agrega puntos de interrupción en el código de la app del SDK para comenzar a depurar tu SDK.
![El proceso de la app del SDK aparece en una vista de lista cerca de la parte inferior del diálogo.](https://developers.google.cn/static/privacy-sandbox/assets/images/android/debug-sdk-app.png?authuser=0000&hl=es)
Inicia y detén el entorno de ejecución del SDK desde la línea de comandos
Para iniciar el proceso del entorno de ejecución del SDK de tu app, usa el siguiente comando shell:
adb shell cmd sdk_sandbox start [--user <USER_ID> | current] <CLIENT_APP_PACKAGE>
Del mismo modo, para detener el proceso del entorno de ejecución del SDK, ejecuta este comando:
adb shell cmd sdk_sandbox stop [--user <USER_ID> | current] <CLIENT_APP_PACKAGE>
Verifica qué SDKs están cargados
Puedes comprobar qué SDKs están cargados usando la funcionalidad getSandboxedSdks
dentro de SdkSandboxManager
.
Limitaciones
Si quieres obtener una lista de las funciones en curso para el entorno de ejecución del SDK, consulta las notas de la versión.
Muestras de código
El Repositorio de APIs que preserva la privacidad y el entorno de ejecución del SDK en GitHub contiene un conjunto de proyectos individuales de Android Studio que te ayudarán a obtener que incluye ejemplos que muestran cómo inicializar y llamar al SDK Entorno de ejecución.Informa errores y problemas
Tus comentarios son una parte fundamental de Privacy Sandbox en Android. Avísanos si tienes problemas o ideas para mejorar Privacy Sandbox en Android.
Recomendaciones para ti
- Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
- Entorno de ejecución de SDK
- Notas de la versión
- Guía para desarrolladores de la API de Protected Audience en Android