APIs de apresentação da interface do SDK Runtime

O SDK Runtime permite que os SDKs de anúncios sejam executados em um ambiente em sandbox, impedindo que eles acessem a hierarquia de visualização de um editor. Para mostrar anúncios, a plataforma expõe uma API SandboxedSdkProvider.getView ao SDK de modo a receber uma visualização do anúncio e a empacota como um SurfacePackage para ser enviado por comunicação entre processos (IPC) ao aplicativo cliente. Isso tem várias desvantagens, que serão discutidas abaixo. Este documento vai apresentar uma proposta de biblioteca do Jetpack que está sendo criada para lidar com esses desafios.

Justificativa para aumentar as APIs da plataforma

As APIs de framework foram projetadas para oferecer flexibilidade e deixam a tarefa de criar um canal secundário para a apresentação da interface a cargo do app e do SDK. Esse canal secundário:

  1. Permite que o SDK gerencie várias visualizações de anúncios durante o ciclo de vida delas e entenda o que acontece com a interface do anúncio depois que ela é criada pelo SDK.
  2. Separa a criação de visualizações e a vinculação de conteúdo. O uso do canal secundário permite que o SDK retorne um objeto que corresponde à solicitação de anúncio para o app (o conteúdo), que poderá ser vinculado ao contêiner de anúncios sempre que o app considerar adequado.
  3. Abstrai as construções da plataforma usadas para mostrar a interface nos processos. No momento, a plataforma usa um SurfaceControlViewhost e gera um SurfacePackage baseado nele.
  4. Permite que os SDKs de anúncios no SDK Runtime recebam notificações automaticamente quando a interface do contêiner do anúncio mudar. Se um editor mudar o layout do contêiner de anúncios, o SDK não vai saber dessas mudanças, a menos que o editor chame explicitamente uma API para avisá-lo.
  5. Sincroniza redimensionamentos da interface do anúncio e do contêiner de anúncios sem qualquer instabilidade visível para o usuário.
  6. Gerencia automaticamente a compatibilidade com versões anteriores. O SurfacePackage não está disponível antes do nível 30 da API. Além disso, em dispositivos em que não há um ambiente de execução do SDK e o SDK tem processamento local para o editor, não é útil criar um SurfacePackage para um anúncio quando uma visualização pode ser recebida diretamente do SDK. O canal secundário abstrai essa complexidade do SDK e do código do desenvolvedor do app.
  7. Permite que a interface do anúncio se integre perfeitamente a elementos combináveis. Os desenvolvedores do Jetpack Compose que não trabalham com visualizações também podem continuar hospedando a interface gerada pelo desenvolvedor do SDK, que ainda funciona com visualizações.

Bibliotecas de interface

As bibliotecas de interface abstraem as complexidades detalhadas acima. Além disso, elas fornecem o canal secundário que o editor e o SDK podem usar para mostrar a interface em todos os processos e mantê-lo atualizado à medida que o usuário interage com ela e com o dispositivo.

Há três bibliotecas de interface: principal, de cliente e de provedor. A biblioteca principal fornece as interfaces usadas pelas bibliotecas de cliente e de provedor. O provedor da interface (normalmente o SDK) depende da biblioteca de provedor, e o consumidor da interface (geralmente o editor) depende da biblioteca de cliente. Juntas, as bibliotecas de cliente e do provedor formam o canal secundário necessário para criar e manter uma sessão de interface.

As APIs

As APIs para apresentação da interface do SDK Runtime são as seguintes:

SandboxedUiAdapter: criada pelo SDK, oferecendo uma maneira de acessar o conteúdo a ser mostrado na interface do editor.

SandboxedSdkView: criada pelo editor, é um contêiner que armazena o conteúdo extraído pelo SandboxedUiAdapter.

Session: criada pelo SDK em resposta ao SandboxedUiAdapter.openSession(). Representa uma chamada da sessão de interface. Isso forma o final do túnel de comunicação do SDK entre o SDK e o editor e recebe notificações sobre mudanças no SandboxedSdkView, como remoções de janelas, redimensionamentos ou mudanças de configuração.

SessionClient: criada pela biblioteca de cliente, forma a parte do editor do túnel de comunicação entre o SDK e o editor.

SandboxedSdkUiSessionStateChangedListener: criada pelo editor. Um listener para mudanças no estado da sessão de interface associada a SandboxedSdkView.

Ilustração que mostra as relações da API de apresentação da interface do SDK Runtime.
Figura 1. Relações entre as APIs de apresentação da interface do SDK Runtime.

Leia a documentação de referência de privacysandbox-ui para saber mais detalhes sobre essas APIs.

Fluxo de controle

Os diagramas a seguir mostram a interação entre as bibliotecas de interface do cliente e do provedor em vários cenários:

A Figura 1 mostra como o editor pode criar uma SandboxedSdkView de maneira programática ou pelo XML e anexá-la a um SdkSandboxUiAdapter recebido do SDK usando uma API definida pelo SDK. Para observar todas as mudanças de estado da interface, o editor precisa adicionar um SandboxedSdkUiSessionStateChangedListener à SandboxedSdkView antes de anexar SdkSandboxUiAdapter.

Ilustração mostrando o processo de sessão aberta.
Figura 2. Recebimento da interface do SDK.

A Figura 2 mostra como, se a atividade do editor processar as mudanças de configuração, a biblioteca de cliente vai encaminhar a mudança de configuração ao SDK, permitindo que ele atualize a interface de maneira adequada. Por exemplo, esse fluxo pode ser acionado quando o usuário gira o dispositivo e o editor declara que processa mudanças de configuração na atividade, definindo android:configChanges=["orientation"].

Figura 3. Mudança na interface iniciada pelo editor.

A Figura 3 ilustra como o SDK pode solicitar uma mudança no contêiner de anúncios usando métodos na SessionClient. Essa API é acionada quando o SDK quer redimensionar o anúncio e precisa que o editor redimensione o contêiner de anúncios para acomodar as novas dimensões. Isso pode acontecer em resposta à interação do usuário, como mraid.resize().

Figura 4. Mudança na interface iniciada pelo SDK.

A Figura 4 mostra como a sessão é encerrada quando a SandboxedSdkView é removida da janela. A sessão também pode ser encerrada a qualquer momento pelo SDK invocando SessionClient.onSessionError(). Isso pode acontecer, por exemplo, quando o usuário perde a conectividade de rede.

Figura 5. Fechamento da sessão de interface.

Ordem Z

A biblioteca de interface do cliente usa uma SurfaceView internamente para hospedar a interface do SDK. A SurfaceView pode usar a ordem Z para mostrar a interface acima ou abaixo da janela do editor. Isso é controlado pelo método SandboxedSdkView.orderProviderUiAboveClientUi(), que aceita um booleano setOnTop.

Quando setOnTop for true, cada android.view.MotionEvent no SandboxedSdkView será enviado ao SDK. Quando for false, o envio será feito ao editor. Por padrão, os eventos de movimento são enviados ao SDK.

Os editores normalmente não precisam mudar a ordem Z padrão das visualizações de anúncios. No entanto, ao mostrar a interface que cobre um anúncio, como um menu suspenso, a ordem Z precisa ser temporariamente invertida do padrão e restaurada quando o elemento da interface da cobertura é dispensado. Estamos avaliando maneiras de automatizar esse processo na biblioteca de interface do cliente.

Rolagem

Quando a interface do anúncio é ordenada usando o modo "Z acima" da janela do editor, MotionEvents da interface do anúncio são enviados ao SDK. Gestos de rolagem e de deslize rápido iniciados na interface do anúncio recebem tratamento especial:

  1. Os gestos de rolagem vertical e deslize rápido são enviados e processados pelo contêiner do editor. Isso proporciona uma boa UX quando o contêiner do editor em que a interface do anúncio é posicionada tem rolagem vertical. Nenhum trabalho extra é exigido do SDK ou do editor.
  2. Os gestos de rolagem e deslize rápido horizontal são enviados e processados pelo SDK. Isso proporciona uma boa UX quando a própria interface do anúncio pode ser rolada horizontalmente (como um carrossel de anúncios).

Guia de implementação

O SDK precisa implementar o seguinte:

1. SandboxedUiAdapter**: é retornado ao editor em resposta a uma API definida pelo SDK, como loadAd. Use o método openSession() dessa implementação para fazer uma solicitação de anúncio aos servidores do SDK e preparar uma visualização de anúncio para essa solicitação. 1. Session**: retornado em resposta à chamada de SandboxedUiAdapter.openSession. Fornece uma maneira de a biblioteca de cliente receber a interface do anúncio e notificar o SDK sobre mudanças na API. Todos os métodos Session precisam ser implementados aqui.

O editor precisa fazer o seguinte:

  1. Criar um SandboxedSdkView usando XML ou de forma programática.
  2. Anexar um SandboxedSdkUiSessionStateChangedListener à SandboxedSdkView para observar as mudanças na interface.
  3. Anexar um SandboxedUiAdapter fornecido pelo SDK à SandboxedSdkView.
  4. Adicionar a SandboxedSdkView à janela como de costume e deixar a biblioteca de cliente criar e manter a sessão de interface com o SDK.
  5. Em momentos adequados, reagir às mudanças no estado relatadas por SandboxedSdkUiSessionChangedListener. Por exemplo, se o SDK fechar a sessão inesperadamente, o editor poderá substituir a SandboxedSdkView por uma imagem estática ou removê-la da hierarquia de visualização.
  6. Ao fazer transições que podem cobrir a interface do anúncio, como um menu suspenso, usar orderProviderUiAboveClientUi temporariamente para "false" e posicionar a interface abaixo da janela do editor. Depois que o menu suspenso for dispensado, chamar orderProviderUiAboveClientUi para true.

O futuro das APIs da plataforma

Quando as bibliotecas de interface entrarem na versão Beta, planejamos suspender o uso das APIs da plataforma SDK Runtime relacionadas à apresentação da interface, ou seja, SdkSandboxManager.requestSurfacePackage() e SandbxedSdkProvider.getView().

Perguntas

  1. Existem casos de uso mais comuns da interface de anúncios que as bibliotecas de interface precisam processar automaticamente?
  2. Quais frameworks de interface você usa para mostrar a interface do anúncio? Você prevê problemas na integração das bibliotecas de interface com esses frameworks?
  3. A interface de anúncios rolável colocada em um contêiner de editor rolável é um caso de uso comum para você? Qual é a direção da rolagem da interface do anúncio e do contêiner nesse caso? Qual comportamento você espera quando o usuário inicia uma rolagem na interface do anúncio?