管理対象設定のセットアップ

企業向け市場向けのアプリを開発している場合は、組織のポリシーで定められた特定の要件を満たす必要がある場合があります。管理対象設定(旧称は「アプリの制限」)により、組織の IT 管理者はリモートでアプリの設定を指定できます。この機能は、組織による承認を受けて仕事用プロファイルにデプロイされたアプリで特に有用です。

たとえば、組織では、承認済みのアプリで IT 管理者が次の操作を行えるようにすることが求められる場合があります。

  • ウェブブラウザの URL を許可またはブロックする
  • アプリがモバイル経由でコンテンツを同期できるかどうか、または Wi-Fi 経由でのみ同期できるかどうかを設定します。
  • アプリのメール設定を構成する

このガイドでは、アプリに管理対象設定を実装する方法について説明します。管理対象設定を使用したサンプルアプリについては、ManagedConfigurations をご覧ください。企業向けモバイル管理(EMM)デベロッパーの場合は、Android Management API ガイドをご覧ください。

注: 歴史的な理由から、これらの構成設定は制限と呼ばれ、この用語を使用するファイルとクラス(RestrictionsManager など)で実装されます。ただし、これらの制限は、アプリの機能の制限だけでなく、幅広い構成オプションを実装できます。

リモート構成の概要

アプリは、IT 管理者がリモートで設定できる管理対象設定オプションを定義します。これらは、マネージド構成プロバイダによって変更可能な任意の設定です。アプリが仕事用プロファイルで実行されている場合、IT 管理者はアプリの管理対象構成を変更できます。

管理対象構成プロバイダは、同じデバイスで実行されている別のアプリです。このアプリは通常、IT 管理者が管理します。IT 管理者は、構成の変更を管理対象構成プロバイダ アプリに通知します。そのアプリは、アプリの構成を変更します。

外部で管理される構成を指定するには:

  • アプリ マニフェストで管理対象設定を宣言します。これにより、IT 管理者は Google Play API を使用してアプリの設定を読み取ることができます。
  • アプリが再開されるたびに、RestrictionsManager オブジェクトを使用して現在のマネージド構成を確認し、それらの構成に準拠するようにアプリの UI と動作を変更します。
  • ACTION_APPLICATION_RESTRICTIONS_CHANGED インテントをリッスンします。このブロードキャストを受け取ったら、RestrictionsManager をチェックして現在の管理対象構成を確認し、アプリの動作に必要な変更を加えます。

管理対象構成を定義する

アプリは、定義する管理対象設定をすべてサポートできます。アプリのマネージド構成はマネージド構成ファイルで宣言し、構成ファイルをマニフェストで宣言します。構成ファイルを作成すると、他のアプリがアプリが提供する管理対象設定を調べることができます。EMM パートナーは、Google Play API を使用してアプリの構成を読み取ることができます。

アプリのリモート構成オプションを定義するには、マニフェストの <application> 要素に次の要素を追加します。

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

アプリの res/xml ディレクトリに app_restrictions.xml という名前のファイルを作成します。このファイルの構造については、RestrictionsManager のリファレンスをご覧ください。このファイルには、最上位の <restrictions> 要素が 1 つあり、アプリの構成オプションごとに 1 つの <restriction> 子要素が含まれています。

注: マネージド構成ファイルのローカライズ バージョンは作成しないでください。アプリには 1 つのマネージド構成ファイルのみを指定できるため、すべての言語 / 地域でアプリの構成が一貫します。

企業環境では、通常、EMM は管理対象の構成スキーマを使用して IT 管理者向けのリモート コンソールを生成し、管理者がリモートでアプリケーションを構成できるようにします。

マネージド構成プロバイダは、アプリにクエリを実行して、アプリで利用可能な構成の詳細(説明テキストなど)を確認できます。構成プロバイダと IT 管理者は、アプリが実行されていない場合でも、アプリの管理対象構成をいつでも変更できます。

たとえば、モバイル接続経由でデータをダウンロードすることを許可または禁止するようにアプリをリモートで構成できるとします。アプリには次のような <restriction> 要素が含まれている場合があります。

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

各構成の android:key 属性を使用して、マネージド構成バンドルから値を読み取ります。このため、各構成に一意のキー文字列が必要です。この文字列はローカライズできません。文字列リテラルで指定する必要があります。

注: 製品版アプリでは、リソースを使用したローカライズで説明されているように、android:titleandroid:description はローカライズされたリソース ファイルから描画する必要があります。

アプリは、bundle_array 内のバンドルを使用して制限を定義します。たとえば、複数の VPN 接続オプションがあるアプリでは、各 VPN サーバー構成を bundle で定義し、複数のバンドルをバンドル アレイにグループ化できます。

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

android:restrictionType 要素でサポートされているタイプは、表 1 に記載されています。また、RestrictionsManagerRestrictionEntry のリファレンスにも記載されています。

表 1. 制限エントリのタイプと使用方法。

タイプ android:restrictionType 一般的な使用方法
TYPE_BOOLEAN "bool" ブール値(true または false)。
TYPE_STRING "string" 名前などの文字列値。
TYPE_INTEGER "integer" MIN_VALUEMAX_VALUE の値を持つ整数。
TYPE_CHOICE "choice" android:entryValues から選択された文字列値。通常は単一選択リストとして表示されます。
TYPE_MULTI_SELECT "multi-select" android:entryValues から選択された値を含む文字列配列。許可リストに登録する特定のタイトルを選択する場合など、複数のエントリを選択できる複数選択リストを表示する場合に使用します。
TYPE_NULL "hidden" 非表示の制限タイプ。このタイプは、転送する必要があるが UI でユーザーに表示しない情報に使用します。単一の文字列値を格納します。
TYPE_BUNDLE_ARRAY "bundle_array" 制限 bundles の配列を格納する場合に使用します。Android 6.0(API レベル 23)で利用可能。

注: android:entryValues は機械読み取り可能であり、ローカライズできません。android:entries を使用して、ローカライズ可能な人が読める値を表示します。各エントリには android:entryValues 内の対応するインデックスが必要です。

管理対象設定を確認する

他のアプリが構成設定を変更しても、アプリに自動的に通知されることはありません。代わりに、アプリの起動時または再開時に管理対象の構成を確認して、システム インテントをリッスンし、アプリの実行中に構成が変更されたかどうかを確認する必要があります。

アプリは、現在の構成設定を確認するために RestrictionsManager オブジェクトを使用します。アプリは、次のタイミングで現在の管理対象設定を確認する必要があります。

RestrictionsManager オブジェクトを取得するには、getActivity() を使用して現在のアクティビティを取得し、そのアクティビティの Activity.getSystemService() メソッドを呼び出します。

Kotlin

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

Java

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

RestrictionsManager を取得したら、getApplicationRestrictions() メソッドを呼び出して現在の構成設定を取得できます。

Kotlin

var appRestrictions: Bundle = myRestrictionsMgr.applicationRestrictions

Java

Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();

注: 便宜上、UserManager.getApplicationRestrictions() を呼び出して、UserManager で現在の構成を取得することもできます。このメソッドは RestrictionsManager.getApplicationRestrictions() とまったく同じように動作します。

getApplicationRestrictions() メソッドではデータ ストレージからの読み取りが必要になるため、使用は控えめにする必要があります。現在の構成を確認する必要があるたびに、このメソッドを呼び出す必要はありません。代わりに、アプリの起動時または再開時に 1 回呼び出し、取得した管理対象設定バンドルをキャッシュに保存する必要があります。次に、管理対象設定の変更をリッスンするで説明されているように、ACTION_APPLICATION_RESTRICTIONS_CHANGED インテントをリッスンして、アプリのアクティブ中に構成が変更されたかどうかを確認します。

管理対象構成の読み取りと適用

getApplicationRestrictions() メソッドは、設定された各構成の Key-Value ペアを含む Bundle を返します。値はすべて BooleanintStringString[] の型です。管理対象の構成 Bundle を取得したら、getBoolean()getString() などのデータ型の標準 Bundle メソッドを使用して、現在の構成設定を確認できます。

注: マネージド構成 Bundle には、マネージド構成プロバイダによって明示的に設定された構成ごとに 1 つの項目が含まれます。ただし、マネージド構成 XML ファイルでデフォルト値を定義したからといって、バンドルに構成が存在するとは限りません

現在のマネージド構成設定に基づいて適切なアクションを実行するのはアプリ次第です。たとえば、アプリにモバイル接続経由でデータをダウンロードできるかどうかを指定する構成があり、その構成が false に設定されている場合は、次のコード例に示すように、デバイスが Wi-Fi に接続されている場合を除き、データのダウンロードを無効にする必要があります。

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
}

複数のネストされた制限を適用するには、bundle_array 制限エントリを Parcelable オブジェクトのコレクションとして読み取り、Bundle としてキャストします。この例では、各 VPN の構成データが解析され、サーバー接続オプションのリストが作成されます。

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
}

管理対象設定の変更をリッスンする

アプリの管理対象構成が変更されると、システムは ACTION_APPLICATION_RESTRICTIONS_CHANGED インテントを起動します。構成設定が変更されたときにアプリの動作を変更できるように、アプリはこのインテントをリッスンする必要があります。

注: ACTION_APPLICATION_RESTRICTIONS_CHANGED インテントは、動的に登録されたリスナーにのみ送信されます。アプリ マニフェストで宣言されたリスナーには送信されません。

次のコードは、このインテントのブロードキャスト レシーバを動的に登録する方法を示しています。

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

注: 通常、アプリが一時停止しているときに構成の変更について通知する必要はありません。代わりに、アプリが一時停止されたときにブロードキャスト レシーバーの登録を解除する必要があります。アプリが再開されたら、まず現在の管理対象設定を確認します(管理対象設定を確認するを参照)。次に、ブロードキャスト レシーバーを登録して、アプリのアクティブ中に発生した構成変更について通知を受け取るようにします。

管理対象設定のフィードバックを EMM に送信する

マネージド構成の変更をアプリに適用したら、変更のステータスを EMM に通知することをおすすめします。Android は、鍵付きアプリ状態と呼ばれる機能をサポートしています。この機能を使用すると、アプリが管理対象設定の変更を適用しようとするたびにフィードバックを送信できます。このフィードバックは、アプリがマネージド構成を正常に設定したことを確認する役割を果たします。また、アプリが指定された変更を適用できなかった場合は、エラー メッセージが含まれることもあります。

EMM プロバイダは、このフィードバックを取得してコンソールに表示し、IT 管理者が確認できるようにします。アプリにフィードバック サポートを追加する方法の詳細なガイドなど、このトピックについて詳しくは、EMM にアプリのフィードバックを送信するをご覧ください。

その他のコードサンプル

ManagedConfigurations サンプルでは、このページで説明した API の使用方法をさらに詳しく説明しています。

個人用プロファイルでアプリを許可リストまたはブロックリストに登録する

サードパーティ製アプリストアは、管理対象構成を使用して、個人プロファイルとプライベート スペースの両方にアプリのブロックリストまたは許可リストを適用する信頼性の高い方法を検討している場合があります。プライベート スペースは、ユーザーが機密性の高いアプリを保存するための追加の個人スペースです。企業向けのアプリストアを開発していて、この機能をご利用になりたい場合は、 こちらのフォームを送信してご希望をお知らせください。フォームの [Reason for Response](回答の理由)で [Interest in 3P app store allowlisting](サードパーティのアプリストアの許可リストへの登録に関心がある)を選択してください。