Crea e utilizza un SDK abilitato per il runtime

1
Key concepts
2
Set up your development environment
3
Build an RE SDK
4
Consume the RE SDK
5
Testing, and building for distribution

Crea un SDK abilitato per il runtime

Per creare un SDK abilitato per il runtime, devi completare i seguenti passaggi:

  1. Configurare la struttura del progetto
  2. Prepara le dipendenze del progetto e dei moduli
  3. Aggiungi la logica di business dell'SDK
  4. Definire le API SDK
  5. Specificare un punto di ingresso per il tuo SDK

Configura la struttura del progetto

Ti consigliamo di organizzare il progetto nei seguenti moduli:

  1. Modulo App: l'app di test che stai utilizzando per testare e sviluppare la tua che rappresenta ciò che avrebbero avuto i tuoi clienti di app reali. La tua app deve avere una dipendenza dal modulo della libreria di annunci esistente (SDK consapevole del runtime).
  2. Modulo esistente della libreria di annunci (SDK che supporta il runtime): un modulo della libreria Android che contiene i valori "non abilitati per il runtime" della logica SDK, in modo statico SDK collegato.
    • Per iniziare, le funzionalità possono essere suddivise. Ad esempio, una parte di codice gestite dall'SDK esistente e alcune possono essere indirizzate all'account abilitato per il runtime l'SDK.
  3. Modulo della libreria di annunci abilitata per il runtime: contiene la logica di business dell'SDK abilitato per il runtime. Può essere creato in Android Studio come libreria Android. in maggior dettaglio più avanti in questo modulo.
  4. Modulo ASB abilitato per il runtime: definisce i dati del pacchetto per raggruppare il codice SDK abilitato per il runtime in un ASB.
    • Deve essere creato manualmente utilizzando il tipo com.android.privacy-sandbox-sdk. Puoi farlo creando un nella nuova directory.
    • Questo modulo non deve contenere codice e solo un file build.gradle vuoto con dipendenze del modulo della libreria di annunci abilitato per il runtime. I contenuti di questo file sono definiti in Preparare l'SDK.
    • Ricordati di includere questo modulo nel file settings.gradle e nel modulo della libreria pubblicitaria esistente.

La struttura del progetto in questa guida è un suggerimento. Puoi scegliere una struttura diversa per il tuo SDK e applicare gli stessi principi tecnici. Puoi sempre creare altri moduli aggiuntivi per modularizzare il codice nei moduli dell'app e della libreria.

Prepara l'SDK

Per preparare il progetto per lo sviluppo di un SDK abilitato per il runtime, devi devi prima definire alcuni strumenti e dipendenze delle librerie:

  • Librerie di compatibilità con le versioni precedenti del runtime dell'SDK, che forniscono supporto per i dispositivi che non dispongono di Privacy Sandbox (Android 13 e versioni precedenti) (androidx.privacysandbox.sdkruntime:)
  • Librerie UI per supportare la presentazione degli annunci (androidx.privacysandbox.ui:)
  • Strumenti per sviluppatori SDK per supportare la dichiarazione dell'API SDK e la generazione di shim (androidx.privacysandbox.tools:)
  1. Aggiungi questo flag al file gradle.properties del progetto per abilitare la possibilità di creare SDK abilitati per il runtime.

    # This enables the Privacy Sandbox for your project on Android Studio.
    android.experimental.privacysandboxsdk.enable=true
    android.experimental.privacysandboxsdk.requireServices=false
    
  2. Modifica il file build.gradle del progetto in modo da includere le librerie di assistenza Jetpack e altre dipendenze:

    // Top-level build file where you can add configuration options common to all sub-projects/modules.
    buildscript {
        ext.kotlin_version = '1.9.10'
        ext.ksp_version = "$kotlin_version-1.0.13"
        ext.privacy_sandbox_activity_version = "1.0.0-alpha01"
        ext.privacy_sandbox_sdk_runtime_version = "1.0.0-alpha13"
        ext.privacy_sandbox_tools_version = "1.0.0-alpha09"
        ext.privacy_sandbox_ui_version = "1.0.0-alpha09"
        repositories {
            mavenCentral()
        }
        dependencies {
            classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        }
    }
    
    plugins {
        id 'com.android.application' version '8.4.0-alpha13' apply false
        id 'com.android.library' version '8.4.0-alpha13' apply false
    
        // These two plugins do annotation processing and code generation for the sdk-implementation.
        id 'androidx.privacysandbox.library' version '1.0.0-alpha02' apply false
        id 'com.google.devtools.ksp' version "$ksp_version" apply false
    
        id 'org.jetbrains.kotlin.jvm' version '1.9.10' apply false
    }
    
    task clean(type: Delete) {
        delete rootProject.buildDir
    }
    
  3. Aggiorna il file build.gradle nel modulo Libreria di annunci abilitata per il runtime (SDK RE) per includere queste dipendenze.

    dependencies {
        // This allows Android Studio to parse and validate your SDK APIs.
        ksp "androidx.privacysandbox.tools:tools-apicompiler:$privacy_sandbox_tools_version"
    
        // This contains the annotation classes to decorate your SDK APIs.
        implementation "androidx.privacysandbox.tools:tools:$privacy_sandbox_tools_version"
    
        // This is runtime dependency required by the generated server shim code for
        // backward compatibility.
        implementation "androidx.privacysandbox.sdkruntime:sdkruntime-provider:$privacy_sandbox_sdk_runtime_version"
    
        // These are runtime dependencies required by the generated server shim code as
        // they use Kotlin.
        implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1"
        implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1'
    
        // This is the core part of the UI library to help with UI notifications.
        implementation "androidx.privacysandbox.ui:ui-core:$privacy_sandbox_ui_version"
    
        // This helps the SDK open sessions for the ad.
        implementation "androidx.privacysandbox.ui:ui-provider:$privacy_sandbox_ui_version"
    
        // This is needed if your SDK implements mediation use cases
        implementation "androidx.privacysandbox.ui:ui-client:$privacy_sandbox_ui_version"
    }
    
  4. Sostituisci il file build.gradle nel modulo ASB abilitato per il runtime con quanto segue:

    plugins {
        id 'com.android.privacy-sandbox-sdk'
    }
    
    android {
        compileSdk 34
        minSdk 21
    
        bundle {
            // This is the package name of the SDK that you want to publish.
            // This is used as the public identifier of your SDK.
            // You use this later on to load the runtime-enabled SDK
            packageName = '<package name of your runtime-enabled SDK>'
    
            // This is the version of the SDK that you want to publish.
            // This is used as the public identifier of your SDK version.
            setVersion(1, 0, 0)
    
            // SDK provider defined in the SDK Runtime library.
            // This is an important part of the future backwards compatibility
            // support, most SDKs won't need to change it.
            sdkProviderClassName = "androidx.privacysandbox.sdkruntime.provider.SandboxedSdkProviderAdapter"
    
            // This is the class path of your implementation of the SandboxedSdkProviderCompat class.
            // It's the implementation of your runtime-enabled SDK's entry-point.
            // If you miss this step, your runtime-enabled SDK will fail to load at runtime:
            compatSdkProviderClassName = "<your-sandboxed-sdk-provider-compat-fully-qualified-class-name>"
        }
    }
    
    dependencies {
        // This declares the dependency on your runtime-enabled ad library module.
        include project(':<your-runtime-enabled-ad-library-here>')
    }
    
  5. Aggiorna il file build.gradle nel modulo della libreria annunci esistente (SDK RA) in modo da includere le seguenti dipendenze:

    dependencies {
        // This declares the client's dependency on the runtime-enabled ASB module.
        //  ⚠️ Important: We depend on the ASB module, not the runtime-enabled module.
        implementation project(':<your-runtime-enabled-asb-module-here>')
    
        // Required for backwards compatibility on devices where SDK Runtime is unavailable.
        implementation "androidx.privacysandbox.sdkruntime:sdkruntime-client:$privacy_sandbox_sdk_runtime_version"
    
        // This is required to display banner ads using the SandboxedUiAdapter interface.
        implementation "androidx.privacysandbox.ui:ui-core:$privacy_sandbox_ui_version"
        implementation "androidx.privacysandbox.ui:ui-client:$privacy_sandbox_ui_version"
    
        // This is required to use SDK ActivityLaunchers.
        implementation "androidx.privacysandbox.activity:activity-core:$privacy_sandbox_activity_version"
        implementation "androidx.privacysandbox.activity:activity-client:$privacy_sandbox_activity_version"
    }
    

Aggiungi la logica di business dell'SDK

Implementa la logica di business dell'SDK come faresti regolarmente nella modulo della libreria di annunci abilitato per il runtime.

Se stai eseguendo la migrazione di un SDK esistente, in questa fase sposta tutte le funzioni della logica di business, dell'interfaccia e del sistema che vuoi, ma tieni conto di una migrazione completa in futuro.

Se hai bisogno di accedere allo spazio di archiviazione, all'ID pubblicità di Google Play o all'ID set di app, leggi le seguenti sezioni:

Utilizzare le API di archiviazione nell'SDK

Gli SDK in SDK Runtime non possono più accedere, leggere o scrivere nella memoria interna di un'app e viceversa.

All'ambiente di runtime dell'SDK viene allocata una propria area di archiviazione interna, separata dall'app.

Gli SDK sono in grado di accedere a questo spazio di archiviazione interno separato utilizzando le API di archiviazione dei file nell'oggetto Context restituito da SandboxedSdkProvider#getContext().

Gli SDK possono usare solo la memoria interna; di conseguenza, solo le API di archiviazione interna, come Context.getFilesDir() o Context.getCacheDir() lavoro. Vedi altri esempi in Accesso dalla memoria interna.

L'accesso allo spazio di archiviazione esterno da SDK Runtime non è supportato. La chiamata delle API per accedere allo spazio di archiviazione esterno genera un'eccezione o restituisce null. Il seguente elenco include alcuni esempi:

Devi utilizzare Context restituito da SandboxedSdkProvider.getContext() per l'archiviazione. L'utilizzo dell'API di archiviazione file su qualsiasi altra istanza di oggetto Context, ad esempio il contesto dell'applicazione, non è garantito che funzioni come previsto in tutte le situazioni.

Il seguente snippet di codice mostra come utilizzare lo spazio di archiviazione in SDK Runtime:

class SdkServiceImpl(private val context: Context) : SdkService {
    override suspend fun getMessage(): String = "Hello from Privacy Sandbox!"

    override suspend fun createFile(sizeInMb: Int): String {
        val path = Paths.get(
            context.dataDir.path, "file.txt"
        )

        withContext(Dispatchers.IO) {
            Files.deleteIfExists(path)
            Files.createFile(path)
            val buffer = ByteArray(sizeInMb * 1024 * 1024)
            Files.write(path, buffer)
        }

        val file = File(path.toString())
        val actualFileSize: Long = file.length() / (1024 * 1024)
        return "Created $actualFileSize MB file successfully"
    }
}

All'interno dello spazio di archiviazione interno separato per ogni runtime dell'SDK, ogni SDK ha la propria directory di archiviazione. Lo spazio di archiviazione per SDK è una separazione logica dello spazio di archiviazione interno di SDK Runtime che consente di tenere conto della quantità di spazio di archiviazione utilizzata da ciascun SDK.

Tutte le API di archiviazione interna nell'oggetto Context restituiscono un percorso di archiviazione per ogni SDK.

Se il tuo SDK deve accedere all'ID pubblicità fornito da Google Play Services, utilizza AdIdManager#getAdId() per recuperare il valore in modo asincrono.

Se il tuo SDK richiede l'accesso all'ID set di app fornito da Google Play Services, usa AppSetIdManager#getAppSetId() per recuperare il valore in modo asincrono.

Dichiara le API SDK

Affinché l'SDK abilitato per il runtime sia accessibile al di fuori del runtime, devi per definire le API utilizzabili dai client (SDK RA o app client).

Utilizza le annotazioni per dichiarare queste interfacce.

Annotazioni

Le API SDK devono essere dichiarate in Kotlin come interfacce e classi di dati utilizzando le seguenti annotazioni:

Annotazioni
@PrivacySandboxService
  • Definisce il punto di ingresso per l'SDK RE
  • Deve essere univoco
@PrivacySandboxInterface
  • Consente un'ulteriore modularizzazione e l'esposizione delle interfacce
  • Può avere più istanze
@PrivacySandboxValue
  • Consente di inviare dati tra i processi
  • Simile agli struct immutabili, che possono restituire più valori di tipi diversi
@PrivacySandboxCallback
  • Dichiara le API con un callback
  • Fornisce un canale secondario per richiamare il codice cliente

Devi definire queste interfacce e classi in qualsiasi punto del modulo della libreria di annunci abilitata in fase di runtime.

Vedi l'utilizzo di queste annotazioni nelle sezioni seguenti.

@PrivacySandboxService
interface SdkService {
    suspend fun getMessage(): String

    suspend fun createFile(sizeInMb: Int): String

    suspend fun getBanner(request: SdkBannerRequest, requestMediatedAd: Boolean): SdkSandboxedUiAdapter?

    suspend fun getFullscreenAd(): FullscreenAd
}
@PrivacySandboxInterface
interface SdkSandboxedUiAdapter : SandboxedUiAdapter
@PrivacySandboxValue
data class SdkBannerRequest(
    /** The package name of the app. */
    val appPackageName: String,
    /**
     *  An [SdkActivityLauncher] used to launch an activity when the banner is clicked.
     */
    val activityLauncher: SdkActivityLauncher,
    /**
     * Denotes if a WebView banner ad needs to be loaded.
     */
    val isWebViewBannerAd: Boolean
)
@PrivacySandboxCallback
interface InAppMediateeSdkInterface {
    suspend fun show()
}

Tipi supportati

Le API SDK abilitate per il runtime supportano i seguenti tipi:

  • Tutti i tipi primitivi nel linguaggio di programmazione Java (come int, long, char, booleano e così via)
  • Stringa
  • Interfacce Kotlin annotate con @PrivacySandboxInterface o @PrivacySandboxCallback
  • Classi di dati Kotlin annotate con @PrivacySandboxValue
  • java.lang.List: tutti gli elementi nell'elenco devono essere uno dei dati supportati Tipi

Esistono alcuni altri aspetti da tenere presente:

  • Le classi di dati annotate con @PrivacySandboxValue non possono contenere campi di tipo @PrivacySandboxCallback
  • I tipi restituiti non possono contenere tipi annotati con @PrivacySandboxCallback
  • L'elenco non può contenere elementi di tipi annotati con @PrivacySandboxInterface o @PrivacySandboxCallback

API asincrone

Poiché le API SDK effettuano sempre una chiamata a un processo separato, assicurati che queste chiamate non blocchino il thread delle chiamate del client.

A questo scopo, tutti i metodi nelle interfacce sono annotati con @PrivacySandboxService, @PrivacySandboxInterface e @PrivacySandboxCallback devono essere dichiarate esplicitamente come API asincrone.

Le API asincrone possono essere implementate in Kotlin in due modi:

  1. Utilizza le funzioni di sospensione.
  2. Accetta i callback che ricevono una notifica al termine dell'operazione o di altri eventi durante l'avanzamento dell'operazione. Il tipo restituito della funzione deve essere una Unit.

Eccezioni

Le API SDK non supportano nessun tipo di eccezioni selezionate.

Il codice shim generato rileva eventuali eccezioni di runtime generate dall'SDK e la invia come PrivacySandboxException al cliente con informazioni la causa.

libreria UI

Se disponi di interfacce che rappresentano annunci, ad esempio un banner, devi implementare anche l'interfaccia di SandboxedUiAdapter per abilitare le sessioni di apertura per l'annuncio caricato.

Queste sessioni formano un canale laterale tra il client e l'SDK e soddisfano due scopi principali:

  • Ricevi notifiche ogni volta che si verifica un cambiamento dell'interfaccia utente.
  • Avvisa il cliente di eventuali modifiche alla presentazione dell'interfaccia utente.

Poiché il client può utilizzare l'interfaccia annotata con @PrivacySandboxService per comunicare con il tuo SDK, le API per il caricamento degli annunci possono essere aggiunte a questo a riga di comando.

Quando il client richiede di caricare un annuncio, carica l'annuncio e restituisci un'istanza dell'interfaccia che implementa SandboxedUiAdapter. In questo modo, il client può richiedere sessioni di apertura per quell'annuncio.

Quando il client richiede di aprire una sessione, l'SDK abilitato al runtime può creare una visualizzazione dell'annuncio utilizzando la risposta all'annuncio e il contesto fornito.

A questo scopo, crea una classe che implementi l'interfaccia SandboxedUiAdapter.Session e, quando viene chiamato SandboxedUiAdapter.openSession(), assicurati di chiamare client.onSessionOpened(), passando un'istanza della classe Session come parametro.

class SdkSandboxedUiAdapterImpl(
   private val sdkContext: Context,
   private val request: SdkBannerRequest,
) : SdkSandboxedUiAdapter {
   override fun openSession(
       context: Context,
       windowInputToken: IBinder,
       initialWidth: Int,
       initialHeight: Int,
       isZOrderOnTop: Boolean,
       clientExecutor: Executor,
       client: SandboxedUiAdapter.SessionClient
   ) {
       val session = SdkUiSession(clientExecutor, sdkContext, request)
       clientExecutor.execute {
           client.onSessionOpened(session)
       }
   }
}

Inoltre, questo corso riceve notifiche ogni volta che si verifica un cambiamento dell'interfaccia utente. Puoi utilizzare questa classe per ridimensionare l'annuncio o sapere, ad esempio, quando la configurazione è stata modificata.

Scopri di più sulle API di presentazione dell'interfaccia utente nel runtime.

Assistenza per l'attività

Per avviare le attività di proprietà dell'SDK da Privacy Sandbox, devi modificare l'API SDK per ricevere un oggetto SdkActivityLauncher, fornito anch'esso dalla libreria UI.

Ad esempio, la seguente API SDK dovrebbe avviare delle attività, quindi è previsto il parametro SdkActivityLauncher:

@PrivacySandboxInterface
interface FullscreenAd {
    suspend fun show(activityLauncher: SdkActivityLauncher)
}

Entry-point SDK

La classe astratta SandboxedSdkProvider incapsula l'API che SDK Runtime utilizza per interagire con gli SDK caricati al suo interno.

Un SDK abilitato per il runtime deve implementare questa classe astratta per generare un punto di ingresso affinché il runtime dell'SDK sia in grado di comunicare con quest'ultima.

Per il supporto della compatibilità con le versioni precedenti, abbiamo introdotto i seguenti tipi di classe:

Scopri di più sulla compatibilità con le versioni precedenti di SDK Runtime.

Gli strumenti di generazione di shim aggiungono un altro livello di astrazione: generano una classe astratta denominata AbstractSandboxedSdkProvider utilizzando l'interfaccia annotata con @PrivacySandboxService.

Questa classe estende SandboxedSdkProviderCompat e si trova all'interno dello stesso pacchetto dell'interfaccia annotata.

// Auto-generated code.
abstract class AbstractSandboxedSdkProvider : SandboxedSdkProviderCompat {
    abstract fun createMySdk(context: Context): MySdk
}

Questa classe generata espone un singolo metodo di fabbrica astratto che accetta una Context e prevede che venga restituito l'interfaccia annotata del tuo punto di ingresso.

Questo metodo prende il nome dall'interfaccia @PrivacySandboxService, con create premesso al nome. Ad esempio, se l'interfaccia si chiama MySdk, gli strumenti genereranno createMySdk.

Per connettere completamente il tuo punto di ingresso, devi fornire un'implementazione dell'interfaccia annotata @PrivacySandboxService nell'SDK abilitato per il runtime all'elemento AbstractSandboxedSdkProvider generato.

class MySdkSandboxedSdkProvider : AbstractSandboxedSdkProvider() {
    override fun createMySdk(context: Context): MySdk = MySdkImpl(context)
}

Modifiche al modulo ASB

Devi dichiarare il nome completo della classe dell'implementazione di SandboxedSdkProviderCompat nel campo compatSdkProviderClassName di build.gradle del modulo ASB.

Questa è la classe che hai implementato nel passaggio precedente. Devi modificare build.gradle sul modulo ASB nel seguente modo:

bundle {
    packageName = '<package name of your runtime-enabled SDK>'
    setVersion(1, 0, 0)

    // SDK provider defined in the SDK Runtime library.
    sdkProviderClassName = "androidx.privacysandbox.sdkruntime.provider.SandboxedSdkProviderAdapter"
    // This is the class that extends AbstractSandboxedSdkProvider,
    // MySdkSandboxProvider as per the example provided.
    compatSdkProviderClassName = "com.example.mysdk.MySdkSandboxProvider"
}

Passaggio 2: configura l'ambiente di sviluppo Passaggio 4: utilizza l'SDK abilitato per il runtime