Criar e consumir um SDK ativado pelo ambiente de execução

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

Consumir o SDK ativado no momento da execução

Esta seção descreve como os clientes podem interagir com as APIs do SDK ativadas no tempo de execução (RE, na sigla em inglês) declaradas.

Neste guia, vamos nos referir ao módulo de SDK atual (ou SDK compatível com o tempo de execução) como o cliente.

Se você quiser o SDK ativado pelo ambiente de execução diretamente no seu app, o módulo do app será o cliente.

Carregar o SDK ativado pelo ambiente de execução

A primeira coisa que você precisa fazer no SDK ou app cliente compatível com o ambiente de execução é carregar o SDK ativado pelo ambiente de execução.

A classe SdkSandboxManager ajuda a carregar SDKs ativados no momento da execução, retornando uma classe IBinder que o SDK compatível com o tempo de execução pode vincular à interface declarada no SDK ativado no momento da execução.

Carregue cada SDK RE apenas uma vez. Caso contrário, o gerenciador de SDKs vai retornar uma exceção.

As ferramentas de geração de shim criam classes auxiliares para converter a interface IBinder retornada pelo SdkSandboxManager de volta à interface da API do SDK declarada.

As ferramentas usam a interface anotada com @PrivacySandboxService para gerar uma classe *Factory.

Essa classe contém uma função estática wrapTo* que converte um objeto IBinder em uma instância da interface do SDK ativado pelo ambiente de execução.

Seu SDK compatível com o ambiente de execução pode se comunicar com o SDK ativado para o ambiente de execução usando essa interface e invocar as APIs do SDK declaradas na etapa anterior.

// Name of the SDK to be loaded, defined in your ASB module
private const val SDK_NAME = "com.example.sdk"

try {
    // SdkSandboxManagerCompat is used to communicate with the sandbox and load SDKs with backward compatibility.
    val sandboxManagerCompat = SdkSandboxManagerCompat.from(context)
    val sandboxedSdk = sandboxManagerCompat.loadSdk(SDK_NAME, Bundle.EMPTY)
    val mySdk = MySdkFactory.wrapToMySdk(sandboxedSdk.getInterface()!!)
} catch (e: LoadSdkCompatException) {
    Log.e(TAG, "Failed to load SDK, error code: ${e.loadSdkErrorCode}", e)
    return null
}

Uso da biblioteca de UI

Se você quiser usar a biblioteca de UI para mostrar anúncios, verifique se adicionou androidx.privacysandbox.ui:ui-core e androidx.privacysandbox.ui:ui-client às dependências no build.gradle do SDK compatível com o tempo de execução.

Carregar um anúncio de banner usando SandboxedSdkView

O androidx.privacysandbox.ui:ui-client apresenta um novo ViewGroup chamado SandboxedSdkView para hospedar a interface criada por um SDK ativado pelo ambiente de execução.

setAdapter() abre uma sessão com o SDK ativado pelo tempo de execução para receber a visualização do anúncio e notificações de mudanças na interface. Quando o SDK abre a sessão, o anúncio é mostrado.

Isso pode ser integrado da seguinte forma:

class BannerAd(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
    suspend fun loadAd() {
        // mySdk is the previously loaded SDK in the SDK Runtime.
        val bannerAd = mySdk.loadAd()
        val sandboxedSdkView = SandboxedSdkView(context)
        addViewToLayout(sandboxedSdkView)

        // This renders the ad.
        sandboxedSdkView.setAdapter(bannerAd)
        return
    }
    private fun addViewToLayout(view: View) {
        view.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
        super.addView(view)
    }
}

Seu SDK compatível com o tempo de execução também pode receber notificações quando o estado da sessão muda para a apresentação da interface. Para fazer isto:

  1. Crie uma classe SessionStateChangeListener() para processar os diferentes cenários:

    private class SessionStateChangeListener() : SandboxedSdkUiSessionStateChangedListener {
        override fun onStateChanged(state: SandboxedSdkUiSessionState) {
            if (state is SandboxedSdkUiSessionState.Error) {
            // Some error has occurred while opening the session. Handle
            // accordingly.
            Log.e(TAG, state.throwable.message!!);
            } else if (state is SandboxedSdkUiSessionState.Loading) {
                // The session is attempting to be opened.
            } else if (state is SandboxedSdkUiSessionState.Active) {
                // The session is open and the UI presentation was successful.
            } else if (state is SandboxedSdkUiSessionState.Idle) {
                // There is no open session.
            }
        }
    }
    
  2. Adicione um listener de mudança de estado à SandboxedSdkView que você instanciou anteriormente. O listener é chamado imediatamente com o estado atual assim que é anexado à visualização.

Observe o seguinte:

  • Se o SDK compatível com o tempo de execução chamar métodos SandboxedSdkView quando a sessão ainda não tiver terminado de abrir, todos os efeitos serão aplicados depois que ela terminar de abrir.
    • Métodos como SandboxedSdkView.orderProviderUiAboveClientUi(providerUiOnTop)
  • Chamar métodos que adicionam ou removem uma visualização de SandboxedSdkView (como addView(), removeView(), removeViewAt() etc.) não é compatível, gerando um UnsupportedOperationException.
    • Use apenas setAdapter() para mostrar o anúncio.
  • O SandboxedSdkView.orderProviderUiAboveClientUi(providerUiOnTop) alterna a ordenação Z, o que afeta se os MotionEvents da interação do usuário são enviados ao SDK ativado pelo ambiente de execução ou ao SDK compatível com o ambiente de execução.

Iniciar atividades

Para iniciar atividades pertencentes ao SDK ativado pelo ambiente de execução, use a extensão createSdkActivityLauncher para criar um iniciador no SDK compatível com o ambiente de execução.

Esse iniciador pode ser transmitido ao SDK ativado pelo ambiente de execução, permitindo que ele inicie atividades conforme necessário.

Você pode usar um predicado para controlar se a atividade será iniciada ou não. O predicado precisa retornar um valor true para que as atividades sejam permitidas.

val launchSdkActivityPredicate = {
    // Boolean which has to be true to launch the activities
    }
val launcher = baseActivity.createSdkActivityLauncher(launchSdkActivityPredicate)
fullscreenService.showActivity(launcher)

No SDK ativado pelo ambiente de execução, registre SdkSandboxActivityHandlerCompat e forneça-o para SdkActivityLauncher.LaunchSdkActivity(IBinder).

fun showActivity(activityLauncher: SdkActivityLauncher) {
    val handler = object : SdkSandboxActivityHandlerCompat {
        override fun onActivityCreated(activityHolder: ActivityHolder) {
            activityHolder.getActivity().setContentView(contentView)
        }
    }

    val token = controller.registerSdkSandboxActivityHandler(handler)
    activityLauncher.launchSdkActivity(token)
}

O ActivityHolder transmitido para SdkSandboxActivityHandlerCompat.onActivityCreated(ActivityHolder) implementa LifecycleOwner, ao SDK ativado pelo ambiente de execução acesso ao ciclo de vida da atividade.

Ela também fornece a API getOnBackPressedDispatcher, que pode ser usada para registrar instâncias getOnBackPressedCallback e processar o comportamento do botão "Voltar" na atividade.


Etapa 3: criar um SDK compatível com o ambiente de execução Etapa 5: teste e criação para distribuição