Создайте и используйте SDK с поддержкой среды выполнения.

1
Ключевые понятия
2
Настройте среду разработки
3
Создайте RE SDK
4
Используйте RE SDK
5
Тестирование и сборка для распространения
,
1
Ключевые понятия
2
Настройте среду разработки
3
Создайте RE SDK
4
Используйте RE SDK
5
Тестирование и сборка для распространения

Создайте SDK с поддержкой среды выполнения.

Для создания SDK с поддержкой среды выполнения необходимо выполнить следующие шаги:

  1. Настройте структуру вашего проекта.
  2. Подготовьте зависимости вашего проекта и модуля.
  3. Добавьте бизнес-логику из вашего SDK.
  4. Определите API SDK.
  5. Укажите точку входа для вашего SDK.

Настройте структуру вашего проекта.

Мы рекомендуем организовать ваш проект в следующие модули:

  1. Модуль приложения — тестовое приложение, которое вы используете для тестирования и разработки вашего SDK, имитирующее то, что будет доступно вашим реальным клиентам. Ваше приложение должно зависеть от существующего модуля библиотеки рекламы ( SDK, поддерживающий среду выполнения ).
  2. Существующий модуль библиотеки рекламы (SDK, поддерживающий среду выполнения) — модуль библиотеки Android, содержащий существующую логику SDK, не поддерживающую среду выполнения, статически связанный SDK.
    • Для начала, возможности можно разделить. Например, часть кода может обрабатываться существующим SDK, а часть — SDK, поддерживающим среду выполнения.
  3. Модуль библиотеки рекламы с поддержкой среды выполнения — содержит бизнес-логику вашего SDK с поддержкой среды выполнения. Его можно создать в Android Studio как модуль библиотеки Android.
  4. Модуль ASB с поддержкой среды выполнения — определяет данные пакета для объединения кода SDK с поддержкой среды выполнения в модуль ASB.
    • Его необходимо создать вручную, используя тип com.android.privacy-sandbox-sdk . Это можно сделать, создав новую директорию.
    • Этот модуль не должен содержать никакого кода, а только пустой файл build.gradle с зависимостями от вашего модуля библиотеки рекламы, поддерживающего среду выполнения . Содержимое этого файла определено в разделе «Подготовка SDK» .
    • Не забудьте добавить этот модуль в файл settings.gradle, а также в существующий модуль библиотеки рекламы.

Представленная в этом руководстве структура проекта является рекомендацией; вы можете выбрать другую структуру для своего SDK, применяя те же технические принципы. Вы всегда можете создать дополнительные модули для модульной организации кода в приложении и модулях библиотеки.

Подготовьте свой SDK

Для подготовки вашего проекта к разработке с использованием SDK с поддержкой среды выполнения необходимо сначала определить зависимости от некоторых инструментов и библиотек:

  • Библиотеки обратной совместимости среды выполнения SDK, обеспечивающие поддержку устройств, не имеющих песочницы конфиденциальности (Android 13 и ниже) ( androidx.privacysandbox.sdkruntime: ).
  • Библиотеки пользовательского интерфейса для поддержки показа рекламы ( androidx.privacysandbox.ui: )
  • Инструменты разработчика SDK для поддержки объявления API SDK и генерации заглушек ( androidx.privacysandbox.tools: )
  1. Добавьте этот флаг в файл gradle.properties вашего проекта, чтобы включить возможность создания SDK с поддержкой среды выполнения.

    # This enables the Privacy Sandbox for your project on Android Studio.
    android.experimental.privacysandboxsdk.enable=true
    android.experimental.privacysandboxsdk.requireServices=false
    
  2. Измените файл build.gradle вашего проекта, чтобы включить вспомогательные библиотеки Jetpack и другие зависимости:

    // 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. Обновите файл build.gradle в модуле runtime-enabled ad library (RE SDK), чтобы включить эти зависимости.

    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. Замените файл build.gradle в вашем модуле ASB с поддержкой среды выполнения следующим содержимым:

    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. Обновите файл build.gradle в существующем модуле библиотеки рекламы (RA SDK), добавив следующие зависимости:

    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

Реализуйте бизнес-логику вашего SDK так же, как вы это делали бы в обычном режиме внутри модуля библиотеки рекламы, поддерживающего работу во время выполнения.

Если вы переносите существующий SDK, на данном этапе перенесите столько бизнес-логики, интерфейса и функций, взаимодействующих с системой, сколько необходимо, но учтите возможность полной миграции в будущем.

Если вам необходим доступ к хранилищу, рекламному идентификатору Google Play или идентификатору набора приложений, ознакомьтесь со следующими разделами:

Используйте API хранилища в вашем SDK.

В среде выполнения SDK SDK больше не могут получать доступ, читать или записывать данные во внутреннюю память приложения, и наоборот.

Среда выполнения SDK имеет собственное внутреннее хранилище, отдельное от приложения.

SDK могут получить доступ к этому отдельному внутреннему хранилищу, используя API файлового хранилища объекта Context , возвращаемого методом SandboxedSdkProvider#getContext() .

SDK могут использовать только внутреннюю память, поэтому работают только API для работы с внутренней памятью, такие как Context.getFilesDir() или Context.getCacheDir() . Дополнительные примеры см. в разделе «Доступ из внутренней памяти» .

Доступ к внешнему хранилищу из среды выполнения SDK не поддерживается. Вызов API для доступа к внешнему хранилищу приведет либо к возникновению исключения, либо к возврату значения null. Ниже приведен список некоторых примеров:

  • При попытке доступа к файлам с использованием Storage Access Framework возникает исключение SecurityException.
  • getExternalFilsDir() всегда возвращает значение null.

Для хранения данных необходимо использовать Context возвращаемый методом SandboxedSdkProvider.getContext() . Использование API файлового хранилища для любого другого экземпляра объекта Context , например, контекста приложения, не гарантирует корректной работы во всех ситуациях.

Следующий фрагмент кода демонстрирует, как использовать хранилище в среде выполнения 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"
    }
}

Внутри каждой среды выполнения SDK имеется отдельная внутренняя память, и каждый SDK имеет свой собственный каталог хранения. Хранилище для каждого SDK представляет собой логическое разделение внутренней памяти среды выполнения SDK, что помогает учитывать объем памяти, используемый каждым SDK.

Все внутренние API хранилища объекта Context возвращают путь к хранилищу для каждого SDK.

Воспользуйтесь рекламным идентификатором, предоставленным сервисами Google Play.

Если вашему SDK необходим доступ к рекламному идентификатору, предоставляемому сервисами Google Play, используйте AdIdManager#getAdId() для асинхронного получения этого значения.

Получите доступ к идентификатору набора приложений, предоставленному сервисами Google Play.

Если вашему SDK требуется доступ к идентификатору набора приложений, предоставляемому сервисами Google Play, используйте AppSetIdManager#getAppSetId() для асинхронного получения значения.

Объявление API SDK

Для того чтобы ваш SDK с поддержкой среды выполнения был доступен вне среды выполнения, необходимо определить API, которые могут использовать клиенты (RA SDK или клиентское приложение).

Для объявления этих интерфейсов используйте аннотации.

Аннотации

API SDK необходимо объявлять в Kotlin как интерфейсы и классы данных, используя следующие аннотации:

Аннотации
@PrivacySandboxService
  • Определяет точку входа в ваш SDK для репозитория.
  • Должно быть уникальным
@PrivacySandboxInterface
  • Обеспечивает дальнейшую модульность и доступ к интерфейсам.
  • Может иметь несколько экземпляров
@PrivacySandboxValue
  • Позволяет передавать данные между процессами.
  • Подобно неизменяемым структурам, которые могут возвращать несколько значений разных типов,
@PrivacySandboxCallback
  • Объявляет API с функцией обратного вызова.
  • Предоставляет обратный канал для вызова клиентского кода.

Эти интерфейсы и классы необходимо определить в любом месте внутри модуля библиотеки рекламы, поддерживающего работу во время выполнения.

Использование этих аннотаций описано в следующих разделах.

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

Поддерживаемые типы

API SDK с поддержкой среды выполнения поддерживают следующие типы:

  • Все примитивные типы данных в языке программирования Java (такие как int, long, char, boolean и так далее).
  • Нить
  • Интерфейсы Kotlin, аннотированные с помощью @PrivacySandboxInterface или @PrivacySandboxCallback
  • Классы данных Kotlin, аннотированные с помощью @PrivacySandboxValue
  • java.lang.List — все элементы списка должны иметь один из поддерживаемых типов данных.

Есть еще несколько оговорок:

  • Классы данных, аннотированные @PrivacySandboxValue , не могут содержать поля типа @PrivacySandboxCallback
  • Возвращаемые типы не могут содержать типы, аннотированные @PrivacySandboxCallback
  • Список не может содержать элементы типов, аннотированных @PrivacySandboxInterface или @PrivacySandboxCallback

Асинхронные API

Поскольку API SDK всегда обращаются к отдельному процессу, нам необходимо убедиться, что эти вызовы не блокируют поток, вызывающий клиентскую часть.

Для этого все методы в интерфейсах, аннотированных @PrivacySandboxService , @PrivacySandboxInterface и @PrivacySandboxCallback должны быть явно объявлены как асинхронные API.

Асинхронные API в Kotlin можно реализовать двумя способами:

  1. Используйте функции приостановки .
  2. Принимает обратные вызовы, которые уведомляют о завершении операции или о других событиях в процессе её выполнения. Тип возвращаемого значения функции должен быть Unit.

Исключения

API SDK не поддерживают никакие формы проверяемых исключений.

Сгенерированный вспомогательный код перехватывает любые исключения, возникающие во время выполнения SDK, и отправляет их клиенту в виде исключения PrivacySandboxException , содержащего информацию о причине возникновения.

Библиотека пользовательского интерфейса

Если у вас есть интерфейсы, представляющие рекламу, например, баннер, вам также необходимо реализовать интерфейс SandboxedUiAdapter , чтобы разрешить открытие сессий для загруженной рекламы.

Эти сессии образуют побочный канал связи между клиентом и SDK и выполняют две основные функции:

  • Получайте уведомления о любых изменениях в пользовательском интерфейсе.
  • Сообщите клиенту о любых изменениях в пользовательском интерфейсе.

Поскольку клиент может использовать интерфейс, аннотированный @PrivacySandboxService , для взаимодействия с вашим SDK, любые API для загрузки рекламы могут быть добавлены в этот интерфейс.

Когда клиент запрашивает загрузку рекламы, загрузите рекламу и верните экземпляр интерфейса, реализующего интерфейс SandboxedUiAdapter . Это позволяет клиенту запрашивать открытие сессий для этой рекламы.

Когда клиент запрашивает открытие сессии, ваш SDK с поддержкой среды выполнения может создать рекламное объявление, используя ответ с объявлением и предоставленный контекст.

Для этого создайте класс, реализующий интерфейс SandboxedUiAdapter.Session , и при вызове метода SandboxedUiAdapter.openSession() убедитесь, что вы вызываете метод client.onSessionOpened() , передавая в качестве параметра экземпляр класса Session .

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

Этот класс также получает уведомления о любых изменениях в пользовательском интерфейсе. Вы можете использовать этот класс, например, для изменения размера рекламы или для получения информации об изменении конфигурации.

Узнайте больше об API отображения пользовательского интерфейса в среде выполнения.

Поддержка мероприятий

Для запуска действий, принадлежащих SDK, из песочницы конфиденциальности необходимо изменить API SDK таким образом, чтобы он принимал объект SdkActivityLauncher , также предоставляемый библиотекой пользовательского интерфейса.

Например, следующий API SDK должен запускать активности, поэтому он ожидает параметр SdkActivityLauncher :

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

точка входа SDK

Абстрактный класс SandboxedSdkProvider инкапсулирует API, который среда выполнения SDK использует для взаимодействия с загруженными в нее SDK.

SDK с поддержкой среды выполнения должен реализовать этот абстрактный класс, чтобы создать точку входа для взаимодействия среды выполнения SDK с ним.

Для обеспечения обратной совместимости мы ввели следующие классы:

Узнайте больше об обратной совместимости среды выполнения SDK.

Инструменты генерации заглушек добавляют еще один уровень абстракции: они генерируют абстрактный класс под названием AbstractSandboxedSdkProvider , используя интерфейс, который вы аннотировали с помощью @PrivacySandboxService .

Этот класс наследует SandboxedSdkProviderCompat и находится в том же пакете, что и ваш аннотированный интерфейс.

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

Этот сгенерированный класс предоставляет единственный абстрактный фабричный метод, который принимает объект Context и ожидает возврата аннотированного интерфейса, являющегося точкой входа.

Этот метод назван в честь вашего интерфейса @PrivacySandboxService , и перед именем будет добавлено слово create . Например, если ваш интерфейс называется MySdk , инструменты сгенерируют createMySdk .

Для полноценного подключения вашей точки входа необходимо предоставить реализацию интерфейса, аннотированного @PrivacySandboxService в SDK с поддержкой среды выполнения для сгенерированного AbstractSandboxedSdkProvider .

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

Изменения в модуле ASB

Необходимо указать полное имя класса вашей реализации SandboxedSdkProviderCompat в поле compatSdkProviderClassName файла build.gradle вашего модуля ASB.

Это класс, который вы реализовали на предыдущем шаге, и вам нужно будет изменить файл build.gradle в вашем модуле ASB следующим образом:

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

Шаг 2 : Настройка среды разработки Шаг 4 : Использование SDK с поддержкой среды выполнения