Key concepts | Set up your development environment | Build an RE SDK | Consume the RE SDK | Testing, and building for distribution |
Laufzeitfähiges SDK erstellen
Führen Sie die folgenden Schritte aus, um ein laufzeitfähiges SDK zu erstellen:
- Projektstruktur einrichten
- Projekt- und Modulabhängigkeiten vorbereiten
- SDK-Geschäftslogik hinzufügen
- SDK APIs definieren
- Einstiegspunkt für das SDK angeben
Projektstruktur einrichten
Wir empfehlen, Ihr Projekt in die folgenden Module zu gliedern:
- 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
- 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.
- 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.
- 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:
)
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
Ä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 }
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" }
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>') }
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:
- Beim Zugriff auf Dateien mit dem Storage Access Framework wird eine SecurityException ausgelöst.
getExternalFilsDir()
gibt immer null zurück.
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.
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 |
|
@PrivacySandboxInterface |
|
@PrivacySandboxValue |
|
@PrivacySandboxCallback |
|
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:
- Verwenden Sie Unterbrechungsfunktionen.
- 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:
SandboxedSdkProviderAdapter
erweitertSandboxedSdkProvider
und verarbeitet SDK-Ladeanfragen unabhängig von der SDK-Laufzeitverfügbarkeit. Dieser wird intern verwendet und im ASB-Modul deklariert.SandboxedSdkProviderCompat
, eine abstrakte Klasse, die die Schnittstelle vonSandboxedSdkProvider
nachahmt.
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 einrichtenSchritt 4: Laufzeitfähiges SDK verwenden