Key concepts | Set up your development environment | Build an RE SDK | Consume the RE SDK | Testing, and building for distribution |
Criar um SDK ativado pelo ambiente de execução
Conclua as etapas a seguir para criar um SDK ativado pelo ambiente de execução:
- Configurar a estrutura do projeto
- Preparar o projeto e as dependências do módulo
- Adicionar a lógica de negócios do SDK
- Definir as APIs do SDK
- Especificar um ponto de entrada para o SDK
Configurar a estrutura do projeto
Recomendamos que seu projeto seja organizado nos seguintes módulos:
- Módulo do app: o app de teste que você está usando para testar e desenvolver seu , representando o que os clientes reais do seu app teriam. Seu app precisa dependem do módulo da biblioteca de anúncios (SDK baseado no ambiente de execução).
- Módulo de biblioteca de anúncios existente (SDK com reconhecimento de ambiente de execução): um módulo de biblioteca do Android.
que contêm o arquivo "não ativado pelo ambiente de execução" A lógica do SDK, uma maneira estática
SDK vinculado.
- Para começar, os recursos podem ser divididos. Por exemplo, alguns códigos podem ser processados pelo SDK existente, e alguns podem ser roteados para o SDK do Vertex AI Pipelines.
- Módulo da biblioteca de anúncios ativado pelo ambiente de execução: contém seu SDK ativado pelo ambiente de execução. lógica de negócios. Isso pode ser criado no Android Studio como uma biblioteca Android. mais tarde neste módulo.
- Módulo ASB ativado pelo ambiente de execução: define os dados do pacote para agrupar os
código do SDK ativado pelo ambiente de execução em um ASB.
- Ela precisa ser criada manualmente usando o com.android.privacy-sandbox-sdk. Você pode fazer isso criando um novo diretório.
- Esse módulo não pode conter nenhum código e apenas um build.gradle vazio com dependências do módulo da biblioteca de anúncios ativada pelo ambiente de execução. O conteúdo desse arquivo é definido em Prepare o SDK.
- Lembre-se de incluir esse módulo no arquivo settings.gradle e no módulo biblioteca de anúncios existente.
A estrutura do projeto neste guia é uma sugestão. Você pode escolher uma do SDK e aplicam os mesmos princípios técnicos. Você sempre pode criar outros módulos adicionais para modularizar o código no app e nos módulos da biblioteca.
Preparar o SDK
Para preparar seu projeto para o desenvolvimento de SDKs ativados pelo ambiente de execução, você precisa: primeiro defina algumas dependências de ferramentas e bibliotecas:
- Bibliotecas de compatibilidade com versões anteriores do SDK Runtime, que oferecem suporte a
Dispositivos que não têm o Sandbox de privacidade (Android 13 e versões anteriores)
(
androidx.privacysandbox.sdkruntime:
) - Bibliotecas de interface para oferecer suporte à apresentação de anúncios (
androidx.privacysandbox.ui:
) - Ferramentas para desenvolvedores do SDK compatíveis com a declaração da API do SDK e a geração de shim (
androidx.privacysandbox.tools:
)
Adicione essa flag ao arquivo gradle.properties do projeto para ativar o recurso de criação de SDKs ativados pelo ambiente de execução.
# This enables the Privacy Sandbox for your project on Android Studio. android.experimental.privacysandboxsdk.enable=true android.experimental.privacysandboxsdk.requireServices=false
Modifique o build.gradle do projeto para incluir as bibliotecas auxiliares do Jetpack e outras dependências:
// 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 }
Atualize o arquivo build.gradle no módulo da biblioteca de anúncios ativada pelo ambiente de execução (SDK RE) para incluir essas dependências.
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" }
Substitua o arquivo build.gradle no módulo ASB ativado pelo ambiente de execução pelo seguinte:
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>') }
Atualize o arquivo build.gradle no módulo da biblioteca de anúncios existente (SDK da RA) para incluir estas dependências:
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" }
Adicionar lógica de negócios do SDK
Implemente a lógica de negócios do SDK como faria regularmente no módulo da biblioteca de anúncios ativada pelo tempo de execução.
Se você estiver migrando um SDK, migre o máximo possível da lógica de negócios, da interface e das funções voltadas ao sistema que quiser nessa etapa, mas considere uma migração completa no futuro.
Se você precisar de acesso ao armazenamento, ao ID de publicidade do Google Play ou ao ID do conjunto de apps, leia as seguintes seções:
Usar APIs de armazenamento no SDK
Os SDKs no SDK Runtime não podem mais acessar, ler nem gravar no armazenamento interno de um app. e vice-versa.
O SDK Runtime recebe uma área de armazenamento interno separada do app.
Os SDKs podem acessar esse armazenamento interno separado usando as APIs de armazenamento de arquivos no objeto Context
retornado pelo SandboxedSdkProvider#getContext()
.
Os SDKs só podem usar armazenamento interno, portanto, apenas APIs de armazenamento interno, como Context.getFilesDir()
ou
Context.getCacheDir()
trabalho. Confira mais exemplos em
Acessar do armazenamento interno.
Não há suporte para acesso ao armazenamento externo pelo SDK Runtime. Chamar APIs para acessar o armazenamento externo vai gerar uma exceção ou retornar um valor nulo. A lista a seguir inclui alguns exemplos:
- O acesso a arquivos usando o framework de acesso ao armazenamento gera uma SecurityException.
getExternalFilsDir()
sempre retorna um valor nulo.
Use o Context
retornado por SandboxedSdkProvider.getContext()
para armazenamento. Não há garantia de que o uso da API de armazenamento de arquivos em qualquer outra instância de objeto Context
, como o contexto do aplicativo, vai funcionar como esperado em todas as situações.
O snippet de código a seguir demonstra como usar o armazenamento no SDK Runtime:
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" } }
No armazenamento interno separado de cada SDK Runtime, cada SDK tem o próprio diretório de armazenamento. Essa é uma separação lógica do armazenamento interno do SDK Runtime, que ajuda a contabilizar a quantidade de armazenamento usada por um SDK.
Todas as APIs de armazenamento interno no objeto Context
retornam um caminho de armazenamento para cada SDK.
Acessar o ID de publicidade fornecido pelo Google Play Services
Se o SDK precisar acessar o ID de publicidade fornecido pelo Google Play Services, use AdIdManager#getAdId()
para recuperar o valor de forma assíncrona.
Acessar o ID do conjunto de apps fornecido pelo Google Play Services
Se o SDK precisar de acesso ao ID do conjunto de apps fornecido pelo Google Play Services, use
AppSetIdManager#getAppSetId()
para recuperar o valor de forma assíncrona.
Declarar APIs do SDK
Para que o SDK ativado pelo ambiente de execução possa ser acessado fora dele, você precisa para definir APIs que os clientes (SDK RA ou aplicativo cliente) podem consumir.
Use anotações para declarar essas interfaces.
Anotações
As APIs do SDK precisam ser declaradas em Kotlin como interfaces e classes de dados usando a seguintes anotações:
Anotações | |
---|---|
@PrivacySandboxService |
|
@PrivacySandboxInterface |
|
@PrivacySandboxValue |
|
@PrivacySandboxCallback |
|
Você precisa definir essas interfaces e classes em qualquer lugar da módulo da biblioteca de anúncios ativada pelo tempo de execução.
Consulte o uso dessas anotações nas seções a seguir.
@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() }
Tipos compatíveis
As APIs do SDK ativadas pelo ambiente de execução oferecem suporte aos seguintes tipos:
- Todos os tipos primitivos da linguagem de programação Java (como int, long, char, booleano e assim por diante)
- String
- Interfaces Kotlin anotadas com
@PrivacySandboxInterface
ou@PrivacySandboxCallback
- Classes de dados Kotlin com a anotação
@PrivacySandboxValue
- java.lang.List - todos os elementos da Lista devem ser um dos dados suportados tipos
Há algumas ressalvas adicionais:
- As classes de dados anotadas com
@PrivacySandboxValue
não podem conter campos de tipo@PrivacySandboxCallback
- Os tipos de retorno não podem conter tipos anotados com
@PrivacySandboxCallback
- A lista não pode conter elementos de tipos anotados com
@PrivacySandboxInterface
ou@PrivacySandboxCallback
APIs assíncronas
Como as APIs do SDK sempre fazem uma chamada para um processo separado, precisamos verifique se essas chamadas não bloqueiam o thread de chamada do cliente.
Para isso, todos os métodos nas interfaces anotadas com
@PrivacySandboxService
, @PrivacySandboxInterface
e @PrivacySandboxCallback
precisam ser declaradas explicitamente como APIs assíncronas.
APIs assíncronas podem ser implementadas no Kotlin de duas maneiras:
- Use funções de suspensão.
- Aceita retornos de chamada que são notificados quando a operação é concluída ou de outros eventos durante o andamento da operação. O tipo de retorno do precisa ser uma unidade.
Exceções
As APIs do SDK não oferecem suporte a nenhuma forma de exceção verificada.
O código paliativo gerado captura todas as exceções de tempo de execução geradas pelo SDK e
e as envia como PrivacySandboxException
para o cliente com informações sobre
a causa envolvida nele.
Biblioteca de interface
Se você tiver interfaces que representam anúncios, como um banner, também será necessário implementar a interface SandboxedUiAdapter
para ativar as sessões de abertura do anúncio carregado.
Essas sessões formam um canal secundário entre o cliente e o SDK e atendem a dois propósitos principais:
- Receba notificações sempre que ocorrer uma mudança na interface.
- Notificar o cliente sobre qualquer mudança na apresentação da interface.
Como o cliente pode usar a interface com a anotação @PrivacySandboxService
para
se comunicar com o SDK, todas as APIs para carregamento de anúncios podem ser adicionadas ao
interface gráfica do usuário.
Quando o cliente solicitar o carregamento de um anúncio, carregue o anúncio e retorne uma instância do
a interface que implementa SandboxedUiAdapter
. Isso permite que o cliente solicite sessões de abertura para esse anúncio.
Quando o cliente solicita a abertura de uma sessão, o SDK ativado pelo ambiente de execução pode criar uma visualização de anúncio usando a resposta do anúncio e o contexto fornecido.
Para isso, crie uma classe que implemente a interface SandboxedUiAdapter.Session
e, quando SandboxedUiAdapter.openSession()
for chamado, chame client.onSessionOpened()
, transmitindo uma instância da classe Session
como um parâmetro.
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)
}
}
}
Essa classe também recebe notificações sempre que ocorre uma mudança na interface. Você pode use essa classe para redimensionar o anúncio ou saber quando a configuração mudou, por exemplo.
Saiba mais sobre as APIs de apresentação da interface no ambiente de execução.
Suporte de atividade
Para iniciar as atividades do SDK no Sandbox de privacidade, modifique a API do SDK para receber um objeto SdkActivityLauncher
, também fornecido pela biblioteca da interface.
Por exemplo, a API do SDK a seguir precisa iniciar atividades, então ela espera o parâmetro SdkActivityLauncher
:
@PrivacySandboxInterface
interface FullscreenAd {
suspend fun show(activityLauncher: SdkActivityLauncher)
}
Ponto de entrada do SDK
A classe abstrata SandboxedSdkProvider
encapsula a API que o SDK Runtime usa para interagir com os SDKs carregados nele.
Um SDK ativado pelo ambiente de execução precisa implementar essa classe abstrata para gerar um ponto de entrada ao SDK Runtime e se comunicar com ele.
Para oferecer suporte à compatibilidade com versões anteriores, introduzimos as seguintes classes:
SandboxedSdkProviderAdapter
, que estende oSandboxedSdkProvider
e processa solicitações de carregamento do SDK, seja qual for a disponibilidade do SDK Runtime. É usado internamente, declarado no módulo ASB.SandboxedSdkProviderCompat
, uma classe abstrata que imita a interface doSandboxedSdkProvider
.
Saiba mais sobre a compatibilidade com versões anteriores do SDK Runtime.
As ferramentas de geração de paliativos adicionam outra camada de abstração: elas geram uma classe abstrata chamada AbstractSandboxedSdkProvider
usando a interface que você anotou com @PrivacySandboxService
.
Essa classe estende SandboxedSdkProviderCompat
e está no mesmo pacote que a interface com anotação.
// Auto-generated code.
abstract class AbstractSandboxedSdkProvider : SandboxedSdkProviderCompat {
abstract fun createMySdk(context: Context): MySdk
}
Essa classe gerada expõe um único método de fábrica abstrato que usa uma
Context
e espera que sua interface com anotação do ponto de entrada seja retornada.
Esse método é nomeado de acordo com a interface @PrivacySandboxService
, incluindo o prefixo
create
ao nome. Por exemplo, se o nome da interface for MySdk
, as ferramentas
gerar createMySdk
.
Para conectar totalmente seu ponto de entrada, forneça uma implementação da interface com a anotação @PrivacySandboxService
no SDK ativado pelo ambiente de execução para o AbstractSandboxedSdkProvider
gerado.
class MySdkSandboxedSdkProvider : AbstractSandboxedSdkProvider() {
override fun createMySdk(context: Context): MySdk = MySdkImpl(context)
}
Mudanças no módulo ASB
É necessário declarar o nome de classe totalmente qualificado da implementação do SandboxedSdkProviderCompat
no campo compatSdkProviderClassName
do build.gradle do módulo ASB.
Essa é a classe que você implementou na etapa anterior, e você modificaria o build.gradle no módulo ASB da seguinte maneira:
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"
}
Etapa 2: configurar o ambiente de desenvolvimentoEtapa 4: consumir o SDK ativado pelo ambiente de execução