Ключевые понятия | Настройте среду разработки | Создайте RE SDK | Используйте RE SDK | Тестирование и сборка для распространения |
Ключевые понятия | Настройте среду разработки | Создайте RE SDK | Используйте RE SDK | Тестирование и сборка для распространения |
Создайте SDK с поддержкой среды выполнения
Для создания SDK с поддержкой среды выполнения необходимо выполнить следующие шаги:
- Настройте структуру вашего проекта
- Подготовьте свой проект и зависимости модуля.
- Добавьте бизнес-логику SDK
- Определите API SDK
- Укажите точку входа для вашего SDK
Настройте структуру вашего проекта
Мы рекомендуем разделить ваш проект на следующие модули:
- Модуль приложения — тестовое приложение, которое вы используете для тестирования и разработки своего SDK, представляющее то, что будут иметь ваши реальные клиенты приложения. Ваше приложение должно зависеть от существующего модуля библиотеки объявлений ( SDK с поддержкой среды выполнения ).
- Существующий модуль библиотеки рекламы (SDK с поддержкой среды выполнения) . Модуль библиотеки Android, содержащий существующую логику SDK, не поддерживающую среду выполнения, статически связанный SDK.
- Для начала возможности можно разделить. Например, некоторый код может обрабатываться существующим SDK, а другой — перенаправляться в SDK с поддержкой среды выполнения.
- Модуль библиотеки объявлений с поддержкой среды выполнения . Содержит бизнес-логику SDK с поддержкой среды выполнения. Его можно создать в Android Studio как модуль библиотеки Android.
- Модуль ASB с поддержкой среды выполнения — определяет данные пакета для объединения кода SDK с поддержкой среды выполнения в ASB.
- Его необходимо создать вручную, используя тип com.android.privacy-sandbox-sdk . Вы можете сделать это, создав новый каталог.
- Этот модуль не должен содержать никакого кода, а должен содержать только пустой файл build.gradle с зависимостями от вашего модуля библиотеки объявлений с поддержкой среды выполнения . Содержимое этого файла определено в разделе «Подготовка SDK» .
- Не забудьте включить этот модуль в файл settings.gradle и в существующий модуль библиотеки объявлений.
Структура проекта в этом руководстве является рекомендуемой. Вы можете выбрать другую структуру для своего SDK и применить те же технические принципы. Вы всегда можете создать другие дополнительные модули для модульности кода приложения и модулей библиотеки.
Подготовьте свой SDK
Чтобы подготовить проект к разработке SDK с поддержкой среды выполнения, вам необходимо сначала определить некоторые зависимости инструментов и библиотек:
- Библиотеки обратной совместимости SDK Runtime, которые обеспечивают поддержку устройств, не имеющих Privacy Sandbox (Android 13 и ниже) (
androidx.privacysandbox.sdkruntime:
). - Библиотеки пользовательского интерфейса для поддержки представления рекламы (
androidx.privacysandbox.ui:
) - Инструменты разработчика SDK для поддержки объявления SDK API и создания прокладок (
androidx.privacysandbox.tools:
)
Добавьте этот флаг в файл gradle.properties вашего проекта, чтобы включить возможность создания SDK с поддержкой среды выполнения.
# This enables the Privacy Sandbox for your project on Android Studio. android.experimental.privacysandboxsdk.enable=true android.experimental.privacysandboxsdk.requireServices=false
Измените 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 }
Обновите файл build.gradle в модуле библиотеки объявлений с поддержкой среды выполнения (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" }
Замените файл 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>') }
Обновите файл 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 Runtime не поддерживается. Вызов API для доступа к внешнему хранилищу либо выдаст исключение, либо вернет ноль. Следующий список включает несколько примеров:
- Доступ к файлам с помощью 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 |
|
@PrivacySandboxInterface |
|
@PrivacySandboxValue |
|
@PrivacySandboxCallback |
|
Вам необходимо определить эти интерфейсы и классы в любом месте внутри модуля библиотеки объявлений с поддержкой среды выполнения.
См. использование этих аннотаций в следующих разделах.
@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 двумя способами:
- Используйте функции приостановки .
- Принимайте обратные вызовы, которые получают уведомление о завершении операции или о других событиях во время ее выполнения. Тип возвращаемого значения функции должен быть 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, из Privacy Sandbox, вам необходимо изменить API SDK, чтобы получить объект SdkActivityLauncher
, также предоставляемый библиотекой пользовательского интерфейса.
Например, следующий API SDK должен запускать действия, поэтому он ожидает параметр SdkActivityLauncher
:
@PrivacySandboxInterface
interface FullscreenAd {
suspend fun show(activityLauncher: SdkActivityLauncher)
}
точка входа в SDK
Абстрактный класс SandboxedSdkProvider
инкапсулирует API, который среда выполнения SDK использует для взаимодействия с загруженными в нее SDK.
SDK с поддержкой среды выполнения должен реализовать этот абстрактный класс, чтобы создать точку входа для среды выполнения SDK, чтобы иметь возможность взаимодействовать с ней.
Для поддержки обратной совместимости мы ввели следующие классы:
-
SandboxedSdkProviderAdapter
, который расширяетSandboxedSdkProvider
и обрабатывает запросы на загрузку SDK независимо от доступности среды выполнения SDK. Это используется внутри, объявлено в модуле ASB. -
SandboxedSdkProviderCompat
— абстрактный класс, имитирующий интерфейсSandboxedSdkProvider
.
Узнайте больше об обратной совместимости среды выполнения 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 с поддержкой среды