Verwaltete Konfigurationen einrichten

Wenn Sie Anwendungen für den Unternehmensmarkt entwickeln, müssen Sie möglicherweise bestimmte Anforderungen erfüllen, die in den Richtlinien einer Organisation festgelegt sind. Mit verwalteten Konfigurationen, die früher als Anwendungseinschränkungen bezeichnet wurden, kann der IT-Administrator der Organisation per Remote-Zugriff Einstellungen für Anwendungen festlegen. Diese Funktion ist besonders nützlich für Anwendungen, die von der Organisation genehmigt wurden und in einem Arbeitsprofil bereitgestellt werden.

Beispielsweise kann eine Organisation festlegen, dass der IT-Administrator mit genehmigten Anwendungen Folgendes tun kann:

  • URLs für Webbrowser zulassen oder blockieren
  • Festlegen, ob eine App Inhalte über Mobilfunknetz oder nur über WLAN synchronisieren darf
  • E-Mail-Einstellungen der Anwendung konfigurieren

In diesem Leitfaden wird beschrieben, wie Sie Einstellungen für verwaltete Konfigurationen in Ihrer App implementieren. Beispiel-Apps mit einer verwalteten Konfiguration finden Sie unter ManagedConfigurations. Wenn Sie ein EMM-Entwickler (Enterprise Mobility Management) sind, lesen Sie bitte den Leitfaden zur Android Management API.

Hinweis: Aus historischen Gründen werden diese Konfigurationseinstellungen als Einschränkungen bezeichnet und mit Dateien und Klassen implementiert, die diesen Begriff verwenden (z. B. RestrictionsManager). Durch diese Einschränkungen können jedoch eine Vielzahl von Konfigurationsoptionen implementiert werden, nicht nur Einschränkungen in Bezug auf die App-Funktionen.

Remotekonfiguration – Übersicht

Anwendungen definieren die verwalteten Konfigurationsoptionen, die von einem IT-Administrator remote festgelegt werden können. Dies sind beliebige Einstellungen, die von einem Anbieter verwalteter Konfigurationen geändert werden können. Wenn deine Anwendung in einem Arbeitsprofil ausgeführt wird, kann der IT-Administrator die verwaltete Konfiguration deiner Anwendung ändern.

Der Anbieter für verwaltete Konfigurationen ist eine andere App, die auf demselben Gerät ausgeführt wird. Diese App wird normalerweise vom IT-Administrator verwaltet. Der IT-Administrator teilt der Anwendung des Anbieters verwalteter Konfigurationen Konfigurationsänderungen mit. Diese Anwendung ändert wiederum die Konfigurationen in der Anwendung.

So stellen Sie extern verwaltete Konfigurationen bereit:

  • Deklariere die verwalteten Konfigurationen in deinem App-Manifest. So kann der IT-Administrator die Konfigurationen der App über Google Play APIs lesen.
  • Wenn die Anwendung fortgesetzt wird, prüfen Sie mit dem Objekt RestrictionsManager die aktuell verwalteten Konfigurationen und ändern Sie die UI und das Verhalten der Anwendung so, dass sie diesen Konfigurationen entspricht.
  • Warten Sie auf den Intent ACTION_APPLICATION_RESTRICTIONS_CHANGED. Wenn Sie diesen Broadcast erhalten, prüfen Sie die RestrictionsManager, um die aktuellen verwalteten Konfigurationen zu sehen und alle erforderlichen Änderungen am Verhalten der Anwendung vorzunehmen.

Verwaltete Konfigurationen definieren

Ihre App kann jede verwaltete Konfiguration unterstützen, die Sie definieren möchten. Sie deklarieren die verwalteten Konfigurationen der Anwendung in einer verwalteten Konfigurationsdatei und die Konfigurationsdatei im Manifest. Wenn Sie eine Konfigurationsdatei erstellen, können andere Anwendungen die verwalteten Konfigurationen Ihrer Anwendung untersuchen. EMM-Partner können die Konfigurationen deiner App mithilfe von Google Play APIs lesen.

Um die Remote-Konfigurationsoptionen Ihrer App zu definieren, fügen Sie das folgende Element in das Element <application> Ihres Manifests ein:

<meta-data android:name="android.content.APP_RESTRICTIONS"
    android:resource="@xml/app_restrictions" />

Erstellen Sie im Verzeichnis res/xml Ihrer Anwendung eine Datei mit dem Namen app_restrictions.xml. Die Struktur dieser Datei wird in der Referenz zu RestrictionsManager beschrieben. Die Datei hat auf oberster Ebene ein einzelnes <restrictions>-Element, das für jede Konfigurationsoption der App ein untergeordnetes <restriction>-Element enthält.

Hinweis:Erstellen Sie keine lokalisierten Versionen der verwalteten Konfigurationsdatei. Ihre Anwendung darf nur eine einzige verwaltete Konfigurationsdatei haben. Daher sind die Konfigurationen für Ihre Anwendung in allen Sprachen einheitlich.

In einer Unternehmensumgebung nutzt ein EMM in der Regel das verwaltete Konfigurationsschema, um eine Remote-Konsole für IT-Administratoren zu generieren, damit die Administratoren Ihre Anwendung remote konfigurieren können.

Der Anbieter verwalteter Konfigurationen kann die Anwendung abfragen, um Details zu den verfügbaren Konfigurationen der Anwendung, einschließlich des Beschreibungstexts, zu erhalten. Der Konfigurationsanbieter und der IT-Administrator können die verwalteten Konfigurationen Ihrer Anwendung jederzeit ändern, auch wenn die Anwendung nicht ausgeführt wird.

Angenommen, Ihre App kann per Fernzugriff so konfiguriert werden, dass sie das Herunterladen von Daten über eine Mobilfunkverbindung zulässt oder verbietet. Ihre App könnte ein <restriction>-Element wie dieses haben:

<?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>

Mit dem Attribut android:key jeder Konfiguration können Sie deren Wert aus einem verwalteten Konfigurationspaket lesen. Aus diesem Grund muss jede Konfiguration einen eindeutigen Schlüsselstring haben und der String kann nicht lokalisiert werden. Er muss mit einem Stringliteral angegeben werden.

Hinweis:In einer Produktions-App sollten android:title und android:description aus einer lokalisierten Ressourcendatei abgerufen werden, wie unter Mit Ressourcen lokalisieren beschrieben.

Eine App definiert Einschränkungen mithilfe von Bundles in einer bundle_array. Beispielsweise könnte eine Anwendung mit mehreren VPN-Verbindungsoptionen jede VPN-Serverkonfiguration in einem bundle definieren, wobei mehrere Bundles in einem Bundle-Array gruppiert sind:

<?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>

Die unterstützten Typen für das Element android:restrictionType sind in Tabelle 1 aufgeführt und in der Referenz zu RestrictionsManager und RestrictionEntry dokumentiert.

Tabelle 1 Arten und Nutzung von Einschränkungseinträgen.

Typ android:restrictionType Typische Verwendung
TYPE_BOOLEAN "bool" Boolescher Wert, wahr oder falsch.
TYPE_STRING "string" Ein Stringwert, z. B. ein Name.
TYPE_INTEGER "integer" Eine Ganzzahl mit einem Wert zwischen MIN_VALUE und MAX_VALUE.
TYPE_CHOICE "choice" Ein aus android:entryValues ausgewählter Stringwert, der in der Regel als Liste mit Einzelauswahl dargestellt wird.
TYPE_MULTI_SELECT "multi-select" Ein String-Array mit Werten aus android:entryValues. Verwende diese Option, um eine Liste mit Mehrfachauswahl zu präsentieren, in der mehr als ein Eintrag ausgewählt werden kann, z. B. um bestimmte Titel für die Zulassungsliste auszuwählen.
TYPE_NULL "hidden" Ausgeblendeter Einschränkungstyp. Verwenden Sie diesen Typ für Informationen, die übertragen werden müssen, dem Nutzer aber nicht in der UI angezeigt werden sollen. Speichert einen einzelnen Stringwert.
TYPE_BUNDLE_ARRAY "bundle_array" Wird zum Speichern von Arrays mit der Einschränkung bundles verwendet. Verfügbar in Android 6.0 (API-Level 23).

Hinweis: android:entryValues sind maschinenlesbar und können nicht lokalisiert werden. Verwenden Sie android:entries, um menschenlesbare Werte darzustellen, die lokalisiert werden können. Jeder Eintrag muss einen entsprechenden Index in android:entryValues haben.

Verwaltete Konfigurationen prüfen

Ihre Anwendung wird nicht automatisch benachrichtigt, wenn andere Apps ihre Konfigurationseinstellungen ändern. Stattdessen müssen Sie prüfen, welche verwalteten Konfigurationen vorhanden sind, wenn Ihre Anwendung gestartet oder fortgesetzt wird, und auf einen System-Intent warten, um festzustellen, ob sich die Konfigurationen während der Ausführung der Anwendung ändern.

Ihre Anwendung verwendet ein RestrictionsManager-Objekt, um die aktuellen Konfigurationseinstellungen zu ermitteln. Die Anwendung sollte zu folgenden Zeiten nach den aktuell verwalteten Konfigurationen suchen:

Für das Objekt RestrictionsManager rufen Sie die aktuelle Aktivität mit getActivity() ab und rufen dann die Methode Activity.getSystemService() dieser Aktivität auf:

Kotlin

var myRestrictionsMgr =
        activity?.getSystemService(Context.RESTRICTIONS_SERVICE) as RestrictionsManager

Java

RestrictionsManager myRestrictionsMgr =
    (RestrictionsManager) getActivity()
        .getSystemService(Context.RESTRICTIONS_SERVICE);

Sobald Sie eine RestrictionsManager haben, können Sie die aktuellen Konfigurationseinstellungen durch Aufrufen der entsprechenden getApplicationRestrictions()-Methode abrufen:

Kotlin

var appRestrictions: Bundle = myRestrictionsMgr.applicationRestrictions

Java

Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();

Hinweis: Sie können die aktuellen Konfigurationen auch mit einer UserManager abrufen, indem Sie UserManager.getApplicationRestrictions() aufrufen. Diese Methode verhält sich genau wie RestrictionsManager.getApplicationRestrictions().

Die Methode getApplicationRestrictions() muss aus dem Datenspeicher auslesen, daher sollte sie sparsam eingesetzt werden. Rufen Sie diese Methode nicht jedes Mal auf, wenn Sie die aktuelle Konfiguration kennen müssen. Stattdessen sollten Sie es einmal aufrufen, wenn Ihre Anwendung gestartet oder fortgesetzt wird, und das abgerufene Paket verwalteter Konfigurationen im Cache speichern. Warten Sie dann auf den Intent ACTION_APPLICATION_RESTRICTIONS_CHANGED, um festzustellen, ob sich die Konfiguration ändert, während die Anwendung aktiv ist, wie unter Auf Änderungen der verwalteten Konfiguration warten beschrieben.

Verwaltete Konfigurationen lesen und anwenden

Die Methode getApplicationRestrictions() gibt ein Bundle zurück, das für jede festgelegte Konfiguration ein Schlüssel/Wert-Paar enthält. Die Werte sind alle vom Typ Boolean, int, String und String[]. Sobald Sie die verwalteten Konfigurationen Bundle haben, können Sie die aktuellen Konfigurationseinstellungen mit den standardmäßigen Bundle-Methoden für diese Datentypen prüfen, z. B. getBoolean() oder getString().

Hinweis: Die verwalteten Konfigurationen Bundle enthalten ein Element für jede Konfiguration, die explizit von einem Anbieter verwalteter Konfigurationen festgelegt wurde. Sie können jedoch nicht davon ausgehen, dass das Bundle eine Konfiguration enthält, nur weil Sie in der XML-Datei für verwaltete Konfigurationen einen Standardwert definiert haben.

Es liegt an Ihrer Anwendung, basierend auf den aktuellen verwalteten Konfigurationseinstellungen geeignete Maßnahmen zu ergreifen. Wenn deine App beispielsweise eine Konfiguration hat, die angibt, ob sie Daten über eine Mobilfunkverbindung herunterladen kann, und diese Konfiguration auf false gesetzt ist, musst du den Datendownload deaktivieren, es sei denn, das Gerät hat eine WLAN-Verbindung, wie im folgenden Beispielcode gezeigt:

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
}

Wenn Sie mehrere verschachtelte Einschränkungen anwenden möchten, lesen Sie den Einschränkungseintrag bundle_array als Sammlung von Parcelable-Objekten und wandeln Sie ihn als Bundle um. In diesem Beispiel werden die Konfigurationsdaten jedes VPNs geparst und verwendet, um eine Liste mit Auswahlmöglichkeiten für die Serververbindung zu erstellen:

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
}

Auf verwaltete Konfigurationsänderungen warten

Bei jeder Änderung der verwalteten Konfigurationen einer App löst das System den Intent ACTION_APPLICATION_RESTRICTIONS_CHANGED aus. Ihre App muss auf diesen Intent warten, damit Sie das Verhalten der Anwendung ändern können, wenn sich die Konfigurationseinstellungen ändern.

Hinweis: Der Intent ACTION_APPLICATION_RESTRICTIONS_CHANGED wird nur an Listener gesendet, die dynamisch registriert werden, nicht an Listener, die im App-Manifest deklariert sind.

Der folgende Code zeigt, wie ein Broadcast-Empfänger für diesen Intent dynamisch registriert wird:

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);

Hinweis:Normalerweise muss Ihre Anwendung nicht über Konfigurationsänderungen benachrichtigt werden, wenn sie pausiert wird. Stattdessen sollten Sie die Registrierung des Übertragungsempfängers aufheben, wenn die App pausiert ist. Wenn die Anwendung fortgesetzt wird, prüfen Sie zuerst die aktuellen verwalteten Konfigurationen (wie unter Verwaltete Konfigurationen prüfen beschrieben) und registrieren Sie dann den Broadcast-Empfänger, damit Sie über Konfigurationsänderungen benachrichtigt werden, die während der aktiven Anwendung erfolgen.

Feedback zur verwalteten Konfiguration an EMMs senden

Nachdem Sie verwaltete Konfigurationsänderungen auf Ihre App angewendet haben, sollten Sie die EMM-Anbieter über den Status der Änderung informieren. Android unterstützt eine Funktion namens Schlüssel-App-Status, mit der du jedes Mal Feedback senden kannst, wenn deine App versucht, Änderungen an der verwalteten Konfiguration anzuwenden. Dieses Feedback kann als Bestätigung dafür dienen, dass die verwalteten Konfigurationen Ihrer App festgelegt wurden. Es kann aber auch eine Fehlermeldung enthalten, wenn die festgelegten Änderungen in Ihrer App nicht übernommen werden konnten.

EMM-Anbieter können dieses Feedback abrufen und in ihrer Konsole für IT-Administratoren anzeigen lassen. Weitere Informationen zu diesem Thema finden Sie unter App-Feedback an EMMs senden, einschließlich einer detaillierten Anleitung zum Hinzufügen von Feedbacksupport zu Ihrer App.

Zusätzliche Codebeispiele

Im Beispiel ManagedConfigurations wird die Verwendung der auf dieser Seite behandelten APIs weiter veranschaulicht.