Ustawianie konfiguracji zarządzanych

Jeśli tworzysz aplikacje na potrzeby firm, może być konieczne spełnienie określonych wymagań określonych w zasadach organizacji. Konfiguracje zarządzane, nazywane wcześniej ograniczeniami aplikacji, umożliwiają administratorowi IT organizacji zdalne określanie ustawień aplikacji. Ta funkcja jest szczególnie przydatna w przypadku aplikacji zatwierdzonych przez organizację, wdrażanych w profilu służbowym.

Organizacja może na przykład wymagać, aby zatwierdzone aplikacje pozwalały administratorowi IT na:

  • Zezwalanie na adresy URL i ich blokowanie w przeglądarce
  • Określ, czy aplikacja może synchronizować treści przez sieć komórkową czy tylko przez Wi-Fi.
  • Skonfiguruj ustawienia poczty e-mail w aplikacji

Z tego przewodnika dowiesz się, jak wdrożyć w aplikacji ustawienia konfiguracji zarządzanej. Przykładowe aplikacje z konfiguracją zarządzaną znajdziesz w sekcji ManagedConfigurations. Jeśli jesteś deweloperem rozwiązań do zarządzania urządzeniami mobilnymi (EMM), zapoznaj się z przewodnikiem po interfejsie Android Management API.

Uwaga: ze względów historycznych te ustawienia konfiguracji są nazywane ograniczeniami i są zaimplementowane za pomocą plików i klas, które używają tego terminu (np. RestrictionsManager). Jednak te ograniczenia mogą powodować stosowanie szerokiej gamy opcji konfiguracji, a nie tylko ograniczeń funkcji aplikacji.

Omówienie konfiguracji zdalnej

Aplikacje określają opcje konfiguracji zarządzanej, które może ustawić zdalnie przez administratora IT. Są to dowolne ustawienia, które może zmienić dostawca konfiguracji zarządzanej. Jeśli Twoja aplikacja działa w profilu służbowym, administrator IT może zmienić jej konfigurację zarządzaną.

Dostawca konfiguracji zarządzanych to inna aplikacja uruchomiona na tym samym urządzeniu. Zwykle zarządza nim administrator IT. Administrator IT przekazuje informacje o zmianach konfiguracji w aplikacji dostawcy konfiguracji zarządzanej. Ta aplikacja z kolei zmienia konfiguracje Twojej aplikacji.

Aby udostępnić konfiguracje zarządzane zewnętrznie:

  • Zadeklaruj konfiguracje zarządzane w manifeście aplikacji. Dzięki temu administrator IT będzie mógł odczytywać konfiguracje aplikacji przy użyciu interfejsów Google Play API.
  • Przy wznowieniu aplikacji użyj obiektu RestrictionsManager, aby sprawdzić bieżące konfiguracje zarządzane i zmienić interfejs oraz działanie aplikacji, aby dostosować je do tych konfiguracji.
  • Nasłuchuj intencji ACTION_APPLICATION_RESTRICTIONS_CHANGED. Po otrzymaniu tej wiadomości sprawdź w RestrictionsManager, jakie są aktualne konfiguracje zarządzane, i wprowadź niezbędne zmiany w działaniu aplikacji.

Zdefiniuj konfiguracje zarządzane

Aplikacja może obsługiwać dowolną zdefiniowaną przez Ciebie konfigurację zarządzaną. Konfiguracje zarządzane aplikacji należy zadeklarować w pliku konfiguracji zarządzanych, a plik konfiguracji w pliku manifestu. Utworzenie pliku konfiguracji umożliwia innym aplikacjom sprawdzanie konfiguracji zarządzanych dostępnych w Twojej aplikacji. Partnerzy EMM mogą odczytywać konfiguracje aplikacji przy użyciu interfejsów Google Play API.

Aby określić opcje konfiguracji zdalnej aplikacji, umieść w elemencie <application> w pliku manifestu ten element:

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

Utwórz plik o nazwie app_restrictions.xml w katalogu res/xml aplikacji. Struktura tego pliku jest opisana w dokumentacji dotyczącej RestrictionsManager. Plik zawiera jeden element <restrictions> najwyższego poziomu, który zawiera 1 element podrzędny <restriction> dla każdej opcji konfiguracji używanej w aplikacji.

Uwaga: nie twórz zlokalizowanych wersji pliku konfiguracji zarządzanej. Twoja aplikacja może mieć tylko 1 zarządzany plik konfiguracji, więc konfiguracje będą spójne we wszystkich językach.

W środowisku firmowym dostawca usług EMM używa zwykle schematu konfiguracji zarządzanej do wygenerowania konsoli zdalnej dla administratorów IT, dzięki czemu administratorzy mogą zdalnie konfigurować Twoją aplikację.

Dostawca konfiguracji zarządzanej może wysyłać do aplikacji zapytanie o informacje o dostępnych konfiguracjach aplikacji, w tym o ich tekście opisu. Dostawca konfiguracji i administrator IT może w każdej chwili zmienić zarządzane konfiguracje aplikacji, nawet gdy aplikacja nie jest uruchomiona.

Załóżmy na przykład, że aplikację można zdalnie skonfigurować, zezwalając na pobieranie danych przez sieć komórkową lub w ten sposób zabraniać jej pobierania. Aplikacja może zawierać element <restriction> podobny do tego:

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

Atrybut android:key każdej konfiguracji służy do odczytywania jej wartości z zarządzanego pakietu konfiguracji. Z tego powodu każda konfiguracja musi mieć unikalny ciąg klucza, którego nie można zlokalizować. Musi być określona za pomocą literału ciągu znaków.

Uwaga: w produkcyjnej wersji aplikacji obiekty android:title i android:description powinny być pobierane ze zlokalizowanego pliku zasobów zgodnie z opisem w sekcji Lokalizacja przy użyciu zasobów.

Aplikacja definiuje ograniczenia za pomocą pakietów w obiekcie bundle_array. Na przykład aplikacja z wieloma opcjami połączenia VPN może definiować każdą konfigurację serwera VPN w obiekcie bundle przez zgrupowanie odpowiednich pakietów w tablicy pakietów:

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

Obsługiwane typy elementu android:restrictionType znajdziesz w tabeli 1, a w dokumentacji referencyjnej RestrictionsManager i RestrictionEntry.

Tabela 1. Typy wpisów o ograniczeniach i ich wykorzystanie.

Typ android:typ_ograniczeń Typowe zastosowanie
TYPE_BOOLEAN "bool" Wartość logiczna prawda lub fałsz.
TYPE_STRING "string" Wartość ciągu znaków, np. nazwa.
TYPE_INTEGER "integer" Liczba całkowita o wartości od MIN_VALUE do MAX_VALUE.
TYPE_CHOICE "choice" Wartość ciągu znaków wybrana z pola android:entryValues, zwykle prezentowana jako lista jednokrotnego wyboru.
TYPE_MULTI_SELECT "multi-select" Tablica z ciągami znaków i wartościami wybranymi z tabeli android:entryValues. Ta opcja służy do wyświetlania listy z możliwością wielokrotnego wyboru, na której można wybrać więcej niż 1 wpis, na przykład aby dodać konkretne tytuły do listy dozwolonych.
TYPE_NULL "hidden" Ukryty typ ograniczenia. Użyj tego typu do informacji, które mają być przesyłane, ale nie powinny być wyświetlane użytkownikowi w interfejsie. Zapisuje pojedynczą wartość ciągu znaków.
TYPE_BUNDLE_ARRAY "bundle_array" Służy do przechowywania tablic z ograniczeniami bundles. Dostępne w Androidzie 6.0 (poziom API 23).

Uwaga: pliki android:entryValues są czytelne dla komputera i nie można ich zlokalizować. Używaj metody android:entries, aby prezentować wartości zrozumiałe dla człowieka, które można zlokalizować. Każdy wpis musi mieć odpowiedni indeks w kolumnie android:entryValues.

Sprawdź konfiguracje zarządzane

Twoja aplikacja nie jest automatycznie powiadamiana, gdy inne aplikacje zmienią swoje ustawienia konfiguracji. Zamiast tego sprawdź, jakie są konfiguracje zarządzane podczas uruchamiania i wznawiania aplikacji, a także nasłuchuj intencji systemowej, aby sprawdzić, czy konfiguracje zmieniają się podczas działania aplikacji.

Aby sprawdzić bieżące ustawienia konfiguracji, aplikacja używa obiektu RestrictionsManager. Aplikacja powinna sprawdzić bieżące konfiguracje zarządzane w tych momentach:

Aby pobrać obiekt RestrictionsManager, pobierz bieżącą aktywność za pomocą getActivity(), a następnie wywołaj metodę Activity.getSystemService() tej aktywności:

Kotlin

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

Java

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

Gdy masz już RestrictionsManager, możesz pobrać bieżące ustawienia konfiguracji, wywołując jego metodę getApplicationRestrictions():

Kotlin

var appRestrictions: Bundle = myRestrictionsMgr.applicationRestrictions

Java

Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();

Uwaga: dla wygody możesz też pobrać obecne konfiguracje za pomocą UserManager, wywołując metodę UserManager.getApplicationRestrictions(). Ta metoda działa dokładnie tak samo jak RestrictionsManager.getApplicationRestrictions().

Metoda getApplicationRestrictions() wymaga odczytu danych z pamięci, więc należy jej używać z umiarem. Nie wywołuj tej metody za każdym razem, gdy chcesz poznać bieżącą konfigurację. Zamiast tego należy wywoływać go raz po uruchomieniu lub wznawianiu aplikacji i zapisywać w pamięci podręcznej pobrany pakiet konfiguracji zarządzanych. Następnie nasłuchuj intencji ACTION_APPLICATION_RESTRICTIONS_CHANGED, aby sprawdzić, czy konfiguracja się zmieniła, gdy aplikacja jest aktywna, zgodnie z opisem w sekcji Nasłuchiwanie zmian konfiguracji zarządzanej.

Odczytywanie i stosowanie konfiguracji zarządzanych

Metoda getApplicationRestrictions() zwraca Bundle zawierający parę klucz-wartość dla każdej konfiguracji, która została ustawiona. Wszystkie wartości są typu Boolean, int, String i String[]. Gdy będziesz już mieć konfiguracje zarządzane Bundle, możesz sprawdzić bieżące ustawienia konfiguracji za pomocą standardowych metod Bundle dla tych typów danych, takich jak getBoolean() czy getString().

Uwaga: konfiguracje zarządzane Bundle zawierają po jednym elemencie na każdą konfigurację jawnie ustawioną przez dostawcę konfiguracji zarządzanych. Nie możesz jednak zakładać, że konfiguracja pojawi się w pakiecie tylko dlatego, że w pliku XML konfiguracji zarządzanych została przez Ciebie zdefiniowana wartość domyślna.

Podejmowanie odpowiednich działań na podstawie bieżących ustawień konfiguracji zarządzanej zależy od Twojej aplikacji. Jeśli na przykład Twoja aplikacja ma konfigurację określającą, czy może pobierać dane przez połączenie komórkowe, ale ustawiona jest wartość false, pobieranie danych należy wyłączyć, chyba że urządzenie jest połączone z siecią Wi-Fi – tak jak w tym przykładowym kodzie:

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
}

Aby zastosować wiele ograniczeń zagnieżdżonych, przeczytaj wpis ograniczenia bundle_array jako zbiór Parcelable obiektów i rzutuj jako Bundle. W tym przykładzie dane konfiguracyjne każdej sieci VPN są analizowane i używane do tworzenia listy dostępnych połączeń z serwerem:

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
}

Wykrywaj zmiany konfiguracji zarządzanej

Po każdej zmianie zarządzanych konfiguracji aplikacji system uruchamia intencję ACTION_APPLICATION_RESTRICTIONS_CHANGED. Aplikacja musi nasłuchiwać tej intencji, aby umożliwić Ci zmianę jej działania po zmianie ustawień konfiguracji.

Uwaga: intencja ACTION_APPLICATION_RESTRICTIONS_CHANGED jest wysyłana tylko do zarejestrowanych dynamicznie detektorów, a nie do detektorów zadeklarowanych w pliku manifestu aplikacji.

Poniższy kod pokazuje, jak dynamicznie zarejestrować odbiornik w przypadku tej intencji:

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

Uwaga: zwykle nie trzeba powiadamiać aplikacji o zmianach w konfiguracji, gdy jest ona wstrzymana. Zamiast tego wyrejestruj odbiornik, gdy aplikacja jest wstrzymana. Po wznowieniu aplikacji najpierw sprawdź, czy są dostępne bieżące konfiguracje zarządzane (co zostało omówione w sekcji Sprawdzanie konfiguracji zarządzanych), a następnie zarejestrujesz odbiornika, aby otrzymywać powiadomienia o zmianach w konfiguracji, które zaszły w czasie, gdy aplikacja jest aktywna.

Wysyłanie opinii o konfiguracji zarządzanej do dostawców usług EMM

Po zastosowaniu w aplikacji zmian konfiguracji zarządzanej najlepiej jest powiadamiać dostawców usług EMM o stanie zmian. Android obsługuje funkcję o nazwie stany aplikacji z kluczem, która pozwala wysyłać opinię za każdym razem, gdy aplikacja próbuje wprowadzić zmiany w konfiguracji zarządzanej. Może ona być potwierdzeniem, że Twoja aplikacja skonfigurowała konfiguracje zarządzane, lub zawierać komunikat o błędzie, jeśli nie udało się zastosować określonych zmian w aplikacji.

Dostawcy usług EMM mogą pobierać te opinie i wyświetlać je w swoich konsolach, aby administratorzy IT mogli je zobaczyć. Więcej informacji na ten temat, w tym szczegółowy przewodnik na temat dodawania opinii o aplikacji, znajdziesz w artykule Wysyłanie opinii o aplikacji do usług EMM.

Dodatkowe przykłady kodu

Przykład ManagedConfigurations dodatkowo pokazuje wykorzystanie interfejsów API omówionych na tej stronie.