Android ランタイムパーミッションの例

ようこそ、Androidランタイム許可の例へ。 Android 6.0 Marshmallowの導入により、Googleはアプリによって扱われる許可の方法を変更しました。このチュートリアルでは、導入された新しいAndroidランタイム許可とその取り扱いについて説明します。適切に処理されない場合、アプリのクラッシュの原因となります。

Androidランタイム許可とは何ですか?

Android 6.0(SDK 23)の導入により、ユーザーは特定の許可が必要になると実行時にその許可のプロンプトが表示されます。したがって、最初に思い浮かぶのは、古いアプリがAndroid Marshmallowで実行されるかどうかです。その答えははいです。targetSdkVersionが22以下の場合はサポートされます。したがって、Androidランタイム許可は後方互換性をサポートしています。ただし、これはSDKバージョンを22に設定して古いモデルの許可で作業できることを意味しません。Marshmallowを使用するユーザーは、設定→アプリ→許可から危険な許可(後で危険な許可と通常の許可について説明します)を取り消すことができます。ユーザーがまだ許可していない許可が必要な機能を呼び出そうとする場合、その関数は突然例外(java.lang.SecurityException)をスローし、アプリがクラッシュします。したがって、新しいAndroid許可モデルをアプリに実装する必要があります。

危険なAndroidパーミッションと通常のパーミッション

Androidでは、一部のパーミッションを危険なものとして定義し、他のものを通常のものとしています。両方のタイプで共通することは、それらがマニフェストファイルで定義されている必要があるということです。Android 6.0からは、ランタイムで危険なパーミッションのみがチェックされ、通常のパーミッションはチェックされません。通常のパーミッションの例は、android.permission.INTERNETです。危険なパーミッションは、ユーザーがアプリケーションに許可する内容を理解しやすくするためにカテゴリにグループ化されています。ユーザーがグループ/カテゴリ内の1つのパーミッションを承認すると、そのグループ全体が承認されます。危険なパーミッションの例は、android.permission.FINE_LOCATIONandroid.permission.COARSE_LOCATIONです。ロケーションのパーミッションのいずれかを有効にすると、すべてが有効になります。

Androidランタイムパーミッションの要求

メソッドrequestPermissions(String[] permissions, int requestCode);は、危険な権限をリクエストするために使用されるパブリックメソッドです。文字列配列の権限を渡すことで、複数の危険な権限を要求できます。Note: Android権限は、異なるグループに属する場合、それぞれのダイアログでユーザーにプロンプトが表示されます。同じグループに属する場合、1つのダイアログプロンプトのみが表示されます。リクエストの結果は、メソッドonRequestPermissionResultに渡されます。例:アプリでカメラと位置情報にアクセスしたいとします。どちらも危険な権限です。アプリケーションが起動されると、これらの権限へのアクセスをリクエストするプロンプトが表示されます。権限を文字列配列に追加し、以下に示すようにrequestPermissionsを呼び出します:

String[] perms = {"android.permission.FINE_LOCATION", "android.permission.CAMERA"};

int permsRequestCode = 200; 
requestPermissions(perms, permsRequestCode);

@Override
public void onRequestPermissionsResult(int permsRequestCode, String[] permissions, int[] grantResults){

    switch(permsRequestCode){

        case 200:

            boolean locationAccepted = grantResults[0]==PackageManager.PERMISSION_GRANTED;
            boolean cameraAccepted = grantResults[1]==PackageManager.PERMISSION_GRANTED;

            break;

    }

}

今、ユーザーにすでに承諾されている権限を継続して受け入れさせたくありません。権限が以前に付与されていたとしても、後でその権限を取り消さなかったことを確認するために再度確認する必要があります。これには、各権限に対して次のメソッドを呼び出す必要があります。

checkSelfPermission(String perm);

これはPERMISSION_GRANTEDまたはPERMISSION_DENIEDの整数値を返します。Note: ユーザーがアプリにとって重要な権限を拒否した場合、shouldShowRequestPermissionRationale(String permission);を使用して、ユーザーに権限の必要性を説明します。すでに権限が存在するかどうかをチェックするアプリケーションを開発しましょう。存在しない場合は、実行時にリクエストされます。

Android Runtime Permissions プロジェクト構造

Android Runtime Permissions コード

content_main.xml には、パーミッションを確認およびリクエストするための2つのボタンが含まれています。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.journaldev.runtimepermissions.MainActivity"
    tools:showIn="@layout/activity_main">
    <Button
        android:id="@+id/check_permission"
        android:layout_width="match_parent"
        android:layout_centerInParent="true"
        android:layout_height="wrap_content"
        android:text="Check Permission"/>
    <Button
        android:id="@+id/request_permission"
        android:layout_below="@+id/check_permission"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Request Permission"/>
</RelativeLayout>

MainActivity.java は以下のように定義されています。

package com.journaldev.runtimepermissions;

import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;

import android.view.View;
import android.widget.Button;

import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.Manifest.permission.CAMERA;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final int PERMISSION_REQUEST_CODE = 200;
    private View view;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        Button check_permission = (Button) findViewById(R.id.check_permission);
        Button request_permission = (Button) findViewById(R.id.request_permission);
        check_permission.setOnClickListener(this);
        request_permission.setOnClickListener(this);


    }


    @Override
    public void onClick(View v) {

        view = v;

        int id = v.getId();
        switch (id) {
            case R.id.check_permission:
                if (checkPermission()) {

                    Snackbar.make(view, "Permission already granted.", Snackbar.LENGTH_LONG).show();

                } else {

                    Snackbar.make(view, "Please request permission.", Snackbar.LENGTH_LONG).show();
                }
                break;
            case R.id.request_permission:
                if (!checkPermission()) {

                    requestPermission();

                } else {

                    Snackbar.make(view, "Permission already granted.", Snackbar.LENGTH_LONG).show();

                }
                break;
        }

    }

    private boolean checkPermission() {
        int result = ContextCompat.checkSelfPermission(getApplicationContext(), ACCESS_FINE_LOCATION);
        int result1 = ContextCompat.checkSelfPermission(getApplicationContext(), CAMERA);

        return result == PackageManager.PERMISSION_GRANTED && result1 == PackageManager.PERMISSION_GRANTED;
    }

    private void requestPermission() {

        ActivityCompat.requestPermissions(this, new String[]{ACCESS_FINE_LOCATION, CAMERA}, PERMISSION_REQUEST_CODE);

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case PERMISSION_REQUEST_CODE:
                if (grantResults.length > 0) {

                    boolean locationAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED;
                    boolean cameraAccepted = grantResults[1] == PackageManager.PERMISSION_GRANTED;

                    if (locationAccepted && cameraAccepted)
                        Snackbar.make(view, "Permission Granted, Now you can access location data and camera.", Snackbar.LENGTH_LONG).show();
                    else {

                        Snackbar.make(view, "Permission Denied, You cannot access location data and camera.", Snackbar.LENGTH_LONG).show();

                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                            if (shouldShowRequestPermissionRationale(ACCESS_FINE_LOCATION)) {
                                showMessageOKCancel("You need to allow access to both the permissions",
                                        new DialogInterface.OnClickListener() {
                                            @Override
                                            public void onClick(DialogInterface dialog, int which) {
                                                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                                                    requestPermissions(new String[]{ACCESS_FINE_LOCATION, CAMERA},
                                                            PERMISSION_REQUEST_CODE);
                                                }
                                            }
                                        });
                                return;
                            }
                        }

                    }
                }


                break;
        }
    }


    private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
        new AlertDialog.Builder(MainActivity.this)
                .setMessage(message)
                .setPositiveButton("OK", okListener)
                .setNegativeButton("Cancel", null)
                .create()
                .show();
    }

}

注意: ランタイムで確認する必要があるパーミッションを、Manifestファイルのアプリケーションタグの上に追加してください。

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

上記のコードでは、確認およびリクエストされる2つの権限は CAMERA および LOCATION です。静的権限の完全なクラス名をインポートすることで、私たちは PERMISSION オブジェクトを完全修飾パスの代わりに記述できます。`checkPermission()` は各権限に対して `checkSelfPermission` を呼び出します。`requestPermission()` は `ActivityCompat.requestPermissions(this, new String[]{ACCESS_FINE_LOCATION, CAMERA}, PERMISSION_REQUEST_CODE);` を呼び出します。`onRequestPermissionsResult` は権限が許可されているかどうかを確認します。コードでは、両方の権限が許可されていない場合、権限をリクエストする必要があると示すアラートダイアログが表示されます。これを行うためには、`shouldShowRequestPermissionRationale(String permission)` が呼び出され、権限が必要であることを示すアラートダイアログが表示されます。権限は手動で設定から取り消すこともできます(Settings->Apps->Permissions)。Note: ランタイム権限固有のメソッドは API 23 以降でのみ利用可能です。したがって、各メソッドでこの条件が確認されます:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)

Androidランタイム権限の例のアプリケーションの実行結果は以下の通りです。 これでこのチュートリアルは終了です。最終的なAndroidランタイム権限プロジェクトは以下のリンクからダウンロードできます。

Androidランタイム権限の例プロジェクトのダウンロード

参照:https://developer.android.com/training/permissions/requesting.html

Source:
https://www.digitalocean.com/community/tutorials/android-runtime-permissions-example