Help us understand the problem. What is going on with this article?

実行時のパーミッション リクエスト(Runtime Permission) 色々まとめ

More than 1 year has passed since last update.

〇前置き

現在地取得やカメラ機能など Dangerous パーミッションを利用する場合、Android 6.0(API レベル 23)以降、動的にアプリ内でパーミッションを付与する必要があります。

〇タイトル

1.パーミッションリクエストに必要な関数
2.基本リクエストサンプル
3.権限が必要な説明をユーザーに表示するサンプル
4.連続でリクエストを出すサンプル
5.端末のアプリ設定画面に飛ばす

〇参考URL

実行時のパーミッション リクエスト
Permissions Overview
Normal パーミッションと Dangerous パーミッション

1.パーミッションリクエストに必要な関数

ContextCompat.checkSelfPermission
ユーザーが権限を許可しているのか?の判定
ContextCompat.を付けることで、Android 6.0未満は全部権限ありとみなし、
6.0以降はユーザーの許可状況を教えてくれるので便利。
なので、Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
といった条件分岐は必要なし。

ActiivtyCompat.requestPermissions
ユーザに権限を与える
ポイントとしては権限の配列が引数に設定できます。(同時に複数リクエスト)

ActiivtyCompat.OnRequestPermissionsResult
ActiivtyCompat.requestPermissionsのコールバック
オーバーライドして権限がちゃんと付与されたのか判断することができる。

ActiivtyCompat.shouldShowRequestPermissionRationale
拒否されたときのリクエストの根拠を示すことができる。
なくてもよいが、なんでこの権限が必要なの?とユーザーが懐疑的に思う可能性があるので、
説明を表示してなるべくユーザーフレンドリーに権限を追加してもらえる。
(注意)ただし一回目は表示してくれないという特性があるのでもし一回目も表示させるにはひと手間必要。

2.基本リクエストサンプル

AndroidManifest.xml
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
activity_main.xml
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button" />

activity_main.java
import android.Manifest;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private static final int REQUEST_CODE = 1000;
    Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button = (Button)findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                checkPermission();
            }
        });
    }

    public void checkPermission(){
        // ・現在地取得のパーミッションの許可確認
        // 許可されていない
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // パーミッションの許可をリクエスト
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_CODE);
        }
        // パーミッションが許可されている
        else {
            Toast.makeText(this, "権限が許可されています", Toast.LENGTH_SHORT).show();
            // 以下通常処理等に飛ばす・・・
        }
    }

    // requestPermissionsのコールバック
    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case REQUEST_CODE:
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(this, "パーミッション追加しました", Toast.LENGTH_SHORT).show();
                    // 以下通常処理等に飛ばす・・・
                } else {
                    Toast.makeText(this, "パーミッション追加できませんでした", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
                break;
        }
    }
}

3.権限が必要な説明をユーザーに表示するサンプル

xmlファイルなどは上と同じ

activity_main.java
import android.Manifest;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
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.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private static final int REQUEST_CODE = 1000;
    Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button = (Button)findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                checkPermission(Manifest.permission.ACCESS_COARSE_LOCATION,REQUEST_CODE);
            }
        });
    }

    // パーミッションの状態を確認して、各処理に飛ばす
    public void checkPermission(final String permission,final int request_code){
        // ・現在地取得のパーミッションの許可確認
        // パーミッションが許可されていない
        if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
            // ・許可が必要な説明を表示するかの判定
            // 2回目以降「今後は確認しない」にチェックがない限りtrueになる
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {
                // 説明をダイアログで表示
                showInformationDialog(permission, request_code);
            }
            // 初回は shouldShowRequestPermissionRationale() は必ずfalse を返すため
            // 必要ならプリファランスなどに権限を許可したかの判定を持っていて、強制的にダイアログを表示する
//          else if ( プリファランス == false) {
//              showInformationDialog(permission, request_code);
//          }
            // 初回、または、「今後は確認しない」にチェックがある
            else {
                // 「今後は確認しない」の場合、パーミッション追加のポップアップは出ないで、コールバックは強制的に失敗[PERMISSION_DENIED]を返してくるので注意
                ActivityCompat.requestPermissions(this, new String[]{permission}, request_code);

            }
        }
        // パーミッションが許可されている
        else {
            Toast.makeText(this, "権限が許可されています", Toast.LENGTH_SHORT).show();
            // 以下通常処理等に飛ばす・・・
        }
    }

    // ダイアログを表示してOKを押したら、パーミッション追加リクエスト
    public void showInformationDialog(final String permission, final int request_code){
        new AlertDialog.Builder(this)
                .setTitle("パーミッションについて")
                .setMessage("最寄りの本屋を検索するのに現在地取得を許可してもらう必要があります。")
                .setPositiveButton(
                        "OK",
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                // 権限を追加
                                ActivityCompat.requestPermissions(MainActivity.this, new String[]{permission}, request_code);
                            }
                        })
                .show();

    }

    // requestPermissionsのコールバック
    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {

            case REQUEST_CODE:
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(this, "パーミッション追加しました", Toast.LENGTH_SHORT).show();
                    // 以下通常処理等に飛ばす・・・
                } else {
                    Toast.makeText(this, "パーミッション追加できませんでした。パーミッションがないと機能が使えませんよ!", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
                break;
        }
    }
}

4.連続でリクエストを出すサンプル

AndroidManifest.xml
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
activity_main.java
import android.Manifest;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    private static final int REQUEST_CODE = 1000;
    Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button = (Button)findViewById(R.id.button1);

        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                String permissions[] = new String[]{Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.READ_PHONE_STATE,Manifest.permission.READ_EXTERNAL_STORAGE};
                checkPermission(permissions,REQUEST_CODE);
            }
        });
    }

    public void checkPermission(final String permissions[],final int request_code){
        // 同時に複数渡すが、許可されていないものだけダイアログが表示される
        ActivityCompat.requestPermissions(this, permissions, request_code);
    }

    // requestPermissionsのコールバック
    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {

            case REQUEST_CODE:
                for(int i = 0; i < permissions.length; i++ ){
                    if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                        Log.w( "DEBUG_DATA", "パーミッション追加しました " + permissions[i] + " " + grantResults[i]);
                    } else {
                        Log.w( "DEBUG_DATA", "パーミッション追加できませんでした。 " + permissions[i] + " " + grantResults[i]);
                    }
                }
                break;
            default:
                break;
        }
    }
}

5.端末のアプリ設定画面に飛ばす

「今後は確認しない」にチェックが入っていると、プログラム上で変更はできないので、条件によっては設定画面に飛ばしてあげて、解除してきてもらう

activity_main.java
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.fromParts("package", getApplicationContext().getPackageName(), null));
getApplicationContext().startActivity(intent);
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away