Xamarin.Android でのアクセス許可

概要

Android アプリケーションは、独自のサンドボックスで実行され、セキュリティ上の理由から、デバイス上の特定のシステム リソースまたはハードウェアにアクセスできません。 ユーザーは、これらのリソースを使用する前に、アプリにアクセス許可を明示的に付与する必要があります。 たとえば、アプリケーションは、ユーザーからの明示的なアクセス許可なしでは、デバイス上の GPS にアクセスできません。 アプリがアクセス許可なしで保護されたリソースにアクセスしようとすると、Android は を Java.Lang.SecurityException スローします。

アクセス許可は、アプリの開発時にアプリケーション開発者によって AndroidManifest.xml で宣言されます。 Android には、これらのアクセス許可に対するユーザーの同意を取得するための 2 つの異なるワークフローがあります。

  • Android 5.1 (API レベル 22) 以下を対象とするアプリの場合、アプリのインストール時にアクセス許可要求が発生しました。 ユーザーがアクセス許可を付与しなかった場合、アプリはインストールされません。 アプリがインストールされると、アプリをアンインストールする以外にアクセス許可を取り消す方法はありません。
  • Android 6.0 (API レベル 23) 以降、ユーザーはアクセス許可をより詳細に制御することができました。アプリがデバイスにインストールされている限り、アクセス許可を付与または取り消すことができます。 このスクリーンショットは、Google 連絡先アプリのアクセス許可設定を示しています。 さまざまなアクセス許可が一覧表示され、ユーザーはアクセス許可を有効または無効にできます。

[アクセス許可のサンプル] 画面

Android アプリは、実行時にチェックして、保護されたリソースにアクセスするアクセス許可があるかどうかを確認する必要があります。 アプリにアクセス許可がない場合は、ユーザーがアクセス許可を付与するために Android SDK によって提供される新しい API を使用して要求を行う必要があります。 アクセス許可は、次の 2 つのカテゴリに分かれています。

  • 通常のアクセス許可 – これらは、ユーザーのセキュリティまたはプライバシーに対するセキュリティ リスクがほとんどないアクセス許可です。 Android 6.0 では、インストール時に通常のアクセス許可が自動的に付与されます。 通常のアクセス許可の完全な一覧については、Android のドキュメントを参照してください。
  • 危険なアクセス許可 – 通常のアクセス許可とは対照的に、危険なアクセス許可はユーザーのセキュリティまたはプライバシーを保護するアクセス許可です。 これらは、ユーザーが明示的に付与する必要があります。 SMS メッセージの送受信は、危険なアクセス許可を必要とするアクションの例です。

重要

アクセス許可が属するカテゴリは、時間の経過と同時に変更される可能性があります。 "通常の" アクセス許可として分類されたアクセス許可が、将来の API レベルで危険なアクセス許可に昇格される可能性があります。

危険なアクセス許可は、さらに 権限グループに分割されます。 アクセス許可グループには、論理的に関連するアクセス許可が保持されます。 ユーザーがアクセス許可グループの 1 人のメンバーにアクセス許可を付与すると、Android はそのグループのすべてのメンバーにアクセス許可を自動的に付与します。 たとえば、アクセス許可グループには STORAGEREAD_EXTERNAL_STORAGE の両方のアクセス許可がWRITE_EXTERNAL_STORAGE保持されます。 ユーザーが にアクセス許可を READ_EXTERNAL_STORAGE付与すると、 WRITE_EXTERNAL_STORAGE アクセス許可が自動的に同時に付与されます。

1 つ以上のアクセス許可を要求する前に、アクセス許可を要求する前に、アプリがアクセス許可を必要とする理由に関する根拠を提供することをお勧めします。 ユーザーが根拠を理解したら、アプリはユーザーにアクセス許可を要求できます。 その根拠を理解することで、ユーザーはアクセス許可を付与する場合は情報に基づいた意思決定を行い、許可しない場合は反論を理解できます。

アクセス許可の確認と要求のワークフロー全体は、実行時のアクセス許可チェックと呼ばれ、次の図にまとめることができます。

フロー チャートチェック実行時のアクセス許可

Android サポート ライブラリは、古いバージョンの Android へのアクセス許可に関する新しい API の一部をバックポートします。 これらのバックポートされた API は、デバイス上の Android のバージョンを自動的にチェックするため、毎回 API レベルチェックを実行する必要はありません。

このドキュメントでは、Xamarin.Android アプリケーションにアクセス許可を追加する方法と、Android 6.0 (API レベル 23) 以降を対象とするアプリが実行時アクセス許可チェックを実行する方法について説明します。

注意

ハードウェアのアクセス許可が、アプリを Google Play でフィルター処理する方法に影響する可能性があります。 たとえば、アプリにカメラのアクセス許可が必要な場合、Google Play は、カメラがインストールされていないデバイスの Google Play ストアにアプリを表示しません。

必要条件

Xamarin.Android プロジェクトには、 Xamarin.Android.Support.Compat NuGet パッケージが含まれることを強くお勧めします。 このパッケージは、アクセス許可固有の API を古いバージョンの Android にバックポートし、アプリが実行されている Android のバージョンを常にチェックすることなく、1 つの共通インターフェイスを提供します。

システムのアクセス許可の要求

Android のアクセス許可を操作する最初の手順は、Android マニフェスト ファイルでアクセス許可を宣言することです。 これは、アプリがターゲットとする API レベルに関係なく行う必要があります。

Android 6.0 以降を対象とするアプリでは、ユーザーが過去のある時点でアクセス許可を付与したため、そのアクセス許可が次回有効になると想定することはできません。 Android 6.0 を対象とするアプリでは、常にランタイムアクセス許可チェックを実行する必要があります。 Android 5.1 以下を対象とするアプリでは、実行時のアクセス許可チェックを実行する必要はありません。

注意

アプリケーションは、必要なアクセス許可のみを要求する必要があります。

マニフェストでのアクセス許可の宣言

アクセス許可は、 要素を 使用してAndroidManifest.xmluses-permission 追加されます。 たとえば、アプリケーションがデバイスの位置を特定する場合は、細かい場所とコースの場所のアクセス許可が必要です。 マニフェストには、次の 2 つの要素が追加されます。

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

Visual Studio に組み込まれているツール サポートを使用して、アクセス許可を宣言できます。

  1. ソリューション エクスプローラーの [プロパティ] をダブルクリックし、プロパティ ウィンドウの [Android マニフェスト] タブを選択します。

    [Android マニフェスト] タブで必要なアクセス許可

  2. アプリケーションにまだAndroidManifest.xmlがない場合は、[いいえ] をクリック AndroidManifest.xml見つかりました。次に示すように、クリックして追加 します。

    AndroidManifest.xml メッセージなし

  3. [必要なアクセス許可] の一覧からアプリケーションに必要 なアクセス許可 を選択し、保存します。

    選択された CAMERA 権限の例

Xamarin.Android では、ビルド時にいくつかのアクセス許可がデバッグ ビルドに自動的に追加されます。 これにより、アプリケーションのデバッグが容易になります。 特に、 と READ_EXTERNAL_STORAGEの 2 つの重要なアクセス許可がありますINTERNET。 これらの自動的に設定されたアクセス許可は、[ 必要なアクセス許可 ] の一覧では有効になっていません。 ただし、リリース ビルドでは、[必要なアクセス許可] の一覧で明示的に設定されている アクセス許可 のみを使用します。

Android 5.1 (API レベル 22) 以下を対象とするアプリの場合は、これ以上行う必要はありません。 Android 6.0 (API 23 レベル 23) 以降で実行されるアプリは、実行時のアクセス許可チェックを実行する方法に関する次のセクションに進む必要があります。

Android 6.0 でのランタイム アクセス許可チェック

ContextCompat.CheckSelfPermissionメソッド (Android サポート ライブラリで使用可能) は、特定のアクセス許可が付与されている場合にチェックするために使用されます。 このメソッドは、次の Android.Content.PM.Permission 2 つの値のいずれかを持つ列挙型を返します。

  • Permission.Granted – 指定されたアクセス許可が付与されています。
  • Permission.Denied – 指定されたアクセス許可が付与されていません。

このコード スニペットは、アクティビティの Camera アクセス許可をチェックする方法の例です。

if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.Camera) == (int)Permission.Granted) 
{
    // We have permission, go ahead and use the camera.
} 
else 
{
    // Camera permission is not granted. If necessary display rationale & request.
}

アプリケーションにアクセス許可が必要な理由をユーザーに通知して、アクセス許可を付与するための情報に基づいた決定を行えるようにすることをお勧めします。 この例としては、写真と geo タグを取るアプリがあります。 カメラのアクセス許可が必要であることはユーザーには明らかですが、アプリでデバイスの場所も必要な理由は明らかではない可能性があります。 理由は、場所のアクセス許可が望ましい理由と、カメラのアクセス許可が必要であることをユーザーが理解するのに役立つメッセージを表示する必要があります。

メソッドは ActivityCompat.ShouldShowRequestPermissionRationale 、ユーザーに根拠を表示する必要があるかどうかを判断するために使用されます。 特定のアクセス許可の根拠を表示する必要がある場合、このメソッドは を返 true します。 このスクリーンショットは、アプリがデバイスの場所を知る必要がある理由を説明する、アプリケーションによって表示される Snackbar の例を示しています。

場所の根拠

ユーザーがアクセス許可を付与する場合は、 メソッドを ActivityCompat.RequestPermissions(Activity activity, string[] permissions, int requestCode) 呼び出す必要があります。 このメソッドには、次のパラメーターが必要です。

  • activity – これは、アクセス許可を要求し、結果を Android から通知されるアクティビティです。
  • permissions – 要求されているアクセス許可の一覧。
  • requestCode – アクセス許可要求 RequestPermissions の結果を呼び出しに一致させるために使用される整数値。 この値は、ゼロより大きい値である必要があります。

このコード スニペットは、説明した 2 つのメソッドの例です。 まず、アクセス許可の根拠を表示する必要があるかどうかを判断するチェックが作成されます。 根拠を表示する場合は、その根拠と共に Snackbar が表示されます。 ユーザーが Snack バーで [OK] を クリックすると、アプリはアクセス許可を要求します。 ユーザーが根拠を受け入れない場合、アプリはアクセス許可の要求に進むべきではありません。 根拠が表示されない場合、アクティビティはアクセス許可を要求します。

if (ActivityCompat.ShouldShowRequestPermissionRationale(this, Manifest.Permission.AccessFineLocation)) 
{
    // Provide an additional rationale to the user if the permission was not granted
    // and the user would benefit from additional context for the use of the permission.
    // For example if the user has previously denied the permission.
    Log.Info(TAG, "Displaying camera permission rationale to provide additional context.");

    var requiredPermissions = new String[] { Manifest.Permission.AccessFineLocation };
    Snackbar.Make(layout, 
                   Resource.String.permission_location_rationale,
                   Snackbar.LengthIndefinite)
            .SetAction(Resource.String.ok, 
                       new Action<View>(delegate(View obj) {
                           ActivityCompat.RequestPermissions(this, requiredPermissions, REQUEST_LOCATION);
                       }    
            )
    ).Show();
}
else 
{
    ActivityCompat.RequestPermissions(this, new String[] { Manifest.Permission.Camera }, REQUEST_LOCATION);
}

RequestPermission は、ユーザーが既にアクセス許可を付与している場合でも呼び出すことができます。 後続の呼び出しは必要ありませんが、アクセス許可を確認 (または取り消す) 機会をユーザーに提供します。 が呼び出されると RequestPermission 、コントロールはオペレーティング システムに渡され、アクセス許可を受け入れるための UI が表示されます。

[Permssion] ダイアログ

ユーザーが完了すると、Android はコールバック メソッド OnRequestPermissionResultを使用して結果を Activity に返します。 このメソッドは、アクティビティによって実装される必要があるインターフェイス ActivityCompat.IOnRequestPermissionsResultCallback の一部です。 このインターフェイスには、 OnRequestPermissionsResultユーザーの選択をアクティビティに通知するために Android によって呼び出される 1 つのメソッド があります。 ユーザーがアクセス許可を付与している場合、アプリは先に進み、保護されたリソースを使用できます。 実装 OnRequestPermissionResult 方法の例を次に示します。

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
    if (requestCode == REQUEST_LOCATION) 
    {
        // Received permission result for camera permission.
        Log.Info(TAG, "Received response for Location permission request.");

        // Check if the only required permission has been granted
        if ((grantResults.Length == 1) && (grantResults[0] == Permission.Granted)) {
            // Location permission has been granted, okay to retrieve the location of the device.
            Log.Info(TAG, "Location permission has now been granted.");
            Snackbar.Make(layout, Resource.String.permission_available_camera, Snackbar.LengthShort).Show();            
        } 
        else 
        {
            Log.Info(TAG, "Location permission was NOT granted.");
            Snackbar.Make(layout, Resource.String.permissions_not_granted, Snackbar.LengthShort).Show();
        }
    } 
    else 
    {
        base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

まとめ

このガイドでは、Android デバイスでアクセス許可を追加してチェックする方法について説明しました。 古い Android アプリ (API レベル 23) と新しい Android アプリ (API > レベル < 22) の間のアクセス許可のしくみの違い。 Android 6.0 で実行時のアクセス許可チェックを実行する方法について説明しました。