Compatibilidade com versões anteriores do SDK Runtime

Este documento propõe uma nova biblioteca do Jetpack para ajudar os desenvolvedores na migração para o SDK Runtime. Ele explica como o SDK Runtime vai oferecer suporte a versões anteriores da Plataforma Android (do build à execução) e quais diferenças ou limitações no ambiente de execução os desenvolvedores podem esperar. Essa biblioteca permite que os desenvolvedores criem uma única versão do app ou SDK que inclua a capacidade de execução em dispositivos com ou sem suporte ao SDK Runtime.

A compatibilidade com versões anteriores é alcançada por meio dos seguintes componentes:

  • O Plug-in do Android para Gradle (AGP, na sigla em inglês) + Bundletool cria uma variante do app para dispositivos sem suporte ao SDK Runtime agrupando o SDK Runtime ao APK.

  • A biblioteca de cliente do SDK Runtime (androidx.privacysandbox.sdkruntime:sdkruntime-client) carrega o SDK empacotado usando recursos do app e emula o SDK Runtime em dispositivos sem suporte ao SDK Runtime.

  • A biblioteca de provedor do SDK Runtime (androidx.privacysandbox.sdkruntime:sdkruntime-provider) fornece uma API para que os SDKs permitam o carregamento da biblioteca de cliente do SDK Runtime.

Entrega de SDK com o Bundletool

Em dispositivos com suporte ao SDK Runtime, os SDKs serão enviados e instalados como pacotes separados.

Para oferecer suporte a versões de plataforma que não oferecem suporte ao SDK Runtime, o Bundletool vai criar uma ou mais variantes do conjunto de APKs do app que incluem todos os SDKs de que o app depende. Cada SDK é empacotado como uma divisão de APK separada. Além disso, as seguintes transformações são realizadas:

  1. Copie os arquivos de bytecode (DEX) do SDK para a divisão do SDK como recursos.
  2. Copiar os recursos Java do SDK para a divisão do SDK como recursos.
  3. Remapeie os recursos do SDK e mescle com os recursos do app.
  4. Gerar configurações para a biblioteca de cliente do SDK Runtime.

Carregar SDKs com a biblioteca de cliente do SDK Runtime

A biblioteca de cliente do SDK Runtime fornece APIs semelhantes às da plataforma, mas oferece suporte aos SDKs no ambiente do SDK Runtime e aos SDKs que acompanham o app da variante.

Para usar a biblioteca de cliente do SDK Runtime, adicione a dependência androidx.privacysandbox.sdkruntime:sdkruntime-client e use SdkSandboxManagerCompat em vez de SdkSandboxManager.

Quando um app tenta carregar um SDK, a biblioteca verifica primeiro se o SDK estava agrupado com o app durante o build. Se ele tiver sido empacotado, a biblioteca vai extrair o SDK da divisão do SDK e o carregar no processo do app. Se o SDK não estava incluído no app, a biblioteca delegará a API da plataforma para carregar o SDK.

Extrair um SDK dos recursos

Quando um app tenta carregar um SDK empacotado, a biblioteca de cliente do SDK Runtime vai verificar se os arquivos DEX do SDK já foram extraídos para o armazenamento do dispositivo (code_cache) e, se não estiverem, os extrai dos recursos.

Normalmente, a biblioteca extrai arquivos apenas uma vez após a instalação ou atualização de um app.

Se o espaço de armazenamento disponível for menor que o limite permitido (atualmente 100 MB) e nenhum arquivo DEX for extraído, a biblioteca vai tentar carregar o SDK diretamente de recursos em dispositivos com suporte (API 27+). Isso resulta em um consumo maior de memória.

Carregador de classe para classes do SDK

Para evitar conflitos entre SDKs e classes de apps, todas as classes do SDK são carregadas usando um carregador de classes separado, totalmente independente do carregador de classes do app principal.

No design atual do SDK Runtime, todas as comunicações entre um app e os SDKs acontecem usando chamadas IPC de vinculação. Os mesmos objetos Binder do SDK são usados para SDKs empacotados, e a serialização de transações Binder permite que os desenvolvedores de apps transmitam objetos Binder do SDK para interfaces de vinculação do SDK no lado do app.

Para outras interações internas, como inicializar um SDK, fornecer uma API do controlador a um SDK e assim por diante, a biblioteca usa o reflexo e os proxies dinâmicos para trabalhar em diferentes carregadores de classe.

Ambiente do SDK

A biblioteca SDKRuntime Provider fornece APIs para os desenvolvedores de SDK. Essas APIs são parecidas com as de plataforma, mas permitem que os SDKs sejam carregados pelo ambiente do SDK Runtime e pela biblioteca de cliente do SDKRuntime.

Para usar o SDK da biblioteca, é necessário adicionar a dependência androidx.privacysandbox.sdkruntime:sdkruntime-provider e estender SandboxedSdkProviderCompat em vez de SandboxedSdkProvider.

Também é necessário usar o SandboxedSdkProviderAdapter como provedor do SDK para permitir que o provedor de compatibilidade seja carregado no ambiente do SDK Runtime.

O SdkSandboxControllerCompat delega à API da plataforma quando o SDK é carregado no SDK Runtime ou à biblioteca de cliente do SDKRuntime quando o SDK é carregado como um SDK empacotado.

Para SDKs agrupados, a biblioteca modifica o ambiente do SDK de maneiras que emulam um comportamento semelhante ao do SDK Runtime.

As próximas seções descrevem os comportamentos esperados quando o SDK é carregado pela biblioteca de cliente do SDKRuntime.

Recursos do SDK

Os recursos do SDK (res/) têm suporte quando o SDK é carregado no processo do app. O Bundletool mescla os recursos de todos os SDKs com os do app.

Para evitar conflitos, os recursos do SDK são remapeados com a mudança do prefixo packageId em todos os IDs de recursos.

Quando o SDK é carregado pela biblioteca de cliente do SDKRuntime, o packageId é atualizado durante a execução para permitir o remapeamento de recursos remapeados usando a classe R.

Recursos Java

Recursos Java são suportados quando o SDK é carregado no processo do aplicativo. O Bundletool copia todos os recursos Java do SDK para um diretório especial nos recursos de app. A biblioteca de cliente SDKRuntime usa um carregador de classe intermediário para redirecionar todas as chamadas relacionadas a recursos Java para o novo diretório raiz.

Recursos do SDK

Os recursos do SDK são mesclados com os recursos de link para app sem remapeamento.

Armazenamento do SDK

Para oferecer suporte ao SDK Storage, a biblioteca de cliente do SDK Runtime cria um diretório raiz dedicado para cada SDK empacotado no armazenamento do app e fornece um contexto especial que usa esse diretório como a raiz do armazenamento.

Esse contexto pode ser recuperado de SandboxedSdkProviderCompat#getContext.

Métodos compatíveis relacionados ao armazenamento:

  • getDataDir
  • getCacheDir
  • getCodeCacheDir
  • getNoBackupFilesDir
  • getDir
  • getFilesDir
  • openFileInput
  • openFileOutput
  • deleteFile
  • getFileStreamPath
  • fileList
  • getDatabasePath
  • openOrCreateDatabase
  • moveDatabaseFrom: somente entre contextos do SDK
  • deleteDatabase
  • databaseList
  • getSharedPreferences
  • moveSharedPreferencesFrom: somente entre contextos do SDK
  • deleteSharedPreferences

Um contexto de armazenamento protegido por dispositivo pode ser criado chamando createDeviceProtectedStorageContext() nesse contexto.

SdkSandboxControllerCompat

A biblioteca de cliente do SDKRuntime fornece a implementação de SdkSandboxControllerCompat para SDKs agrupados carregados no processo do app.

Se a biblioteca de cliente não oferecer suporte às APIs (por exemplo, com um SDK criado com uma versão da biblioteca mais recente do que a versão do app), o substituto mais adequado será usado (ambiente autônomo ou exceção).

Controle de versões

Quando a biblioteca de cliente do SDKRuntime carrega um SDK empacotado, ela executa um handshake com a biblioteca do provedor do SDKRuntime dentro do SDK. Durante o handshake, as bibliotecas trocam as próprias versões e ajustam o comportamento para substituir as APIs indisponíveis pelo substituto mais adequado (no-op ou exceção).

O uso da versão mais recente da biblioteca é altamente recomendado para desenvolvedores de apps e de SDKs. Caso contrário, as funcionalidades que exigem suporte em ambas as partes podem não estar disponíveis.

Qualquer versão da biblioteca de cliente do SDKRuntime pode carregar um SDK com qualquer versão da biblioteca do SDKRuntime Provider e vice-versa.

No futuro, ela será alterada para a versão mínima da biblioteca de cliente necessária para carregar o SDK com uma versão específica da biblioteca de provedor.

Isso minimizará a fragmentação e ajudará a garantir que a maioria das APIs tenha suporte se o SDK empacotado for carregado.