LoginSignup
2
2

More than 1 year has passed since last update.

【Android】ResultAPI を使って実行時権限をリクエストしてみる

Last updated at Posted at 2022-01-21

AndroidX に追加された ResultAPI を使って実行時権限をリクエストする処理を書き方をご紹介したいと思います。

ResultAPI とは

ResultAPI とは、androidx.activity のバージョン 1.2.0-alpha02 と androidx.fragment のバージョン 1.3.0-alpha02 で追加された API です。

これを使うことで非推奨となった onActivityResultonPermissionRequest などの処理を置き換えるとともに簡潔に書き直すことができるようになります。

今回は onPermissionRequest が実現できる実行時権限をリクエストしてその結果を受け取る処理を ResultAPI を使って書いていきたいと思います。

環境

Android Studio:2020.3.1 Patch 4
kotlin:1.5.31
targetSdkVersion:31
minSdkVersion:27

準備

まずは gradle にライブラリを追加します。

build.gradle

dependencies {
...

  implementation 'androidx.activity:activity-ktx:1.4.0'
  implementation 'androidx.fragment:fragment-ktx:1.4.0'
}

次に AndroidManifest にリクエストする権限を追加します。

AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.resultapisample">

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

  ...

</manifest>

レイアウトファイルのコードも記載しておきます。

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent">

        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/button1"
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            android:text="button1"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toTopOf="@+id/button2"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent" />

        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/button2"
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            android:text="button2"
            android:layout_marginTop="20dp"
            app:layout_constraintTop_toBottomOf="@+id/button1"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

権限をリクエスト(一つ)

ResultAPI を使って一つだけ権限をリクエストしてみます。

まずはリクエスト結果を受け取る処理を registerForActivityResult メソッドを使って実装します。
第一引数には ActivityResultContracts.RequestPermission クラスを、第二引数にはコールバック関数を指定します。
コールバック関数の引数は権限を許可したか否かの結果が入る Boolean 型の変数です。

 MainActivity.kt
    private val permissionResult = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
        Log.d("permission result", isGranted.toString())

        if (isGranted) {
            Toast.makeText(this, "位置情報が許可されました。", Toast.LENGTH_SHORT).show()
        } else {
            AlertDialog.Builder(this)
                .setMessage("この機能を使用するために位置情報の権限を許可してください。")
                .setCancelable(false)
                .setPositiveButton("OK") { dialog, _ ->
                    dialog.dismiss()
                }
                .setNegativeButton("キャンセル") { dialog, _ ->
                    dialog.cancel()
                }
                .create().show()
        }
    }

位置情報の権限が許可されたらトーストを表示し、許可されなかったら設定アプリから権限を許可するように促すダイアログを表示します。

リクエストするときは launch メソッドを使い、引数にリクエストする権限を指定します。

MainActivity.kt
button1.setOnClickListener {
  permissionResult.launch(Manifest.permission.ACCESS_FINE_LOCATION)
}

権限をリクエストする(複数)

権限を複数リクエストすることも可能です。
メソッドは権限が一つの時と同じように registerForActivityResult メソッドを使うのですが、引数が変わります。
第一引数には ActivityResultContracts.RequestPermissions を指定します。
第二引数にはコールバック関数を指定するのですが、引数の型は Map<String, Boolean> となります。
String型の変数は権限名、Boolean型の変数はその権限が許可されたかどうかの結果を表します。

以下はカメラと位置情報の権限をリクエストする例です。

MainActivity.kt
    private val permissionResults = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result: Map<String, Boolean> ->
        Log.d("permission result", it.toString())

        it.forEach { (permission, isGrant) ->
            val perm = when (permission) {
                Manifest.permission.ACCESS_FINE_LOCATION -> "位置情報の権限"
                Manifest.permission.CAMERA -> "カメラの権限"
                else -> ""
            }
            if (isGrant) {
                Toast.makeText(this, "${perm}が許可されました。", Toast.LENGTH_SHORT).show()
            } else {
                  AlertDialog.Builder(this)
                      .setMessage("この機能を使用するために${perm}を許可してください。")
                      .setCancelable(false)
                      .setPositiveButton("OK") { dialog, _ ->
                          dialog.dismiss()
                      }
                      .setNegativeButton("キャンセル") { dialog, _ ->
                          dialog.cancel()
                      }
                      .create().show()
            }

        }
    }

コールバック関数の Map型の引数から forEach メソッドによって権限名とリクエスト結果のペアを取り出して権限ごとに日本語のメッセージを生成してダイアログやトーストに表示するようにしています。

権限をリクエストするときは launch メソッドの引数に配列形式で権限名を指定します。

MainActivity.kt
button2.setOnClickListener {
  permissionResults.launch(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.CAMERA))
}

参考

[Android] Activity Result API を使う
アプリの権限をリクエストする  |  Android デベロッパー  |  Android Developers
ActivityResultContractsの仕組みを調べてみる - Qiita

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2