仕事用プロファイルで動作するアプリを作成する

仕事用プロファイルとは

仕事用プロファイルとは、従業員が個人所有のデバイスを業務に使用することを会社が許可している場合に、個人所有のデバイスで有効にできるセカンダリ プロファイルです。

仕事用プロファイルは、IT 管理者が管理でき、その機能はユーザーのメイン プロファイルの機能とは別に設定できます。このアプローチにより、組織はユーザーのデバイスで会社固有のアプリとデータが実行および使用される環境を制御し、同時にユーザーは個人のアプリとプロファイルを使用し続けることができます。

アプリにはどのような影響があるでしょうか。どんなアプリも仕事用プロファイルでインストールできますが、実行時に制限や動作変更を受ける場合があります。また、仕事で使用するアプリであれば、セキュリティを確保する必要もあります。アプリが個人用プロファイルで動作している場合でも、仕事用プロファイルが動作に影響を及ぼす場合があります。

前提条件

この Codelab は、初級から中級のスキルを持つ Android デベロッパーを対象としています。

アプリの作成、Android Studio の使用、デバイスまたはエミュレータでのアプリのテストを経験していることが前提です。

演習内容

この Codelab では、仕事用プロファイルを使ってデバイスにインストールされたときのユーザー エクスペリエンスが最大限に高まるようにアプリを変更します。次のようなアプリの作成方法を学びます。

  • 個人用と仕事用の両方の連絡先を同時に処理する。
  • アプリ内から仕事用プロファイルと個人用プロファイルを切り替える。

e69c26cfc305d675.png

必要なもの

  • 管理対象外の Android デバイス(組織が所有または管理していないもの)

テストデバイスをセットアップする

この Codelab には実機を使用することをおすすめしますが、エミュレータでも同じセットアップが可能です。

TestDPC

TestDPC は、デバイス上での管理対象環境のシミュレートとテストに役立つ Google が作成したアプリです。このアプリを使用することにより、仕事用プロファイルがセットアップされ、IT 管理者が行うのと同じように、デバイスで特定の機能の有効化と無効化を管理できるようになります。

TestDPC アプリをインストールする

デバイスから Google Play ストアを開き、TestDPC アプリをダウンロードします。

仕事用プロファイルをセットアップする

TestDPC アプリをインストールすると、デバイスに 2 つのアイコン(セットアップ アイコンと TestDPC アプリのアイコン)が表示されます。セットアップ アイコンをタップし、手順に沿って操作します。

これで、個人用アプリと仕事用アプリのために別々の 2 つのプロファイルができました。切り替えるにはアプリリストの上部にあるタブを使用します。

それぞれのプロファイルには専用の Play ストア アプリがあります。仕事用アプリを見つけるには、ランチャー アイコンの上部にある小さなブリーフケースのアイコンを使用します。

153e3b8dbfb4a86e.gif

アプリは Play ストアから通常どおりにインストール可能で、起動した Play ストアに応じて(個人用か仕事用か)対応するプロファイルのみにインストールされます。アプリを両方の Play ストアからインストールして、両方のプロファイルに存在させることもできます。その場合、両方のアプリの間でストレージと設定の空間が完全に分離されます。

Android Studio からアプリをインストールすると、デフォルトで両方のプロファイルにインストールされます。

デモアプリで使用するテスト用の連絡先を設定します。

  1. 個人用プロファイルからデバイスの連絡帳アプリを起動します。
  2. 個人用の連絡先だとわかるテスト用の連絡先を追加します。
  3. 仕事用プロファイルから連絡帳アプリを起動します(さきほど追加した個人用の連絡先は表示されません)。
  4. 仕事用の連絡先だとわかるテスト用の連絡先を追加します。

設定した連絡先に問題がなければ、デモアプリのスターター コードを試してください。

  1. 次のいずれかの方法でサンプルアプリを入手できます。
  • GitHub からリポジトリのクローンを作成する。
$  git clone https://github.com/a-samak/work-profile-codelab
  • リポジトリを ZIP ファイルとしてダウンロードする。

ZIP をダウンロード

  1. ダウンロードが完了したら、プロジェクト フォルダに移動し、starter ブランチに切り替えます。
$  git checkout starter
  1. Android Studio でアプリを開いて実行します。

アプリを初めて起動したときには次のように表示されます。

f9779ab476511718.png

試してみる

デバイスまたはエミュレータで Android Studio からアプリを実行すると、両方のプロファイルにインストールされます。必要に応じて、一方のプロファイルからアプリを削除し、もう一方には残しておくこともできます。

個人用プロファイルでアプリを実行してみてください。個人用の連絡先がすべて表示されますが、仕事用の連絡先は表示されません。続いて、仕事用プロファイルでアプリを実行してみてください。仕事用の連絡先だけが表示され、個人用の連絡先は表示されません。

この Codelab の終わりには、個人用プロファイルで実行したアプリに仕事用の連絡先と個人用の連絡先がいっしょに表示されるようになります。また、アプリ内からもう一方のプロファイルでアプリの別のインスタンスを起動して、プロファイルを切り替えることもできるようになります。

ContactsContract.Contacts.CONTENT_URI を使用して連絡先を読み込む場合、アプリはどちらのプロファイルで実行中かに応じて、表示する連絡先を決定します。しかし、アプリに両方の連絡先リストを同時に読み込みたい場合も多々あります。たとえば、個人用のデータ(写真、ドキュメント)を同僚と共有する場合などです。そのためには、両方の連絡先リストを取得する必要があります。

MainActivity.kt を開く

メソッド onCreateLoader() は、連絡先の取得と読み込みを行うカーソルローダを作成する役割を担います。現在、このメソッドはデフォルトの ContentURI を使用する CursorLoader のみを返します。このメソッドは 2 回呼び出します。1 回は個人用の連絡先のため、もう 1 回は仕事用の連絡先のためです。両者を区別できるように、それぞれの場合で別々の ID を onCreateLoader() に渡します。このメソッドで受け取る ID を確認して、使用する ContentURI を決定する必要があります。

まず、メソッドに渡される ID の値に応じて ContentURI 変数の値を変更します。PERSONAL_CONTACTS_LOADER_ID の場合は、デフォルトの ContactsContract.Contacts.CONTENT_URI を代入します。それ以外の場合は、こちらで説明されているように ENTERPRISE_CONTENT_FILTER_URI を構築します。

ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI
                    .buildUpon()
                    .appendPath(nameFilter)
                    .appendQueryParameter(
                        ContactsContract.DIRECTORY_PARAM_KEY,
                        ContactsContract.Directory.ENTERPRISE_DEFAULT.toString()
                    )
                    .build()

これはコンテンツ フィルタ URI であるため、ビルダーには連絡先の検索または読み込みを行うときに使用する検索フィルタ(検索フレーズ)が必要です。

差し当たり、検索フレーズをハードコードして文字「a」で始まる名前にしてください。

val nameFilter = Uri.encode("a") // names that start with a

検索する連絡先ディレクトリを指定する必要もあります。ENTERPRISE_DEFAULT ディレクトリを使用します。これを使用すると、デバイスにローカルに保存されている連絡先が検索されます。

onCreateLoader() メソッドは次のようになります。

override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> {
        val nameFilter = Uri.encode("a") // names that start with W
        val contentURI = when (id) {
            PERSONAL_CONTACTS_LOADER_ID -> ContactsContract.Contacts.CONTENT_URI
            else -> {
                ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI
                    .buildUpon()
                    .appendPath(nameFilter)
                    .appendQueryParameter(
                        ContactsContract.DIRECTORY_PARAM_KEY,
                        ContactsContract.Directory.ENTERPRISE_DEFAULT.toString()
                    )
                    .build()
            }
        }
        return CursorLoader(
            this, contentURI, arrayOf(
                ContactsContract.Contacts.DISPLAY_NAME_PRIMARY
            ), null, null, null
        )
    }

ここで、上記のメソッドをトリガーするために、新しい ID 値で別の Loader を初期化する必要があります。

まず、MainActivity の上部に仕事用の連絡先のための新しい定数の ID 値を作成します。

const val WORK_CONTACTS_LOADER_ID = 1

次に、initLoaders()LoaderManager を使用して、上記で作成した新しい ID で新しい Loader を初期化します。

private fun initLoaders() {
        LoaderManager.getInstance(this).
            initLoader(PERSONAL_CONTACTS_LOADER_ID, null, this)
        LoaderManager.getInstance(this).
            initLoader(WORK_CONTACTS_LOADER_ID, null, this)
    }

両方の Loader からのデータ Cursor の構造は同じであるため、他のすべてのメソッドでも同じように機能します。

試してみる

個人用プロファイルでアプリを実行すると、仕事用と個人用の両方の連絡先が表示されます。

f9779ab476511718.png 7e4846e179664d66.png

仕事用プロファイルの場合

仕事用プロファイルでアプリを実行すると、仕事用の連絡先のみが表示され、個人用の連絡先は表示されません。これは、仕事用プロファイルの主な目的がユーザーのプライバシーを保護することであるためで、仕事用アプリでは通常、個人用プロファイルの個人情報にアクセスできません。

9b7ddeec64957963.png

Android には、異なるプロファイルでアプリの別のインスタンスを起動するための API があるため、ユーザーがアカウントを切り替えやすくなっています。たとえば、メールアプリで、ユーザーが個人用プロファイルと仕事用プロファイルを切り替えて 2 つのメール アカウントにアクセスするための UI を用意できます。

すべてのアプリは、すでに他のプロファイルにインストールされていれば、これらの API を呼び出して、同じアプリのメイン アクティビティを起動できます。

クロスプロファイル アカウントの切り替えをアプリに追加するには、まず、メインのアクティビティ レイアウトにボタンを追加して、ユーザーがプロファイルを切り替えられるようにする必要があります。

activity_main.xml を開き、recycler-view ウィジェットの下にボタン ウィジェットを追加します。

<androidx.appcompat.widget.AppCompatButton
        android:id="@+id/button"
        app:layout_constraintTop_toBottomOf="@+id/contacts_rv"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

MainActivity.kt に戻り、プロファイルを切り替えるボタンのクリック イベントを設定します。

それには、まず CrossProfileApps システム サービスを取得します。

val crossProfileApps = getSystemService(CrossProfileApps::class.java)

このクラスは、プロファイル切り替えの機能を実装するのに必要なすべての API を提供します。このアプリがインストールされている他のプロファイルをすべて返す targetUserProfiles を呼び出すと、ユーザー プロファイルのリストを取得できます。

val userHandles = crossProfileApps.targetUserProfiles

返された userHandle の最初の項目を使用して、他のプロファイルでアプリを起動できるようになりました。

crossProfileApps.startMainActivity(
                    componentName,
                    userHandles.first()
                )

ユーザーにプロファイルの切り替えを促すローカライズ済みのテキストを取得し、それを使用してボタンのテキスト値を設定できます。

val label = crossProfileApps.getProfileSwitchingLabel(userHandles.first())

以上の要素をすべてまとめて、MainActivity.kt に以下のとおり追加します。

val crossProfileApps = getSystemService(CrossProfileApps::class.java)
        val userHandles = crossProfileApps.targetUserProfiles
        val label = crossProfileApps.getProfileSwitchingLabel(userHandles.first())
        button = findViewById<AppCompatButton>(R.id.button).apply {
            text = label
            setOnClickListener {
                crossProfileApps.startMainActivity(
                    componentName,
                    userHandles.first()
                )
            }
        }

試してみる

アプリを実行すると、どちらのプロファイルからアプリを起動したかに応じて、仕事用プロファイルまたは個人用プロファイルの切り替えができることを示すボタンが下部に表示されます。

このボタンをクリックすると、他方のプロファイルでアプリが開きます。

d904de4fdc0d091b.png 4835ce56fcf10ea1.png

個人用プロファイルと仕事用プロファイルの両方で動作するアプリの変更ができました。このアプリは、仕事用プロファイルがインストールされていることを認識して、個人用モードで動作していても仕事用の連絡先を取得します。

また、アプリの実行中に同じアプリの仕事用プロファイルと個人用プロファイルを切り替える手段も実装しました。アプリを閉じたり、該当するプロファイルから再起動したりする必要はありません。プロファイルごとにアプリの使い方が異なるユーザーにも対応することをおすすめします。

参考資料