Se você estiver desenvolvendo apps para o mercado corporativo, talvez seja necessário atender a requisitos específicos definidos pelas políticas de uma organização. As configurações gerenciadas, anteriormente conhecidas como restrições de aplicativos, permitem que o administrador de TI da organização especifique remotamente as configurações dos apps. Esse recurso é útil principalmente para apps aprovados pela organização implantados em um perfil de trabalho.
Por exemplo, uma organização pode exigir que os apps aprovados permitam que o administrador de TI:
- Permitir ou bloquear URLs de um navegador da Web
- Configurar se um app pode sincronizar conteúdo por dados móveis ou apenas por Wi-Fi
- Configurar as configurações de e-mail do app
Este guia mostra como implementar configurações de configuração gerenciada no app. Para conferir apps de exemplo com uma configuração gerenciada, consulte Configurações gerenciadas. Se você é um desenvolvedor de gerenciamento de mobilidade empresarial (EMM), consulte o guia da API Android Management.
Observação:por motivos históricos, essas configurações são conhecidas como
restrições e são implementadas com arquivos e classes que usam esse
termo (como RestrictionsManager
). No entanto, essas
restrições podem implementar uma ampla gama de opções de configuração,
não apenas restrições à funcionalidade do app.
Visão geral da configuração remota
Os apps definem as opções de configuração gerenciada que podem ser definidas remotamente por um administrador de TI. Essas são configurações arbitrárias que podem ser alteradas por um provedor de configuração gerenciada. Se o app estiver sendo executado em um perfil de trabalho, o administrador de TI poderá mudar a configuração gerenciada dele.
O provedor de configurações gerenciadas é outro app executado no mesmo dispositivo. Esse app geralmente é controlado pelo administrador de TI. O administrador de TI comunica as mudanças de configuração ao app gerenciado do provedor de configuração. Esse app, por sua vez, muda as configurações no seu app.
Para fornecer configurações gerenciadas externamente:
- Declare as configurações gerenciadas no manifesto do app. Isso permite que o administrador de TI leia as configurações do app pelas APIs do Google Play.
- Sempre que o app for retomado, use o objeto
RestrictionsManager
para verificar as configurações gerenciadas atuais e mudar a interface e o comportamento do app para se adequar a essas configurações. - Ouça a
intent
ACTION_APPLICATION_RESTRICTIONS_CHANGED
. Quando você receber essa transmissão, verifique oRestrictionsManager
para saber quais são as configurações gerenciadas atuais e faça as mudanças necessárias no comportamento do app.
Definir configurações gerenciadas
Seu app pode oferecer suporte a qualquer configuração gerenciada que você queira definir. Declare as configurações gerenciadas do app em um arquivo de configurações gerenciadas e declare o arquivo de configurações no manifesto. A criação de um arquivo de configuração permite que outros apps examinem as configurações gerenciadas fornecidas pelo seu app. Os parceiros de EMM podem ler as configurações do app usando as APIs do Google Play.
Para definir as opções de configuração remota do app, coloque o seguinte elemento
no elemento
<application>
do manifesto:
<meta-data android:name="android.content.APP_RESTRICTIONS" android:resource="@xml/app_restrictions" />
Crie um arquivo chamado app_restrictions.xml
no diretório
res/xml
do app. A estrutura desse arquivo é descrita na
referência para RestrictionsManager
. O arquivo tem um
único elemento <restrictions>
de nível superior, que contém
um elemento filho <restriction>
para cada opção
de configuração do app.
Observação:não crie versões localizadas do arquivo de configuração gerenciado. Seu app só pode ter um arquivo de configurações gerenciadas, para que as configurações sejam consistentes em todos os locais.
Em um ambiente empresarial, um EMM geralmente usa o esquema de configuração gerenciada para gerar um console remoto para administradores de TI configurarem o aplicativo remotamente.
O provedor de configuração gerenciada pode consultar o app para encontrar detalhes sobre as configurações disponíveis, incluindo o texto da descrição. O provedor de configurações e o administrador de TI podem mudar as configurações gerenciadas do app a qualquer momento, mesmo quando ele não está em execução.
Por exemplo, suponha que seu app possa ser configurado remotamente para permitir ou proibir
o download de dados por uma conexão de celular. O app pode ter um
elemento <restriction>
como este:
<?xml version="1.0" encoding="utf-8"?> <restrictions xmlns:android="http://schemas.android.com/apk/res/android"> <restriction android:key="downloadOnCellular" android:title="@string/download_on_cell_title" android:restrictionType="bool" android:description="@string/download_on_cell_description" android:defaultValue="true" /> </restrictions>
Use o atributo android:key
de cada configuração para
ler o valor de um pacote de configuração gerenciado. Por esse motivo,
cada configuração precisa ter uma string de chave exclusiva, e a string
não pode ser localizada. Ele precisa ser especificado com um literal de string.
Observação:em um app de produção, android:title
e
android:description
precisam ser extraídos de um arquivo de recurso
localizado, conforme descrito em
Localização com recursos.
Um app define restrições usando pacotes em um bundle_array
.
Por exemplo, um app com várias opções de conexão VPN pode definir cada configuração de servidor
VPN em um bundle
, com vários
pacotes agrupados em uma matriz de pacotes:
<?xml version="1.0" encoding="utf-8"?> <restrictions xmlns:android="http://schemas.android.com/apk/res/android" > <restriction android:key="vpn_configuration_list" android:restrictionType="bundle_array"> <restriction android:key="vpn_configuration" android:restrictionType="bundle"> <restriction android:key="vpn_server" android:restrictionType="string"/> <restriction android:key="vpn_username" android:restrictionType="string"/> <restriction android:key="vpn_password" android:restrictionType="string"/> </restriction> </restriction> </restrictions>
Os tipos compatíveis com o elemento android:restrictionType
estão listados na Tabela 1 e documentados na
referência de RestrictionsManager
e
RestrictionEntry
.
Tabela 1. Tipos de entrada e uso de restrições.
Tipo | android:restrictionType | Uso típico |
---|---|---|
TYPE_BOOLEAN
|
"bool" |
Um valor booleano, verdadeiro ou falso. |
TYPE_STRING
|
"string" |
Um valor de string, como um nome. |
TYPE_INTEGER
|
"integer" |
Um número inteiro com um valor de
MIN_VALUE a
MAX_VALUE .
|
TYPE_CHOICE
|
"choice" |
Um valor de string selecionado em android:entryValues ,
normalmente apresentado como uma lista de seleção única.
|
TYPE_MULTI_SELECT
|
"multi-select" |
Uma matriz de string com valores selecionados de android:entryValues .
Use isso para apresentar uma lista de seleção múltipla em que mais de uma
entrada pode ser selecionada, como para escolher títulos específicos para a lista de permissões.
|
TYPE_NULL
|
"hidden" |
Tipo de restrição oculta. Use esse tipo para informações que precisam ser transferidas, mas não podem ser apresentadas ao usuário na interface. Armazena um único valor de string. |
TYPE_BUNDLE_ARRAY
|
"bundle_array" |
Use para armazenar matrizes de restrição
bundles . Disponível no Android 6.0 (nível 23 da API).
|
Observação:android:entryValues
são legíveis por máquina e não podem ser
localizadas. Use android:entries
para apresentar valores legíveis por humanos que podem ser localizados.
Cada entrada precisa ter um índice correspondente em android:entryValues
.
Verificar as configurações gerenciadas
O app não é notificado automaticamente quando outros apps mudam as configurações. Em vez disso, você precisa verificar quais são as configurações gerenciadas quando o app é iniciado ou retomado e detectar uma intent do sistema para descobrir se as configurações mudam enquanto o app está em execução.
Para descobrir as configurações atuais, o app usa um
objeto RestrictionsManager
. O app precisa
verificar as configurações gerenciadas atuais nos seguintes momentos:
- Quando o app é iniciado ou retomado, no
método
onResume()
- Quando o app é notificado sobre uma mudança de configuração, conforme descrito em Detectar mudanças de configuração gerenciadas
Para receber um objeto RestrictionsManager
, receba a atividade
atual com getActivity()
e, em seguida,
chame o método Activity.getSystemService()
dessa atividade:
Kotlin
var myRestrictionsMgr = activity?.getSystemService(Context.RESTRICTIONS_SERVICE) as RestrictionsManager
Java
RestrictionsManager myRestrictionsMgr = (RestrictionsManager) getActivity() .getSystemService(Context.RESTRICTIONS_SERVICE);
Depois de ter um RestrictionsManager
, você pode acessar as
configurações de configuração atuais chamando o
método getApplicationRestrictions()
:
Kotlin
var appRestrictions: Bundle = myRestrictionsMgr.applicationRestrictions
Java
Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();
Observação:para sua conveniência, você também pode buscar as configurações
atuais com um UserManager
chamando
UserManager.getApplicationRestrictions()
. Esse método se comporta exatamente
como RestrictionsManager.getApplicationRestrictions()
.
O método getApplicationRestrictions()
exige a leitura do armazenamento de dados. Portanto, ele precisa ser usado com moderação. Não chame esse método sempre que precisar
saber a configuração atual. Em vez disso, chame-o uma vez quando o app
for iniciado ou retomado e armazene em cache o pacote de configurações gerenciadas buscado. Em seguida, detecte
a intent ACTION_APPLICATION_RESTRICTIONS_CHANGED
para descobrir se a configuração
mudou enquanto o app estava ativo, conforme descrito em
Detectar mudanças de configuração gerenciadas.
Como ler e aplicar configurações gerenciadas
O método getApplicationRestrictions()
retorna um Bundle
contendo um par de chave-valor para cada configuração definida. Os
valores são todos do tipo Boolean
, int
,
String
e String[]
. Depois de ter as
configurações gerenciadas Bundle
, é possível verificar as configurações
atuais com os métodos Bundle
padrão para
esses tipos de dados, como getBoolean()
ou
getString()
.
Observação:as configurações gerenciadas Bundle
contêm um item para cada configuração definida explicitamente por um
provedor de configurações gerenciadas. No entanto, não é possível presumir que uma
configuração vai estar presente no pacote só porque você definiu um valor
padrão no arquivo XML de configurações gerenciadas.
Cabe ao app tomar as medidas adequadas com base nas configurações de configuração
gerenciada atuais. Por exemplo, se o app tiver uma
configuração que especifique se ele pode fazer o download de dados por uma
conexão de celular e a configuração estiver definida como
false
, será necessário desativar o download de dados, exceto quando
o dispositivo tiver uma conexão Wi-Fi, conforme mostrado no exemplo de código abaixo:
Kotlin
val appCanUseCellular: Boolean = if (appRestrictions.containsKey("downloadOnCellular")) { appRestrictions.getBoolean("downloadOnCellular") } else { // cellularDefault is a boolean using the restriction's default value cellularDefault } if (!appCanUseCellular) { // ...turn off app's cellular-download functionality // ...show appropriate notices to user }
Java
boolean appCanUseCellular; if (appRestrictions.containsKey("downloadOnCellular")) { appCanUseCellular = appRestrictions.getBoolean("downloadOnCellular"); } else { // cellularDefault is a boolean using the restriction's default value appCanUseCellular = cellularDefault; } if (!appCanUseCellular) { // ...turn off app's cellular-download functionality // ...show appropriate notices to user }
Para aplicar várias restrições aninhadas, leia
a entrada de restrição bundle_array
como uma coleção de objetos Parcelable
e converta como Bundle
. Neste exemplo, os dados de configuração de cada VPN
são analisados e usados para criar uma lista de opções de conexão de servidor:
Kotlin
// VpnConfig is a sample class used store config data, not defined val vpnConfigs = mutableListOf<VpnConfig>() val parcelables: Array<out Parcelable>? = appRestrictions.getParcelableArray("vpn_configuration_list") if (parcelables?.isNotEmpty() == true) { // iterate parcelables and cast as bundle parcelables.map { it as Bundle }.forEach { vpnConfigBundle -> // parse bundle data and store in VpnConfig array vpnConfigs.add(VpnConfig() .setServer(vpnConfigBundle.getString("vpn_server")) .setUsername(vpnConfigBundle.getString("vpn_username")) .setPassword(vpnConfigBundle.getString("vpn_password"))) } } if (vpnConfigs.isNotEmpty()) { // ...choose a VPN configuration or prompt user to select from list }
Java
// VpnConfig is a sample class used store config data, not defined List<VpnConfig> vpnConfigs = new ArrayList<>(); Parcelable[] parcelables = appRestrictions.getParcelableArray("vpn_configuration_list"); if (parcelables != null && parcelables.length > 0) { // iterate parcelables and cast as bundle for (int i = 0; i < parcelables.length; i++) { Bundle vpnConfigBundle = (Bundle) parcelables[i]; // parse bundle data and store in VpnConfig array vpnConfigs.add(new VpnConfig() .setServer(vpnConfigBundle.getString("vpn_server")) .setUsername(vpnConfigBundle.getString("vpn_username")) .setPassword(vpnConfigBundle.getString("vpn_password"))); } } if (!vpnConfigs.isEmpty()) { // ...choose a VPN configuration or prompt user to select from list }
Detectar mudanças de configuração gerenciada
Sempre que as configurações gerenciadas de um app são alteradas, o sistema dispara a
intent ACTION_APPLICATION_RESTRICTIONS_CHANGED
. O app precisa detectar
essa intent para que você possa mudar o comportamento dele quando as configurações
mudarem.
Observação:a intent ACTION_APPLICATION_RESTRICTIONS_CHANGED
é enviada apenas para listeners
registrados dinamicamente, não para listeners declarados
no manifesto do app.
O código a seguir mostra como registrar dinamicamente um broadcast receiver para essa intent:
Kotlin
val restrictionsFilter = IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED) val restrictionsReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { // Get the current configuration bundle val appRestrictions = myRestrictionsMgr.applicationRestrictions // Check current configuration settings, change your app's UI and // functionality as necessary. } } registerReceiver(restrictionsReceiver, restrictionsFilter)
Java
IntentFilter restrictionsFilter = new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED); BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // Get the current configuration bundle Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions(); // Check current configuration settings, change your app's UI and // functionality as necessary. } }; registerReceiver(restrictionsReceiver, restrictionsFilter);
Observação:normalmente, o app não precisa ser notificado sobre mudanças de configuração quando está pausado. Em vez disso, cancele o registro do broadcast receiver quando o app for pausado. Quando o app é retomado, você primeiro verifica as configurações gerenciadas atuais (conforme discutido em Verificar configurações gerenciadas) e depois registra o broadcast receiver para garantir que você seja notificado sobre mudanças de configuração que ocorrem enquanto o app está ativo.
Enviar feedback de configuração gerenciada para EMMs
Depois de aplicar as mudanças de configuração gerenciada ao app, é recomendável notificar os EMMs sobre o status da mudança. O Android oferece suporte a um recurso chamado estados de app com chave, que pode ser usado para enviar feedback sempre que o app tentar aplicar mudanças de configuração gerenciada. Esse feedback pode servir como confirmação de que o app definiu as configurações gerenciadas com sucesso ou pode incluir uma mensagem de erro se o app não conseguir aplicar as mudanças especificadas.
Os provedores de EMM podem recuperar esse feedback e exibi-lo nos consoles para que os administradores de TI possam conferir. Consulte Enviar feedback do app para EMMs para mais informações sobre o assunto, incluindo um guia detalhado sobre como adicionar suporte a feedback ao seu app.
Outros exemplos de código
O exemplo ManagedConfigurations demonstra melhor o uso das APIs abordadas nesta página.
Adicionar/remover apps da lista de permissões no perfil pessoal
As lojas de apps de terceiros podem expressar interesse em usar as configurações gerenciadas para ter uma maneira confiável de aplicar uma lista de permissões ou de bloqueio de apps ao perfil pessoal e ao recurso Espaço particular do consumidor, que é um espaço pessoal adicional para os usuários manterem os apps sensíveis. Se você desenvolve uma app store para uso empresarial e gostaria de usar esse recurso, envie este formulário para expressar seu interesse e selecione Interest in 3P app store allowlisting como Reason for Response no formulário.