アプリのパーミッションに関するおすすめの設定

パーミッション リクエストは、デバイスから入手できる機密情報を保護するための仕組みであり、そうした情報へのアクセスがアプリの機能に必要な場合にのみ行うべきものです。このドキュメントでは、機密情報にアクセスすることなく同等またはそれ以上の機能を実現するためのヒントを紹介します。このドキュメントは、Android オペレーティング システムにおけるパーミッションの仕組みについて包括的な説明を提供するものではありません。

Android パーミッションの概要については、パーミッションの概要をご覧ください。コードでパーミッションを処理する方法の詳細については、アプリのパーミッションをリクエストするをご覧ください。

Android パーミッションを扱う際の原則

Android パーミッションを扱う際は、次の原則に従うことをおすすめします。

#1: アプリの動作に必要なパーミッションのみを使用する。パーミッションの使用方法によっては、機密情報にアクセスすることなく、別の方法(システム インテント、識別子、通話時のバックグラウンド移行)で必要な処理を実行できる場合があります。

#2: ライブラリが必要とするパーミッションに注意する。ライブラリをインクルードすると、そのパーミッション要件も継承されます。インクルードするライブラリ、そのライブラリが必要とするパーミッション、そしてそのパーミッションの用途に注意を払う必要があります。

#3: 透明性を確保する。パーミッションをリクエストするときは、アクセス対象とアクセス理由を明確にし、ユーザーが十分な情報に基づいて判断できるようにする必要があります。インストール時、実行時、パーミッション更新時のダイアログなどで、そのような情報をパーミッション リクエストとともに表示してください。

#4: システム アクセスは明示的に行う。機密性の高い機能(カメラやマイクなど)にアクセスするときは継続的にその旨を表示し、いつデータを収集しているかをユーザーに明示して、データをひそかに収集しているという疑いを抱かせないようにします。

以下のセクションでは、Android アプリの開発時に上記のルールをどのように適用するかについて詳細に説明します。

Android 6.0 以上のパーミッション

Android 6.0(Marshmallow)において、インストール前ではなく実行時にアプリがユーザーにパーミッションをリクエストする新しいパーミッション モデルが導入されました。この新しいモデルをサポートするアプリは、サービスまたはサービスによって保護されるデータが実際に必要になった時点で、パーミッションをリクエストします。新しいモデルの導入により、必ずしもアプリの全体的な動作が変化するわけではありませんが、機密性の高いユーザーデータの取り扱いに関しては変更された部分があります。

コンテキストに応じたリクエストを促進: ユーザーは、アプリの実行中に、アプリのコンテキストに応じて、該当のパーミッション グループがカバーする機能にアクセスするパーミッションの付与を求められます。ユーザーはパーミッションがリクエストされるコンテキストを気にするので、リクエストするパーミッションとアプリの用途が一致しない場合は特に、そのパーミッションをリクエストする理由について詳細な説明をユーザーに提供することがきわめて重要です。リクエストする時点で、またユーザーがリクエストを拒否した場合はフォローアップ ダイアログで、可能な限りリクエストの理由を説明してください。

パーミッション付与の柔軟性が向上: ユーザーは、パーミッションがリクエストされた時点で、さらには設定を通じて、個々のパーミッションへのアクセスを拒否できますが、その結果としてアプリが正常に機能しなくなると困惑する可能性があります。Google アナリティクスなどでパーミッションの付与を拒否したユーザーの数を確認し、そのパーミッションを使用しないようにアプリをリファクタリングするか、アプリが正常に動作するためにパーミッションが必要な理由をユーザーによりわかりやすく説明することをおすすめします。また、ユーザーがパーミッション リクエストを拒否した場合や、設定でパーミッションをオフに切り替えた場合に生じる例外をアプリが処理できるようにすることも必要です。

トランザクションの負担が増大: ユーザーは、パーミッション グループへのアクセスを、一括ではなく個別に許可するよう求められます。このため、リクエストするパーミッションの数を最小限に抑えることがきわめて重要になります。この数が多いと、ユーザーがパーミッションを付与する負担が増大し、少なくとも 1 つのリクエストが拒否される確率が高くなります。

デフォルト ハンドラとしての設定に必要なパーミッション

アプリによっては、通話履歴や SMS メッセージに関するユーザーの機密情報にアクセスする必要があります。通話履歴や SMS メッセージに固有のパーミッションをリクエストするアプリを Play ストアに公開する場合は、ランタイム パーミッションをリクエストする前に、アプリを中核的システム機能のデフォルト ハンドラとして設定することをユーザーに求める必要があります。

デフォルト ハンドラの詳細(デフォルト ハンドラのプロンプトをユーザーに表示する方法など)については、デフォルト ハンドラでのみ使用されるパーミッションに関するガイドをご覧ください。

不要なパーミッションのリクエストを避ける

パーミッションを求められるたびに、ユーザーはどうするか判断する負担を強いられます。パーミッションをリクエストする回数は最小限に抑えてください。Android 6.0(API レベル 23)以降を実行している場合、ユーザーはパーミッションを必要とする新しいアプリ機能にアクセスするたびに、パーミッション リクエストで操作を中断することを余儀なくされます。6.0 より前のバージョンの Android を使用している場合、ユーザーはアプリのインストール時にアプリのすべてのパーミッションを個別に付与する必要があります。パーミッションのリストが長すぎる場合や、パーミッションの付与が適切でないと感じた場合は、アプリのインストール自体をやめてしまうかもしれません。上記の理由により、アプリが必要とするパーミッションの数は最小限に抑える必要があります。

以下のセクションでは、一般的なユースケースの代替手段として、パーミッション リクエストの数を抑えるために役立つ方法を紹介します。ユーザーに表示されるパーミッション リクエストの数とタイプはアプリのダウンロード数に影響し、リクエスト数が多いアプリはリクエスト数が少ない類似のアプリと比べて不利になります。したがって、不要な機能に対するパーミッション リクエストは避けることをおすすめします。

パーミッションの代わりにインテントを使用する

多くの場合、アプリがタスクを実行するには 2 つの方法があります。それは、タスクを実行するパーミッションをアプリ自身がリクエストする方法と、インテントを使用して別のアプリにタスクを実行させる方法です。

たとえば、デバイスのカメラを使用して写真を撮る機能がアプリに必要であるとします。この場合、アプリはカメラに直接アクセスするための CAMERA パーミッションをリクエストできます。アプリはカメラ API を使用してカメラの制御と写真の撮影を行います。この方法では、アプリが写真撮影プロセスを完全に制御できるため、アプリにカメラの UI を組み込むことができます。

一方、ユーザーデータへのアクセスが必要になる頻度が低い場合(つまり、データへのアクセスが必要になるたびに実行時ダイアログを表示してもそれほどユーザーの操作の邪魔にならない場合)は、インテント ベースのリクエストを使用できます。Android に用意されているいくつかのシステム インテントを使用すると、アプリからパーミッションをリクエストする必要がなくなります。これは、インテント ベースのリクエストが発行された時点で、アプリに何を許可するかを(許可するものがもしあれば)ユーザーが選択するためです。

たとえば、インテント アクション タイプとして MediaStore.ACTION_IMAGE_CAPTURE または MediaStore.ACTION_VIDEO_CAPTURE を使用すると、Camera オブジェクトを直接使用せずに(パーミッション リクエストなしで)画像または動画を撮影できます。この場合、画像を撮影するたびに、アプリに代わってシステム インテントがユーザーにパーミッションをリクエストします。

同様に、電話をかける処理やユーザーの連絡先にアクセスする処理が必要な場合も、適切なインテントを作成してそれらを処理できます。もちろん、パーミッションをリクエストして、該当オブジェクトに直接アクセスすることもできます。これら 2 つの方法には、それぞれ長所と短所があります。

パーミッションを使用する場合:

  • オペレーションを実行する際、アプリはユーザー エクスペリエンスを完全に制御します。しかし、このような広範な制御を行うには適切な UI を設計する必要があるため、コードが複雑になります。
  • ユーザーの Android バージョンに応じて、実行時またはインストール時に 1 回、ユーザーはパーミッションの付与を求められます。その後は、ユーザーに追加の操作を求めることなく、アプリはオペレーションを実行できます。ただし、ユーザーがパーミッションを付与しなかった場合(または、後で取り消した場合)、アプリはそのオペレーションを一切実行できなくなります。

インテントを使用する場合:

  • オペレーション用の UI の設計は不要です。UI は、インテントを処理するアプリが提供します。
  • ユーザーは自分が望むアプリを使用してタスクを実行できます。たとえば、お気に入りの写真アプリを選択して写真を撮影できます。
  • ユーザーがオペレーション用のデフォルトのアプリを持っていない場合、ユーザーはアプリの選択を求められます。ユーザーがデフォルト ハンドラを指定しないと、オペレーションを実行するたびに追加のダイアログが表示されます。

ユーザーに負担を与えない

ユーザーが Android 6.0(API レベル 23)以降を実行している場合、ユーザーはアプリの実行中にアプリにパーミッションを付与する必要があります。一度に多数のパーミッション リクエストをユーザーに提示すると、ユーザーは負担を感じてアプリの使用をやめる可能性があります。これを避けるため、必要なパーミッションのみをリクエストしてください。

アプリに 1 つ以上のパーミッションが不可欠な場合があります。この場合は、アプリが起動された直後にそれらのパーミッションをすべてリクエストする方法が適切です。たとえば、写真アプリを作成する場合、そのアプリはデバイスのカメラにアクセスする必要があります。アプリを初めて起動するときにカメラを使用するパーミッションを求められてもユーザーは驚きません。 しかし、このアプリに、ユーザーの連絡先に登録されている人々と写真を共有する機能が含まれている場合、初回起動時に READ_CONTACTS パーミッションをリクエストするのは不適切です。ユーザーが「共有」機能を使用したときに初めて、このパーミッションをリクエストするようにしてください。

アプリにチュートリアルを用意している場合は、チュートリアル シーケンスの最後で、アプリに不可欠なパーミッションをリクエストすることをおすすめします。

音声フォーカスを失ったときにメディアを一時停止する

場合によっては、アプリはユーザーに電話がかかってきたらバックグラウンドに移行し、通話が終了したらフォーカスを取り戻す必要があります。

このようなケース(たとえば通話中にメディア プレーヤーがミュートや一時停止を行う場合)の一般的な解決策は、PhoneStateListener を使用するか、または android.intent.action.PHONE_STATE のブロードキャストをリッスンして、通話状態の変化をリッスンすることです。この解決策の問題点は、READ_PHONE_STATE パーミッションが必要になることです。つまり、ユーザーは、デバイス、SIM ハードウェア ID、着信の電話番号など、多岐にわたる機密データへのアクセスを許可することを強いられます。さらに、Android 10(API レベル 29)以上でアプリが実行されている場合は、LISTEN_CELL_LOCATION イベントと LISTEN_CELL_INFO イベントで位置情報のパーミッションが必要になります(特にアプリが Android 10 以上をターゲットにしている場合は ACCESS_FINE_LOCATION が必要になります)。

ユーザーが通話中かどうかは、READ_PHONE_STATE パーミッションまたは MODIFY_PHONE_STATE パーミッションがなくても、(機密情報にアクセスしないので)明示的なパーミッションを必要としない AudioFocus をアプリ用にリクエストすることで検出できます。これは、アプリのオーディオをバックグラウンドに移行するために必要なコードを onAudioFocusChange() イベント ハンドラに配置するだけで実現できます。このコードは、OS により音声フォーカスがシフトされると、自動的に実行されます。この方法の詳細については、こちらをご覧ください。

インスタンスが稼働しているデバイスを判別する

アプリのインスタンスが動作しているデバイスを判別するために一意の ID が必要になることがあります。

たとえば、ユーザーが自動車と自宅で別々のプレイリストを利用できるように、デバイス別のプレイリストをクラウドに保存している場合のように、アプリがデバイス固有の設定やメッセージを使用するケースがあります。一般的な解決策は Device IMEI などのデバイス ID を利用することですが、これには Device ID and call information パーミッション グループ(Android M 以上では PHONE)が必要です。また、この方法では、すべてのアプリ間で共有されるリセット不可能な ID を使用することになります。

このタイプの ID の代わりに使用できる方法は 2 つあります。

  1. com.google.android.gms.iid InstanceID API を使用します。 getInstance(Context context).getID() は、アプリ インスタンス用の一意のデバイス ID を返します。返される ID はアプリ インスタンスをスコープとし、アプリに関する情報を保存する際にキーとして使用することが可能です。この ID は、ユーザーがアプリを再インストールするとリセットされます。
  2. randomUUID() などの基本的なシステム機能を使用して、アプリのストレージをスコープとする独自の ID を作成できます。

広告やユーザー分析用の一意の ID を作成する

広告のターゲティングやコンバージョンの測定などの目的で、アプリにログインしていないユーザーのプロファイルを作成するために、一意の ID が必要になるケースがあります。

広告やユーザー分析用にプロファイルを作成する際に、他のアプリと共有できる ID が必要になるケースもあります。一般的な解決策は Device IMEI などのデバイス ID を利用することですが、これには Device ID and call information パーミッション グループ(API レベル 23 以上では PHONE)が必要です。また、ユーザーはこの ID をリセットできません。この場合、リセット不可能な ID を使用し、ユーザーが不自然に感じるであろうパーミッションをリクエストすることになります。さらに、Google Play のデベロッパー プログラム ポリシーにも違反します。

残念ながら、このケースでは、com.google.android.gms.iid InstanceID API またはシステム機能を使用して、アプリをスコープとする ID を作成する解決策は適切ではありません。アプリ間で ID を共有することが必要になる可能性があるからです。別の解決策は、 AdvertisingIdClient.Info クラスから getId() メソッドを介して利用できる Advertising Identifier を使用することです。この識別子を使用するには、getAdvertisingIdInfo(Context) メソッドで AdvertisingIdClient.Info オブジェクトを作成し、getId() メソッドを呼び出します。なお、このメソッドはブロッキング メソッドであるため、メインスレッドから呼び出してはなりません。このメソッドの詳細については、こちらをご覧ください。

使用するライブラリをよく調べる

アプリ内で使用するライブラリにパーミッションが必要なケースはよくあります。たとえば、広告や分析用のライブラリは、必要な機能を実装するために LOCATION パーミッション グループへのアクセスを必要とする場合があります。ただし、ユーザーの観点からすると、パーミッションをリクエストしているのはアプリであって、ライブラリではありません。

ユーザーは、機能が同じであれば、使用するパーミッションが少ないアプリを選択します。それと同様に、デベロッパーはライブラリを調査して、不要なパーミッションを使用していないサードパーティ SDK を選択する必要があります。たとえば、位置情報機能を提供するライブラリを使用する場合、位置情報ベースのターゲティング機能を使用するのでなければ、FINE_LOCATION パーミッションをリクエストしないようにします。

位置情報へのバックグラウンド アクセスを制限する

アプリがバックグラウンドで実行されている場合、アプリの中核的機能にとって不可欠な位置情報へのアクセスのみを実行し、その明確なメリットをユーザーに示す必要があります。

パーミッションが必要な理由を説明する

requestPermissions() を呼び出したときにシステムが表示するパーミッション ダイアログでは、アプリが必要とするパーミッションは示されますが、その理由は示されません。そのため、ユーザーが困惑する可能性があります。requestPermissions() を呼び出す前に、アプリがパーミッションを必要とする理由をユーザーに説明することをおすすめします。

調査によると、ユーザーはアプリがパーミッションを必要とする理由を知ると、パーミッション リクエストを快く受け入れる確率が高くなることが判明しています。あるユーザー調査は、次のように指摘しています。

...ユーザーが特定のパーミッションを特定のモバイルアプリに付与するかどうかは、そのパーミッションに関連付けられている目的に大きく左右されます。たとえば、ユーザーが位置情報へのアクセスを快く許可するかどうかは、アプリの中核的機能を実現するためにそのパーミッションが必要なのか、それとも広告掲載ネットワークや分析会社に位置情報を提供することが目的なのかによって変わります。1

カーネギー メロン大学の Jason Hong 教授は、研究チームの調査結果に基づいて次のように述べています。

...アプリが位置情報のような機密情報を使用する理由がわかっている場合、たとえばターゲット広告の場合は、単にアプリが位置情報を使用していることを知らされた場合よりも、ユーザーの安心感は高まります。1

したがって、あるパーミッション グループに含まれる一部の API 呼び出しだけを使用する場合は、使用するパーミッションとそのパーミッションを使用する理由を明示的にリストすることをおすすめします。例:

  • 低精度の位置情報だけを使用する場合は、その点について、アプリの説明やアプリに関するヘルプ記事でユーザーに知らせます。
  • 不正行為からユーザーを保護する認証コードを取得するために SMS メッセージにアクセスする必要がある場合は、その旨をアプリの説明に記載するか、または(それとともに)アプリがデータに初めてアクセスするときにユーザーに知らせます。

    注: アプリが Android 8.0(API レベル 26)以上をターゲットにしている場合は、ユーザーの認証情報を検証するプロセス内で READ_SMS パーミッションをリクエストしないでください。代わりに、createAppSpecificSmsToken() を使用してアプリ固有のトークンを生成し、確認済み SMS メッセージを送信できる別のアプリまたはサービスにそのトークンを渡してください。

状況によっては、機密データへのアクセスをリアルタイムでユーザーに知らせることも有益です。たとえば、カメラやマイクにアクセスする場合、一般的な方法として、アプリ内または(アプリがバックグラウンドで稼働している場合は)通知トレイ内に通知アイコンを表示してユーザーに知らせることで、データをひそかに収集していると思われないようにします。

最後に、アプリのなんらかの機能のためにパーミッションをリクエストする必要があるにもかかわらず、その理由をユーザーに明確に説明できない場合は、最も機密性の高いパーミッションを必要とする理由をユーザーに知らせる方法を見つけてください。

2 つのパーミッション モデルをテストする

Android 6.0(API レベル 23)以降、ユーザーはアプリのインストール時ではなくアプリの実行時に、パーミッションの付与または取り消しを行うようになりました。そのため、さまざまな条件下でアプリをテストする必要があります。Android 6.0 より前のバージョンでは、アプリが実行されていれば、アプリ マニフェスト内で宣言したすべてのパーミッションが付与されていると見なすことができました。Android 6.0 以降では、ユーザーは、すべてのアプリで(API レベル 22 以下をターゲットとするアプリでさえ)パーミッションのオン / オフを切り替えることができます。パーミッションの付与状況にかかわらず、アプリが正常に機能するかテストする必要があります。

API レベル 23 以上を実行しているデバイスで、パーミッションに関連するコードの問題を検出するためのヒントを以下に示します。

  • アプリの現在のパーミッションと、関連するコードパスを確認します。
  • パーミッションで保護されているサービスとデータにかかわるユーザーフローをテストします。
  • 付与されたパーミッションまたは取り消されたパーミッションのさまざまな組み合わせをテストします。たとえば、カメラアプリのマニフェストに CAMERAREAD_CONTACTSACCESS_FINE_LOCATION がリストされているとします。各パーミッションのオン / オフを切り替えてアプリをテストし、すべてのパーミッション構成をアプリが適切に処理できるかどうかを確認します。
  • コマンドラインからパーミッションを管理するには、adb ツールを使用します。
    • グループごとにパーミッションとステータスをリストするには、次のコマンドを使用します。
      $ adb shell pm list permissions -d -g
    • 1 つまたは複数のパーミッションの付与または取り消しを行うには、次のコマンドを使用します。
      $ adb shell pm [grant|revoke] <permission-name> ...
  • アプリを分析して、パーミッションを使用しているサービスを調べます。

参考情報

出典

[1] Modeling Users' Mobile App Privacy Preferences: Restoring Usability in a Sea of Permission Settings(J. Lin、B. Liu、N. Sadeh、J. Hong 著。 SOUPS 2014 紀要)