Register now for Android Dev Summit 2019!

アプリの権限に関するおすすめの設定

権限リクエストは、デバイスで利用可能な機密情報を保護するためのものであるため、情報へのアクセスがアプリの動作に必要な場合にのみ行ってください。このドキュメントでは、こうした機密情報にアクセスせずに、同等またはそれ以上の機能を実現するための方法について説明します(Android オペレーティング システムでの権限の動作についての包括的な説明ではありません)。

Android の権限の概要については、権限の概要についての説明をご覧ください。コードでの権限の扱い方について詳しくは、アプリの権限をリクエストする方法についての説明をご覧ください。

Android の権限を扱うときの原則

Android の権限を扱うときは、次の原則に従うことをおすすめします。

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

#2: ライブラリが必要とする権限には注意する。 ライブラリを追加すると、そのライブラリが必要とする権限も継承します。追加する要素、その要素が必要とする権限、その権限の用途には注意する必要があります。

#3: 透明性を確保する。 権限をリクエストするときは、アクセスする対象とアクセスの理由を明確にし、ユーザーが十分な情報に基づいて判断できるようにする必要があります。インストール、ランタイム、更新の権限ダイアログを含め、権限のリクエストとともにこの情報を表示してください。

#4: システム アクセスを明示的にする。 機密性の高い機能(カメラ、マイクなど)にアクセスするときは、通知を継続して表示することにより、データを収集するタイミングをユーザーに明確に示して、データをひそかに収集しているという疑いをもたれないようにします。

このガイドの残りのセクションでは、Android アプリの開発における、これらのルールについて解説します。

Android 6.0 以降の権限

Android 6.0 Marshmallow では、アプリがユーザーに対する権限リクエストをインストール前ではなく、ランタイムに実行できる新しい権限モデルが導入されました。この新しいモデルをサポートするアプリは、サービスやサービスによって保護されるデータが実際に必要になったときに権限をリクエストします。これでアプリの全体的な動作が必ずしも変わるわけではありませんが、機密性の高いユーザーデータの取り扱いに関する操作には変化が生じます。

状況に応じた説明の機会が増加: ユーザーには、アプリの実行中に、アプリの中で、こうした権限グループの対象となる機能へのアクセス許可を求めるメッセージが表示されます。ユーザーは権限がリクエストされる状況に強く反応するため、リクエストする権限とアプリの用途が一致しない場合には、その権限をリクエストしている理由についての詳細な説明をユーザーに提供することがさらに重要になります。可能な限り、リクエストの時点で、またユーザーがリクエストを拒否した場合はフォローアップ ダイアログで、リクエストする理由を説明してください。

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

トランザクション側の負担が増大: ユーザーには、一括ではなく、個々に権限グループのアクセス許可を求めます。このため、リクエストする権限の数を最小限に抑えることが非常に重要となります。ユーザーが権限を付与する場合の負担が増え、リクエストが拒否される可能性が高くなります。

不要な権限のリクエストを避ける

権限を求めるたびに、ユーザーに決断する負担を強いるため、権限リクエストの回数は最小限に抑えてください。ユーザーが Android 6.0(API レベル 23)以降を使用している場合は、権限を必要とする新しいアプリ機能をユーザーが試すたびに、アプリは権限リクエストによってユーザーの作業を中断する必要があります。それ以前のバージョンの Android を使用している場合、ユーザーはアプリのインストール時にアプリの権限をすべて付与する必要があります。リストが長すぎたり、不適切に見えたりすると、ユーザーはアプリをインストールしない可能性があります。これらの理由から、アプリが必要とする権限の数は最小限にしてください。

次に、権限リクエストの数を制限することに役立つ、一般的なユースケースに代わる選択肢について説明します。権限のリクエストが少ない他の類似したアプリと比べ、ユーザーにリクエストする権限の数とタイプはダウンロード数に影響するため、不要な機能の権限のリクエストは避けることをおすすめします。

代わりにインテントを使用する

多くの場合、アプリがタスクを実行する方法には 2 つの選択肢があります。アプリ自身がタスクを実行する権限を求める方法と、インテントを使用して別のアプリにタスクを実行してもらう方法です。

たとえば、デバイスのカメラを使って写真を撮る機能がアプリに必要だとします。アプリは CAMERA 権限をリクエストできます。この権限を使ってアプリはカメラに直接アクセスします。アプリはカメラの API を使ってカメラの操作や写真の撮影を行います。この方法では、アプリで写真撮影のプロセスを完全に制御できるため、アプリにカメラの UI を組み込むことができます。

ただし、ユーザーデータへのアクセスを求める頻度が低い場合、つまりデータへのアクセスが必要になるたびにユーザーにランタイム ダイアログを表示することが許容範囲内の場合は、インテント ベースのリクエストを使用できます。Android に用意されているシステム インテントをアプリが使用した場合、インテント ベースのリクエストの発行時にユーザーはアプリと共有する要素(存在する場合)を選択するため、アプリは権限を求める必要がありません。

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

同様に、電話をかける、ユーザーの連絡先にアクセスするなどの操作が必要な場合も、適切なインテントを作成してその操作を行うことができます。また、権限を要求して適切なオブジェクトに直接アクセスすることもできます。各方法には長所と短所があります。

権限を使用する場合:

  • 操作を実行する際にアプリがユーザー エクスペリエンスを完全に制御します。ただし、このような幅広い制御を行うには適切な UI を設計する必要があるため、コードが複雑化します。
  • 実行時またはインストール時のいずれか(ユーザーの Android バージョンによって異なります)に 1 回、ユーザーに権限の付与を求めるメッセージが表示されます。その後は、ユーザーにさらに許可を求めることなくアプリは操作を実行できます。ただし、ユーザーが権限を付与しなかった場合(または後で権限を取り消した場合)、アプリは操作を一切実行できなくなります。

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

  • 操作用の UI を設計する必要はありません。インテントを処理するアプリが UI を提供します。
  • ユーザーはタスクに自分が希望するアプリを使用できます。たとえば、お気に入りの写真アプリを選択して写真を撮影できます。
  • 操作に対するデフォルトのアプリがないユーザーには、アプリの選択を求めるメッセージが表示されます。ユーザーがデフォルトのアプリを指定しないと、操作のたびに選択ダイアログが表示される可能性があります。

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

Android 6.0(API レベル 23)以降を使用しているユーザーは、アプリの実行中にアプリに権限を付与する必要があります。ユーザーは一度に多くの権限をリクエストされると、負担を感じてアプリを終了してしまう場合があります。ユーザーには必要な権限のみを要求してください。

アプリによっては 1 つ以上の権限が必須である場合もあります。その場合は、アプリの起動後すぐにすべての権限を要求するのが合理的です。たとえば、写真アプリを作成する場合、そのアプリはデバイスのカメラにアクセスする必要があります。ユーザーはアプリを初めて起動するときにカメラを使用する権限を求められても驚きません。ただし、ユーザーの連絡先と写真を共有する機能もある場合は、最初の起動時に READ_CONTACTS 権限を求めず、ユーザーが「共有」機能を使ったときに初めて求めるようにしてください。

アプリにチュートリアルが含まれる場合は、チュートリアルのシーケンスの最後でアプリに必須の権限を要求する方が合理的です。

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

この場合は、ユーザーに電話がかかってきたときにアプリはバックグラウンドに移行し、通話が終了した後でのみリフォーカスする必要があります。

たとえば、通話中にメディア プレーヤーをミュートしたり一時停止したりする場合は一般的に、PhoneStateListener を使用して通話の状態の変化を確認するか、android.intent.action.PHONE_STATE のブロードキャストを確認します。この解決方法の問題点は、READ_PHONE_STATE 権限が必要になることです。ユーザーは、デバイスや SIM ハードウェアの ID、着信した電話番号など、機密性の高いさまざまなデータへのアクセス権を付与する必要があります。

ユーザーが通話中かどうかは、READ_PHONE_STATE 権限や MODIFY_PHONE_STATE 権限がなくても、明示的な権限を必要としない(機密情報にアクセスしないため)AudioFocus を要求することで検出できます。必要なのは、オーディオをバックラウンドにするために必要なコードを onAudioFocusChange() イベントハンドラに追加することのみです。OS が音声フォーカスをシフトすると、このコードが自動的に実行されます。この方法について詳しくは、こちらをご覧ください。

インスタンスが実行されているデバイスを判別する

この場合は、アプリのインスタンスが実行されているデバイスを判別するために一意の識別子が必要になります。

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

これらのタイプの識別子の代わりとなる方法が 2 つあります。

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

広告またはユーザー分析用の一意の識別子を作成する

この場合は、アプリにログインしていないユーザーのプロファイルを作成するために(たとえば、広告のターゲティングやコンバージョンの測定などのために)一意の識別子が必要になります。

広告やユーザー分析のためにプロファイルを作成する場合は、他のアプリの間で共有される識別子が必要になることがあります。一般的な解決策は、Device IMEI などのデバイス識別子を利用することですが、これには Device IDand call information 権限グループ(API レベル 23 以降では PHONE)が必要となります。また、この識別子をユーザーがリセットすることはできません。いずれの場合も、リセット不可の識別子を使用したり、ユーザーには不自然に思える可能性がある権限をリクエストしたりすることに加え、Play デベロッパー プログラム ポリシーに違反することになります。

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

使用するライブラリを把握する

アプリで使用するライブラリに権限が必要となることがあります。たとえば、広告と分析のライブラリは、必要な機能を実装するために Location 権限グループや Identity 権限グループへのアクセスを必要とする場合があります。ただし、ユーザー側から見ると、権限をリクエストしているのはアプリであって、ライブラリではありません。

同じ機能に対してより少ない権限を使用するアプリをユーザーが選択する場合と同じように、デベロッパーは、ライブラリを確認し、不要な権限を使用しないサードパーティの SDK を選択する必要があります。たとえば、アプリが権限を必要とする明確なユーザー向けの理由がない限り、Identity 権限グループを必要とするライブラリは使用しないようにしてください。特に、位置情報機能を提供するライブラリでは、位置情報ベースのターゲット機能を使用している場合を除き、FINE_LOCATION 権限をリクエストする必要はありません。

権限が必要な理由を説明する

requestPermissions() を呼び出したときに表示される権限ダイアログには、アプリが必要とする権限は表示されますが、その理由は表示されないため、ユーザーが困惑することがあります。requestPermissions() を呼び出す前に、アプリがその権限を必要とする理由をユーザーに説明することをおすすめします。

調査によると、ユーザーはアプリに権限が必要な理由を知っていると、権限リクエストを快く受け入れるようになることがわかっています。あるユーザー調査では、次の点が指摘されています。

...ユーザーが特定の権限を特定のモバイルアプリに付与するかどうかは、その権限に関連付けられている目的に大きく左右されます。たとえば、ユーザーが自分の位置情報へのアクセスを付与するかどうかは、アプリの中核機能をサポートするためにリクエストが要求されているのか、広告ネットワークや分析会社とこの情報を共有するためにリクエストが要求されているかどうかによって異なります。1

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

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

そのため、権限グループに属する API 呼び出しの一部のみを使用している場合は、使用する権限とその権限を使用する理由の明示的なリストを作成することをおすすめします。次に例を示します。

  • 低精度の位置情報のみを使用している場合は、これについて、アプリの説明またはアプリに関するヘルプ記事でユーザーに知らせます。
  • SMS メッセージを利用して、不正使用からユーザーを保護する認証コードを取得する必要がある場合は、これについて、アプリの説明で、またはデータに最初にアクセスする時点でユーザーに知らせます。

    注: アプリが Android 8.0(API レベル 26)以上を対象としている場合は、ユーザーの認証情報を確認する一環として READ_SMS 権限をリクエストしないでください。代わりに、createAppSpecificSmsToken() を使用してアプリ固有のトークンを生成し、確認の SMS メッセージを送信できる別のアプリまたはサービスにこのトークンを渡します。

特定の状況では、機密性の高いデータへのアクセスをリアルタイムでユーザーに知らせることもおすすめします。たとえば、カメラやマイクにアクセスする場合は、通常、アプリ内の任意の場所に表示される通知アイコンまたは通知トレイ(アプリがバックグラウンドで実行されている場合)を使ってユーザーに知らせることにより、データをひそかに収集しているわけではないことを示すことをおすすめします。

最後に、アプリの機能を動作させるために権限をリクエストする必要があるが、その理由がユーザーに明確ではない場合は、最も機密性の高い権限を必要とする理由をユーザーに知らせる方法を探してください。

両方の権限モデルでテストする

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 の紀要。