Tworzenie i wykorzystywanie pakietu SDK z włączonym środowiskiem wykonawczym

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

Tworzenie pakietu SDK z włączonym środowiskiem wykonawczym

Aby utworzyć pakiet SDK obsługujący środowisko wykonawcze, musisz wykonać te czynności:

  1. Konfigurowanie struktury projektu
  2. Przygotowywanie zależności projektu i modułów
  3. Dodawanie logiki biznesowej związanej z pakietem SDK
  4. Definiowanie interfejsów API pakietu SDK
  5. Określanie punktu wejścia pakietu SDK

Konfigurowanie struktury projektu

Zalecamy, aby projekt składał się z tych modułów:

  1. 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).
  2. 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.
  3. 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 .
  4. 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:)
  1. 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
    
  2. 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
    }
    
  3. 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"
    }
    
  4. 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>')
    }
    
  5. 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:

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
  • Określa punkt wejścia dla pakietu SDK RE
  • Musi być niepowtarzalna
@PrivacySandboxInterface
  • Umożliwia dodatkową modularyzację i udostępnianie interfejsów.
  • Może mieć wiele instancji
@PrivacySandboxValue
  • Umożliwia wysyłanie danych między procesami
  • Są podobne do stałych elementów struct, które mogą zwracać wiele wartości różnych typów.
@PrivacySandboxCallback
  • Deklaruje interfejsy API za pomocą wywołania zwrotnego
  • Udostępnia kanał tylny do wywoływania kodu klienta

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:

  1. Użyj funkcji zawieszania.
  2. 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:

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 programistyczne Krok 4. Skorzystaj z pakietu SDK używanego w czasie działania aplikacji