Key concepts | Set up your development environment | Build an RE SDK | Consume the RE SDK | Testing, and building for distribution |
Tworzenie pakietu SDK z włączonym środowiskiem wykonawczym
Aby utworzyć pakiet SDK obsługujący środowisko wykonawcze, musisz wykonać te czynności:
- Konfigurowanie struktury projektu
- Przygotowywanie zależności projektu i modułów
- Dodawanie logiki biznesowej związanej z pakietem SDK
- Definiowanie interfejsów API pakietu SDK
- Określanie punktu wejścia pakietu SDK
Konfigurowanie struktury projektu
Zalecamy, aby projekt składał się z tych modułów:
- Moduł aplikacji – aplikacja testowa, której używasz do testowania i tworzenia SDK reprezentujący rzeczywiste aplikacje klienckie. Aplikacja powinna zależą od modułu biblioteki reklam (pakietu SDK środowiska wykonawczego).
- Istniejący moduł biblioteki reklam (pakiet SDK środowiska wykonawczego) – moduł biblioteki na Androida
które zawierają istniejące zasoby, które nie są włączone w czasie działania aplikacji. Statyczna logika pakietu SDK
połączony pakiet SDK.
- Na początek funkcje można podzielić. Na przykład część kodu może być są obsługiwane przez istniejący pakiet SDK, a niektóre z nich mogą być kierowane do środowiska wykonawczego SDK.
- Moduł biblioteki reklam z włączonym środowiskiem wykonawczym – zawiera pakiet SDK dostępny w czasie działania aplikacji. to logika biznesowa. Można go utworzyć w Android Studio jako bibliotekę Androida .
- Moduł ASB z włączonym środowiskiem wykonawczym – definiuje dane pakietu, w którym zostaną
kodu SDK używanego w czasie działania aplikacji do pakietu ASB.
- Należy go utworzyć ręcznie za pomocą com.android.privacy-sandbox-sdk. Możesz to zrobić, tworząc nowego katalogu.
- Ten moduł nie powinien zawierać żadnego kodu, tylko pusty plik build.gradle plik zawierający zależności modułu biblioteki reklam z włączonym środowiskiem wykonawczym. Zawartość tego pliku jest określona w Przygotuj swój pakiet SDK.
- Pamiętaj, aby umieścić ten moduł w pliku settings.gradle oraz w pliku w istniejącym module biblioteki reklam.
Struktura projektu opisana w tym przewodniku jest sugestią. Możesz wybrać inny, dla pakietu SDK i zastosować te same zasady techniczne. Zawsze możesz utworzyć inne moduły dodatkowe, aby połączyć kod w aplikacji i moduły biblioteki z modułów.
Przygotowywanie pakietu SDK
Aby przygotować projekt do programowania pakietu SDK używanego w czasie działania aplikacji, musisz wykonać te czynności: najpierw zdefiniuj niektóre zależności narzędzi i bibliotek:
- Środowisko wykonawcze SDK ma biblioteki zgodności wstecznej, które obsługują
urządzenia bez Piaskownicy prywatności (Android 13 i starsze)
(
androidx.privacysandbox.sdkruntime:
) - Biblioteki interfejsu do obsługi prezentacji reklam (
androidx.privacysandbox.ui:
) - Narzędzia dla deweloperów w pakiecie SDK do obsługi deklaracji interfejsu API pakietu SDK i generowania podkładek (
androidx.privacysandbox.tools:
)
Dodaj tę flagę do pliku gradle.properties projektu, aby umożliwić tworzenie pakietów SDK używanych w czasie działania aplikacji.
# This enables the Privacy Sandbox for your project on Android Studio. android.experimental.privacysandboxsdk.enable=true android.experimental.privacysandboxsdk.requireServices=false
Zmodyfikuj plik build.gradle projektu, aby uwzględnić pomocnicze biblioteki Jetpack i inne zależności:
// 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 }
Zaktualizuj plik build.gradle w module biblioteki reklam z włączonym środowiskiem wykonawczym (RE SDK), aby uwzględnić te zależności.
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" }
Zastąp plik build.gradle w module ASB obsługującym środowisko wykonawcze następującym:
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>') }
Zaktualizuj plik build.gradle w dotychczasowym module biblioteki reklam (RA SDK), aby uwzględnić te zależności:
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" }
Dodaj logikę biznesową pakietu SDK
Wdróż logikę biznesową pakietu SDK w taki sam sposób jak w ramach który działa w czasie działania aplikacji.
Jeśli masz aktualny pakiet SDK, który przenosisz, na tym etapie ustaw dowolną część logiki biznesowej, interfejsu i funkcji obsługi systemu, ale pamiętaj o pełnej migracji w przyszłości.
Jeśli potrzebujesz dostępu do miejsca na dane, identyfikatora wyświetlania reklam w Google Play lub identyfikatora zestawu aplikacji, przeczytaj te sekcje:
Używanie interfejsów API pamięci masowej w pakiecie SDK
Pakiety SDK w środowisku wykonawczym SDK nie mają już dostępu do pamięci wewnętrznej aplikacji, nie mogą też jej odczytywać ani zapisywać i na odwrót.
Środowisko wykonawcze SDK przydziela własną pamięć wewnętrzną, niezależną od aplikacji.
Pakiety SDK mają dostęp do tej oddzielnej pamięci wewnętrznej za pomocą interfejsów API do przechowywania plików w obiekcie Context
zwracanym przez funkcję SandboxedSdkProvider#getContext()
.
Pakiety SDK mogą korzystać tylko z pamięci wewnętrznej, więc wyłącznie interfejsy API pamięci wewnętrznej, takie jak Context.getFilesDir()
lub
Context.getCacheDir()
do pracy. Zobacz więcej przykładów w
Dostęp z pamięci wewnętrznej.
Dostęp do pamięci zewnętrznej ze środowiska wykonawczego SDK nie jest obsługiwany. Wywołanie interfejsów API w celu uzyskania dostępu do pamięci zewnętrznej spowoduje zgłoszenie wyjątku lub zwrócenie wartości null. Oto kilka przykładów:
- Uzyskiwanie dostępu do plików przy użyciu platformy Storage Access Framework powoduje zgłoszenie SecurityException.
getExternalFilsDir()
zawsze zwraca wartość null.
Aby uzyskać miejsce na dane, musisz wykorzystać środki w wysokości Context
zwrócone przez użytkownika SandboxedSdkProvider.getContext()
. Nie ma gwarancji, że interfejs File Storage API w innej instancji obiektu Context
, np. w kontekście aplikacji, będzie działać zgodnie z oczekiwaniami we wszystkich sytuacjach.
Ten fragment kodu pokazuje, jak korzystać z pamięci w środowisku wykonawczym SDK:
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" } }
Każdy pakiet SDK ma własny katalog pamięci wewnętrznej w osobnej pamięci wewnętrznej dla każdego środowiska wykonawczego SDK. Przechowywanie danych według pakietu SDK to logiczna segregacja pamięci wewnętrznej środowiska wykonawczego SDK, która pomaga uwzględnić ilość miejsca wykorzystywanego przez poszczególne pakiety SDK.
Wszystkie interfejsy API pamięci wewnętrznej w obiekcie Context
zwracają ścieżkę pamięci dla każdego pakietu SDK.
Korzystanie z identyfikatora wyświetlania reklam udostępnianego przez Usługi Google Play
Jeśli Twój pakiet SDK wymaga dostępu do identyfikatora wyświetlania reklam udostępnianego przez Usługi Google Play, użyj metody AdIdManager#getAdId()
, aby asynchronicznie pobrać wartość.
Uzyskiwanie dostępu do identyfikatora zestawu aplikacji udostępnianego przez Usługi Google Play
Jeśli Twój pakiet SDK potrzebuje dostępu do identyfikatora zestawu aplikacji udostępnianego przez Usługi Google Play, użyj
AppSetIdManager#getAppSetId()
, aby asynchronicznie pobrać wartość.
Deklarowanie interfejsów API pakietu SDK
Aby pakiet SDK obsługujący środowisko wykonawcze był dostępny poza środowiskiem wykonawczym, musisz mieć aby zdefiniować interfejsy API, których mogą używać klienci (pakiet SDK RA lub aplikacja kliencka).
Użyj adnotacji do zadeklarowania tych interfejsów.
Adnotacje
Interfejsy API pakietu SDK należy zadeklarować w Kotlin jako interfejsy i klasy danych za pomocą następujące adnotacje:
Adnotacje | |
---|---|
@PrivacySandboxService |
|
@PrivacySandboxInterface |
|
@PrivacySandboxValue |
|
@PrivacySandboxCallback |
|
Te interfejsy i klasy musisz zdefiniować w dowolnym miejscu który działa w czasie działania aplikacji.
Informacje o wykorzystaniu tych adnotacji znajdziesz w kolejnych sekcjach.
@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() }
Typy obsługiwane
Interfejsy API pakietu SDK obsługujące środowisko wykonawcze obsługują te typy:
- Wszystkie typy podstawowe w języku programowania Java (np. int, long, char, boolean itp.)
- Ciąg znaków
- Interfejsy Kotlin z adnotacjami
@PrivacySandboxInterface
lub@PrivacySandboxCallback
- Klasy danych Kotlin z adnotacjami za pomocą funkcji
@PrivacySandboxValue
- java.lang.List – wszystkie elementy listy muszą należeć do obsługiwanych danych Typy
Jest kilka dodatkowych zastrzeżeń:
- Klasy danych z adnotacjami
@PrivacySandboxValue
nie mogą zawierać pól: wpisz@PrivacySandboxCallback
- Typy zwrotów nie mogą zawierać typów z adnotacjami za pomocą atrybutu
@PrivacySandboxCallback
- Lista nie może zawierać elementów typów z adnotacjami
@PrivacySandboxInterface
lub@PrivacySandboxCallback
Asynchroniczne interfejsy API
Interfejsy API pakietu SDK zawsze wywołują oddzielny proces, więc musimy upewnij się, że te wywołania nie blokują wątku wywołującego klienta.
Aby to osiągnąć, wszystkie metody w interfejsach opisane przy użyciu
@PrivacySandboxService
, @PrivacySandboxInterface
i @PrivacySandboxCallback
muszą być jawnie zadeklarowane jako asynchroniczne interfejsy API.
Asynchroniczne interfejsy API można wdrożyć w Kotlin na 2 sposoby:
- Użyj funkcji zawieszania.
- Akceptuj wywołania zwrotne, które otrzymają powiadomienie o zakończeniu operacji, lub inne zdarzenia w trakcie jej trwania. Typ zwracany parametru musi być jednostką.
Wyjątki
Interfejsy API pakietu SDK nie obsługują żadnych form sprawdzonych wyjątków.
Wygenerowany kod podkładki wykrywa wszystkie wyjątki w czasie działania zgłoszone przez SDK oraz
przekazuje je jako PrivacySandboxException
do klienta z informacjami o
uwidocznioną w nim przyczynę.
Biblioteka UI
Jeśli korzystasz z interfejsów reprezentujących reklamy (np. banerów), musisz też zaimplementować interfejs SandboxedUiAdapter
, by umożliwić sesje otwarcia wczytanej reklamy.
Sesje te stanowią poboczny kanał komunikacji między klientem a pakietem SDK, realizacji 2 głównych celów:
- Otrzymuj powiadomienia za każdym razem, gdy nastąpi zmiana interfejsu.
- Powiadom klienta o wszelkich zmianach w prezentacji interfejsu.
Ponieważ klient może używać interfejsu z adnotacją @PrivacySandboxService
do
komunikuje się z pakietem SDK, można do niego dodać dowolne interfejsy API do wczytywania reklam
za pomocą prostego interfejsu online.
Gdy klient zażąda wczytania reklamy, wczyta ją i zwróci wystąpienie
zaimplementuj interfejs SandboxedUiAdapter
. Dzięki temu klient może zażądać sesji otwarcia danej reklamy.
Gdy klient poprosi o otwarcie sesji, pakiet SDK obsługujący środowisko wykonawcze może utworzyć widok reklamy, korzystając z odpowiedzi na reklamę i podanego kontekstu.
Aby to osiągnąć, utwórz klasę implementującą interfejs SandboxedUiAdapter.Session
. Po wywołaniu funkcji SandboxedUiAdapter.openSession()
upewnij się, że wywołujesz client.onSessionOpened()
, przesyłając wystąpienie klasy Session
jako parametr.
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)
}
}
}
Ta klasa otrzymuje też powiadomienia po każdej zmianie interfejsu użytkownika. Dostępne opcje użyj tej klasy, by zmienić rozmiar reklamy lub np. dowiedzieć się, kiedy nastąpiła zmiana konfiguracji.
Dowiedz się więcej o interfejsach API do prezentacji UI w środowisku wykonawczym
Wsparcie dla aktywności
Aby uruchomić należące do pakietu SDK działania z Piaskownicy prywatności, musisz zmodyfikować interfejs SDK API tak, aby otrzymywał obiekt SdkActivityLauncher
również z biblioteki UI.
Na przykład ten interfejs API pakietu SDK powinien uruchamiać działania, więc oczekuje parametru SdkActivityLauncher
:
@PrivacySandboxInterface
interface FullscreenAd {
suspend fun show(activityLauncher: SdkActivityLauncher)
}
Punkt wejścia pakietu SDK
Klasa abstrakcyjna SandboxedSdkProvider
.
zawiera interfejs API, którego środowisko wykonawcze SDK używa do interakcji z wczytanymi pakietami SDK.
Pakiet SDK obsługujący środowisko wykonawcze musi zaimplementować tę klasę abstrakcyjną, aby wygenerować punkt wejścia, który umożliwi mu komunikację z nią.
Aby zapewnić zgodność wsteczną, wprowadziliśmy te klasy:
SandboxedSdkProviderAdapter
, która rozszerza możliwości pakietuSandboxedSdkProvider
i obsługuje żądania wczytywania pakietu SDK niezależnie od dostępności środowiska wykonawczego SDK. Jest używane wewnętrznie zadeklarowane w module ASB.SandboxedSdkProviderCompat
– klasa abstrakcyjna, która imituje interfejs klasySandboxedSdkProvider
.
Więcej informacji o zgodności wstecznej środowiska wykonawczego SDK
Narzędzia do generowania podkładek dodają kolejną warstwę abstrakcji: generują klasę abstrakcyjną o nazwie AbstractSandboxedSdkProvider
za pomocą interfejsu oznaczonego przez Ciebie adnotacją @PrivacySandboxService
.
Ta klasa wykracza poza zakres SandboxedSdkProviderCompat
i należy do tego samego pakietu co interfejs z adnotacjami.
// Auto-generated code.
abstract class AbstractSandboxedSdkProvider : SandboxedSdkProviderCompat {
abstract fun createMySdk(context: Context): MySdk
}
Ta wygenerowana klasa ujawnia jedną abstrakcyjną metodę fabryki, która pobiera
Context
i oczekuje, że interfejs z adnotacjami zostanie zwrócony.
Nazwa tej metody pochodzi od interfejsu @PrivacySandboxService
(na początku)
create
. Jeśli na przykład interfejs nazywa się MySdk
, narzędzia
wygenerować createMySdk
.
Aby w pełni połączyć punkt wejścia, musisz w wygenerowanym AbstractSandboxedSdkProvider
udostępnić implementację interfejsu z adnotacjami @PrivacySandboxService
w pakiecie SDK obsługującym środowisko wykonawcze.
class MySdkSandboxedSdkProvider : AbstractSandboxedSdkProvider() {
override fun createMySdk(context: Context): MySdk = MySdkImpl(context)
}
Zmiany w module ASB
W polu compatSdkProviderClassName
w pliku build.gradle modułu ASB musisz zadeklarować pełną nazwę klasy implementacji interfejsu SandboxedSdkProviderCompat
.
To klasa zaimplementowana w poprzednim kroku. Musisz zmodyfikować plik build.gradle w module ASB w ten sposób:
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"
}
Krok 2. Skonfiguruj środowisko programistyczneKrok 4. Skorzystaj z pakietu SDK używanego w czasie działania aplikacji