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 aplicativo, permitem que o administrador de TI da organização especifique remotamente as configurações dos apps. Esse recurso é particularmente útil 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 para um navegador da Web
- Configurar se um app pode sincronizar conteúdo por rede celular ou apenas por Wi-Fi
- Definir as configurações de e-mail do app
Este guia mostra como implementar definições de configurações gerenciadas no app. Para acessar apps de exemplo com uma configuração gerenciada, consulte ManagedConfigurations. Se você é um desenvolvedor de gerenciamento de mobilidade empresarial (EMM, na sigla em inglês), consulte o guia da API Android Management.
Observação:por motivos históricos, essas definições de configuração 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 variedade 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. São configurações arbitrárias que podem ser alteradas por um provedor de configuração gerenciado. Se o app estiver sendo executado em um perfil de trabalho, o administrador de TI poderá alterar a configuração gerenciada dele.
O provedor de configurações gerenciadas é outro app em execução no mesmo dispositivo. Esse app geralmente é controlado pelo administrador de TI. O administrador de TI comunica as mudanças de configuração ao app do provedor de configuração gerenciada. Esse app, por sua vez, altera as configurações do 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 nas APIs do Google Play.
- Sempre que o app for retomado, use o objeto
RestrictionsManager
para verificar as configurações gerenciadas atuais e mude a interface e o comportamento do app para se adequar a essas configurações. - Detecte o
intent
ACTION_APPLICATION_RESTRICTIONS_CHANGED
. Quando você receber essa transmissão, verifique oRestrictionsManager
para ver quais são as configurações gerenciadas atuais e faça as mudanças necessárias no comportamento do app.
Definir configurações gerenciadas
O app oferece suporte a qualquer configuração gerenciada que você quiser definir. Você declara as configurações gerenciadas do app em um arquivo de configurações gerenciadas e o arquivo de configurações no manifesto. A criação de um arquivo de configurações permite que outros apps examinem as configurações gerenciadas que seu app oferece. Os parceiros de EMM podem ler as configurações do seu app usando as APIs do Google Play.
Para definir as opções de configuração remota do seu app, coloque o seguinte elemento no elemento
<application>
do seu 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 está descrita na referência de 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 gerenciada. Seu app só pode ter um único arquivo de configurações gerenciado. Portanto, as configurações serão consistentes para o app em todas as localidades.
Em um ambiente corporativo, um EMM normalmente usa o esquema de configuração gerenciada para gerar um console remoto para administradores de TI, permitindo que eles configurem 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 de 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 celular. Seu 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ções gerenciado. Por esse motivo,
cada configuração precisa ter uma string de chave exclusiva, e essa 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 desenhados de um arquivo de recurso
localizado, conforme descrito em
Localizar com recursos.
Um app define restrições usando pacotes em uma bundle_array
.
Por exemplo, um app com várias opções de conexão de VPN pode definir cada configuração de servidor
de VPN em uma bundle
, com vários
pacotes agrupados em uma matriz:
<?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
.
Tipo | android:restrictionType | Uso normal |
---|---|---|
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 de android:entryValues ,
normalmente apresentado como uma lista de seleção única.
|
TYPE_MULTI_SELECT
|
"multi-select" |
Uma matriz de strings com valores selecionados de android:entryValues .
Use para apresentar uma lista de seleção múltipla em que mais de uma
entrada pode ser selecionada, por exemplo, para escolher títulos específicos para a lista de permissões.
|
TYPE_NULL
|
"hidden" |
Tipo de restrição oculto. Use esse tipo para informações que precisam ser transferidas, mas não devem ser apresentadas ao usuário na interface. Armazena um único valor de string. |
TYPE_BUNDLE_ARRAY
|
"bundle_array" |
Use-o para armazenar matrizes de restrição bundles . Disponível no Android 6.0 (API de nível 23).
|
Observação:android:entryValues
são legíveis por máquina e não podem ser localizados. Use android:entries
para apresentar valores legíveis que podem ser localizados.
Cada entrada precisa ter um índice correspondente em android:entryValues
.
Verificar as configurações gerenciadas
Seu app não recebe uma notificação automática quando outros apps mudam as definições de configuração. Em vez disso, você precisa verificar quais são as configurações gerenciadas quando seu 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 definições de configuração atuais, o app usa um objeto
RestrictionsManager
. Seu app precisa
verificar as configurações gerenciadas atuais nos seguintes momentos:
- Quando o app é iniciado ou retomado, no método
onResume()
dele. - 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
, acesse a atividade
atual com getActivity()
e
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);
Quando você tiver um RestrictionsManager
, será possível ver as
definições de configuração atuais chamando o método
getApplicationRestrictions()
dele:
Kotlin
var appRestrictions: Bundle = myRestrictionsMgr.applicationRestrictions
Java
Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();
Observação:por conveniência, você também pode buscar as configurações
atuais com um UserManager
chamando
UserManager.getApplicationRestrictions()
. Esse método se comporta exatamente da
mesma forma que RestrictionsManager.getApplicationRestrictions()
.
O método getApplicationRestrictions()
requer a leitura do armazenamento de dados, portanto, isso deve ser feito com moderação. Não chame esse método sempre que você precisar saber a configuração atual. Em vez disso, é necessário chamá-lo uma vez quando o app
for iniciado ou retomado e armazenar em cache o pacote de configurações gerenciadas buscado. Em seguida, detecte
o intent ACTION_APPLICATION_RESTRICTIONS_CHANGED
para descobrir se a configuração
muda enquanto o app está ativo, conforme descrito em
Detectar mudanças de configuração gerenciadas.
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[]
. Assim que tiver as
configurações gerenciadas Bundle
, será possível verificar as
definiçõ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 que foi definida explicitamente por um
provedor de configurações gerenciadas. No entanto, não é possível presumir que uma configuração estará presente no pacote só porque você definiu um valor padrão no arquivo XML de configurações gerenciadas.
Cabe ao seu app tomar as medidas apropriadas com base nas configurações gerenciadas atuais. Por exemplo, se o app tiver uma
configuração que especifica se pode fazer o download de dados por uma
conexão celular e você descobrir que a configuração está definida como
false
, desative o download de dados, exceto quando
o dispositivo tiver uma conexão Wi-Fi, conforme mostrado no código de exemplo a seguir:
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 transmita como uma 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 do 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 o
intent ACTION_APPLICATION_RESTRICTIONS_CHANGED
. Seu app precisa detectar esse intent para que você possa mudar o comportamento do app quando as definições de configuração forem alteradas.
Observação:a intent ACTION_APPLICATION_RESTRICTIONS_CHANGED
é enviada somente aos listeners
registrados dinamicamente, não aos que foram 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, seu 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 estiver pausado. Quando o app for retomado, você primeiro vai verificar as configurações gerenciadas atuais (conforme discutido em Verificar configurações gerenciadas) e, em seguida, registrar o broadcast receiver para garantir que você seja notificado sobre as mudanças de configuração que ocorrem enquanto o app está ativo.
Enviar feedback sobre a configuração gerenciada para EMMs
Depois de aplicar as mudanças de configuração gerenciada ao app, é recomendado notificar os EMMs sobre o status da mudança. O Android oferece suporte a um recurso chamado estados de apps com chaves, que você pode usar para enviar feedback sempre que o app tentar aplicar mudanças de configuração gerenciadas. Esse feedback pode servir como confirmação de que seu app definiu as configurações gerenciadas corretamente ou pode incluir uma mensagem de erro se o app não aplicar as mudanças especificadas.
Os provedores de EMM podem recuperar esse feedback e exibi-lo nos consoles para os administradores de TI. Consulte Enviar feedback do app para EMMs para mais informações sobre o tópico, incluindo um guia detalhado sobre como adicionar suporte a feedback ao seu app.
Outros exemplos de código
A amostra ManagedConfigurations demonstra melhor o uso das APIs abordadas nesta página.