Runtime-fähiges SDK erstellen und nutzen

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

Laufzeitfähiges SDK erstellen

Führen Sie die folgenden Schritte aus, um ein laufzeitfähiges SDK zu erstellen:

  1. Projektstruktur einrichten
  2. Projekt- und Modulabhängigkeiten vorbereiten
  3. SDK-Geschäftslogik hinzufügen
  4. SDK APIs definieren
  5. Einstiegspunkt für das SDK angeben

Projektstruktur einrichten

Wir empfehlen, Ihr Projekt in die folgenden Module zu gliedern:

  1. App-Modul: Die Test-App, die Sie zum Testen und Entwickeln Ihrer SDK, das dem tatsächlichen App-Client entspricht. Ihre App sollte eine Abhängigkeit vom vorhandenen Anzeigenbibliotheksmodul (runtime-aware SDK) haben
  2. Vorhandenes Anzeigenbibliotheksmodul (runtime-aware SDK): ein Android-Bibliotheksmodul mit Ihren vorhandenen „nicht zur Laufzeit aktivierten“ SDK-Logik, eine statische verknüpftes SDK.
    • Zu Beginn können die Funktionen aufgeteilt werden. Beispielsweise kann Code die von Ihrem vorhandenen SDK verarbeitet werden, und einige können an die laufzeitfähige SDK.
  3. Modul für laufzeitfähige Anzeigenbibliothek – enthält Ihr laufzeitfähiges SDK Geschäftslogik. Dies kann in Android Studio als Android-Bibliothek erstellt werden. -Modul.
  4. Laufzeitfähiges ASB-Modul: Definiert die Paketdaten zum Bündeln der laufzeitfähigen SDK-Code in ein ASB.
    • Sie muss manuell mit der Methode com.android.privacy-sandbox-sdk. Erstellen Sie dazu eine neuen Verzeichnis.
    • Dieses Modul sollte keinen Code und nur eine leere build.gradle-Datei enthalten Datei mit Abhängigkeiten zu Ihrem laufzeitfähigen Anzeigenbibliotheksmodul. Der Inhalt dieser Datei ist definiert in Bereiten Sie Ihr SDK vor.
    • Denken Sie daran, dieses Modul in die Datei „settings.gradle“ und im bestehenden Anzeigenbibliothek-Moduls.

Die Projektstruktur in diesem Leitfaden ist ein Vorschlag. Sie können eine andere Struktur für Ihr SDK und wenden Sie dieselben technischen Prinzipien an. Sie können jederzeit weitere Module erstellen, um den Code in der App und in den Bibliotheksmodulen zu modularisieren.

SDK vorbereiten

Zur Vorbereitung Ihres Projekts für die laufzeitfähige SDK-Entwicklung müssen Sie zunächst einige Tool- und Bibliotheksabhängigkeiten definieren:

  • SDK Runtime-Abwärtskompatibilitätsbibliotheken, die Geräte ohne die Privacy Sandbox (Android 13 und niedriger) (androidx.privacysandbox.sdkruntime:)
  • UI-Bibliotheken zur Unterstützung der Anzeigenpräsentation (androidx.privacysandbox.ui:)
  • SDK-Entwicklertools zur Unterstützung der SDK API-Deklaration und der Shim-Generierung (androidx.privacysandbox.tools:)
  1. Fügen Sie dieses Flag zur Datei „gradle.properties“ Ihres Projekts hinzu, damit laufzeitfähige SDKs erstellt werden können.

    # This enables the Privacy Sandbox for your project on Android Studio.
    android.experimental.privacysandboxsdk.enable=true
    android.experimental.privacysandboxsdk.requireServices=false
    
  2. Ändern Sie die build.gradle-Datei Ihres Projekts, um die Jetpack-Hilfsbibliotheken und andere Abhängigkeiten einzubeziehen:

    // 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. Aktualisieren Sie die Datei „build.gradle“ im Modul runtime-enabled ad library (RE SDK) so, dass sie diese Abhängigkeiten enthält.

    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. Ersetzen Sie die Datei build.gradle in Ihrem laufzeitfähigen ASB-Modul durch Folgendes:

    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. Aktualisieren Sie die Datei „build.gradle“ in Ihrem vorhandenen RA SDK-Modul (Ad Library), sodass sie die folgenden Abhängigkeiten enthält:

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

SDK-Geschäftslogik hinzufügen

Implementieren Sie die Geschäftslogik Ihres SDKs wie gewohnt im laufzeitfähige Anzeigenbibliotheksmodul.

Wenn Sie ein vorhandenes SDK migrieren, verschieben Sie in dieser Phase so viel von der Geschäftslogik, der Benutzeroberfläche und den systemseitigen Funktionen, wie Sie möchten. Berücksichtigen Sie jedoch eine vollständige Migration in der Zukunft.

Wenn Sie Zugriff auf den Speicherplatz, die Google Play-Werbe-ID oder die App-Set-ID benötigen, lesen Sie die folgenden Abschnitte:

Storage APIs im SDK verwenden

SDKs in der SDK Runtime können nicht mehr auf den internen Speicher einer App zugreifen, Daten lesen oder schreiben und umgekehrt.

Der SDK Runtime wird ein eigener interner Speicherbereich zugewiesen, der von der App getrennt ist.

SDKs können über die Dateispeicher-APIs im Context-Objekt, das von SandboxedSdkProvider#getContext() zurückgegeben wird, auf diesen separaten internen Speicher zugreifen.

SDKs können nur internen Speicher nutzen, also nur interne Speicher-APIs wie Context.getFilesDir() oder Context.getCacheDir() Arbeit. Weitere Beispiele finden Sie unter Zugriff aus dem internen Speicher.

Der Zugriff auf externen Speicher über die SDK-Laufzeit wird nicht unterstützt. Beim Aufrufen von APIs für den Zugriff auf externen Speicher wird entweder eine Ausnahme ausgelöst oder null zurückgegeben. Die folgende Liste enthält einige Beispiele:

Du musst die von SandboxedSdkProvider.getContext() zurückgegebene Context als Speicher verwenden. Die Verwendung der File Storage API in einer anderen Context-Objektinstanz, z. B. im Anwendungskontext, funktioniert möglicherweise nicht in allen Situationen wie erwartet.

Das folgende Code-Snippet zeigt, wie Speicher in der SDK-Laufzeit verwendet wird:

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

Innerhalb des separaten internen Speichers für jede SDK-Laufzeit hat jedes SDK ein eigenes Speicherverzeichnis. Der Speicher pro SDK ist eine logische Trennung des internen Speichers der SDK Runtime, mit dem angegeben wird, wie viel Speicherplatz jedes SDK verwendet.

Alle internen Speicher-APIs im Objekt Context geben für jedes SDK einen Speicherpfad zurück.

Auf die von den Google Play-Diensten bereitgestellte Werbe-ID zugreifen

Wenn dein SDK Zugriff auf die von den Google Play-Diensten bereitgestellte Werbe-ID benötigt, kannst du den Wert mit AdIdManager#getAdId() asynchron abrufen.

<ph type="x-smartling-placeholder">

Auf die von den Google Play-Diensten bereitgestellte App-Set-ID zugreifen

Wenn Ihr SDK Zugriff auf die von den Google Play-Diensten bereitgestellte App-Set-ID benötigt, verwenden Sie AppSetIdManager#getAppSetId(), um den Wert asynchron abzurufen.

SDK-APIs deklarieren

Damit außerhalb der Laufzeit auf Ihr laufzeitfähiges SDK zugegriffen werden kann, müssen Sie um APIs zu definieren, die Clients (RA SDK oder die Client-App) nutzen können.

Verwenden Sie Anmerkungen, um diese Schnittstellen zu deklarieren.

Annotationen

SDK APIs müssen in Kotlin mit der Methode folgenden Annotationen:

Annotationen
@PrivacySandboxService
  • Definiert den Einstiegspunkt für das RE SDK
  • Muss eindeutig sein
@PrivacySandboxInterface
  • Ermöglicht eine weitere Modularisierung und die Bereitstellung von Schnittstellen
  • Kann mehrere Instanzen haben
@PrivacySandboxValue
  • Ermöglicht das prozessübergreifende Senden von Daten
  • Ähnlich wie unveränderliche Strukturen, die mehrere Werte verschiedener Typen zurückgeben können
@PrivacySandboxCallback
  • Deklariert APIs per Callback
  • Stellt einen Back-Channel zum Aufrufen von Clientcode bereit.

Sie müssen diese Schnittstellen und Klassen überall innerhalb der laufzeitfähige Anzeigenbibliotheksmodul.

In den folgenden Abschnitten erfahren Sie mehr über die Verwendung dieser Annotationen.

@PrivacySandboxService

@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

@PrivacySandboxInterface
interface SdkSandboxedUiAdapter : SandboxedUiAdapter

@PrivacySandboxValue

@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

@PrivacySandboxCallback
interface InAppMediateeSdkInterface {
    suspend fun show()
}

Unterstützte Typen

Laufzeitfähige SDK APIs unterstützen die folgenden Typen:

  • Alle primitiven Typen in der Programmiersprache Java (z. B. int, long, char, boolean usw.)
  • String
  • Kotlin-Schnittstellen, die mit @PrivacySandboxInterface oder @PrivacySandboxCallback
  • Mit @PrivacySandboxValue annotierte Kotlin-Datenklassen
  • java.lang.List - Alle Elemente in der Liste müssen eines der unterstützten Daten sein. Typen

Es gibt zusätzliche Einschränkungen:

  • Mit @PrivacySandboxValue annotierte Datenklassen dürfen keine Felder mit folgender Kennzeichnung enthalten: Typ @PrivacySandboxCallback
  • Rückgabetypen dürfen keine mit @PrivacySandboxCallback annotierten Typen enthalten
  • Die Liste darf keine Elemente von Typen enthalten, die mit annotiert sind @PrivacySandboxInterface oder @PrivacySandboxCallback

Asynchrone APIs

Da die SDK APIs immer einen separaten Prozess aufrufen, müssen wir dass diese Aufrufe den aufrufenden Thread des Clients nicht blockieren.

Um dies zu erreichen, werden alle Methoden in den mit @PrivacySandboxService, @PrivacySandboxInterface und @PrivacySandboxCallback explizit als asynchrone APIs deklariert werden.

Es gibt zwei Möglichkeiten, asynchrone APIs in Kotlin zu implementieren:

  1. Verwenden Sie Unterbrechungsfunktionen.
  2. Callbacks akzeptieren, die benachrichtigt werden, wenn der Vorgang abgeschlossen ist andere Ereignisse während des Vorgangs. Der Rückgabetyp der muss eine Einheit sein.

Ausnahmen

Die SDK APIs unterstützen keine geprüften Ausnahmen.

Der generierte Shim-Code fängt alle vom SDK ausgelösten Laufzeitausnahmen ab und übergibt sie als PrivacySandboxException an den Client mit Informationen zu die Ursache darin zu finden.

UI-Bibliothek

Wenn Sie Benutzeroberflächen für Google Ads-Anzeigen haben, z. B. Banner, müssen Sie auch die SandboxedUiAdapter-Oberfläche implementieren, um das Öffnen von Sitzungen für die geladene Anzeige zu ermöglichen.

Diese Sitzungen bilden einen Seitenkanal zwischen dem Client und dem SDK. erfüllen zwei Hauptzwecke:

  • Sie erhalten Benachrichtigungen bei jeder Änderung der Benutzeroberfläche.
  • Benachrichtigen Sie den Kunden über alle Änderungen an der UI-Präsentation.

Da der Client die mit @PrivacySandboxService annotierte Schnittstelle verwenden kann, um mit Ihrem SDK kommunizieren können, können Sie APIs zum Laden von Anzeigen hinzufügen. .

Wenn der Client das Laden einer Anzeige anfordert, wird die Anzeige geladen und eine Instanz von die Schnittstelle zur Implementierung von SandboxedUiAdapter So kann der Client das Öffnen von Sitzungen für diese Anzeige anfordern.

Wenn der Client das Öffnen einer Sitzung anfordert, kann Ihr laufzeitfähiges SDK mithilfe der Anzeigenantwort und des bereitgestellten Kontexts eine Anzeigenansicht erstellen.

Dazu erstellen Sie eine Klasse, die die SandboxedUiAdapter.Session-Schnittstelle implementiert. Wenn SandboxedUiAdapter.openSession() aufgerufen wird, müssen Sie client.onSessionOpened() aufrufen und eine Instanz der Session-Klasse als Parameter übergeben.

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

Diese Klasse erhält außerdem Benachrichtigungen, wenn eine Änderung der Benutzeroberfläche erfolgt. Sie können verwenden Sie diese Klasse, um die Größe der Anzeige anzupassen oder um beispielsweise zu erfahren, wann die Konfiguration geändert wurde.

Weitere Informationen zu UI-Darstellungs-APIs in der Laufzeit

Unterstützte Aktivitäten

Wenn Sie SDK-eigene Aktivitäten aus der Privacy Sandbox starten möchten, müssen Sie die SDK API so ändern, dass sie ein SdkActivityLauncher-Objekt empfängt, das auch von der UI-Bibliothek bereitgestellt wird.

Die folgende SDK API sollte beispielsweise Aktivitäten starten, also erwartet sie den Parameter SdkActivityLauncher:

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

SDK-Einstiegspunkt

Abstrakte Klasse SandboxedSdkProvider kapselt die API, die die SDK Runtime für die Interaktion mit den darin geladenen SDKs verwendet.

Ein laufzeitfähiges SDK muss diese abstrakte Klasse implementieren, um einen Einstiegspunkt für die SDK-Laufzeit zu generieren, damit sie mit ihr kommunizieren kann.

Zur Unterstützung der Abwärtskompatibilität haben wir die folgenden Klassen eingeführt:

Weitere Informationen zur Abwärtskompatibilität für die SDK Runtime.

Die Tools zur Shim-Generierung fügen eine weitere Abstraktionsebene hinzu: Sie generieren eine abstrakte Klasse namens AbstractSandboxedSdkProvider über die Oberfläche, die Sie mit @PrivacySandboxService annotiert haben.

Diese Klasse ist eine Erweiterung von SandboxedSdkProviderCompat und befindet sich im selben Paket wie Ihre annotierte Schnittstelle.

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

Diese generierte Klasse stellt eine einzelne abstrakte Factory-Methode bereit, die eine Context und erwartet, dass die mit dem Einstiegspunkt annotierte Schnittstelle zurückgegeben wird.

Diese Methode ist nach Ihrer @PrivacySandboxService-Schnittstelle benannt, create zum Namen hinzu. Lautet die Schnittstelle beispielsweise MySdk, createMySdk generieren.

Zum vollständigen Verbinden Ihres Einstiegspunkts müssen Sie eine Implementierung Ihrer mit @PrivacySandboxService annotierten Schnittstelle im laufzeitfähigen SDK in der generierten AbstractSandboxedSdkProvider bereitstellen.

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

Änderungen am ASB-Modul

Sie müssen den voll qualifizierten Klassennamen Ihrer Implementierung von SandboxedSdkProviderCompat im Feld compatSdkProviderClassName der build.gradle-Datei Ihres ASB-Moduls angeben.

Dies ist die Klasse, die Sie im vorherigen Schritt implementiert haben. Sie würden die build.gradle-Datei in Ihrem ASB-Modul wie folgt ändern:

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

Schritt 2: Entwicklungsumgebung einrichten Schritt 4: Laufzeitfähiges SDK verwenden