【kotlin】Androidの複数のパーミッションを取得する

以前記載した地図アプリケーションの作成において、取得するパーミッションは''ACCESS_FINE_LOCATION"の一つだけでした。
地図ダウンロードで別のパーミッションが複数必要になった場合に、パーミッションをどう取得するか疑問に思ったところもあったので改めてパーミッションの取得コードを検討します。

2つ以上のパーミッションの取得

一つのパーミッションを取得する場合と同様に、複数のパーミッションをループで取得すれば問題ないはずです。

パーミッションのチェック

private fun permissionCheck() {
    val deniedList = mutableListOf<String>()
    for(permission in permissions) {
        if(ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
            deniedList.add(permission)
        }
    }

    if(deniedList.size > 0) {
        // 不許可有
        ActivityCompat.requestPermissions(this, deniedList.toTypedArray(), PERMISSION_REQUEST_CODE)
        return
    }
    mainFunction()
}

"never ask again"チェックボックスの対応

確認ダイアログで「今後は確認しない」のチェックボックがチェックされ「許可しない」を選択された場合、アプリで対応する術はないようなのでメッセージを出した後設定画面に遷移させます。
設定画面を呼び出すための関数です。

private fun openSetting() {
    val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
    val uri = Uri.fromParts("package", packageName, null)
    intent.data = uri
    startActivityForResult(intent, PERMISSION_REQUEST_CODE)
}

設定画面からの戻り処理

設定画面に遷移後、戻るボタンで戻った時になにも変更されていない場合に備えて、再度パーミションをチェックするようオーバーライドします。

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    when(requestCode) {
        PERMISSION_REQUEST_CODE -> permissionCheck()
        else -> super.onActivityResult(requestCode, resultCode, data)
    }
}

パーミッション確認ダイアログの結果処理

パーミッション確認で「許可」、「許可しない」が押下された時の処理をオーバーライドします。

override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) { when(requestCode) {
        PERMISSION_REQUEST_CODE -> {
            for(i in grantResults.indices) {
                if(grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                    if (!ActivityCompat.shouldShowRequestPermissionRationale(this,permissions[i])) {
                        AlertDialog.Builder(this)
                            .setMessage("need permission\n\n" + permissions[i])
                            .setPositiveButton("OK", ({ _, _ -> openSetting() }))
                            .setNegativeButton("Cancel", ({ _, _ -> finish() }))
                            .show()
                    } else {
                        ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE)
                    }
                    return
                }
            }
            // パーミッション全て許可
            mainFunction()
        }
        else -> {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        }
    }
}

コード全体

android studionのプロジェクト選択で"Empty Activity"を選択した場合に初期画面に、"Hello World"のtextviewが設置されています。
このプロジェクトに

  • ACCESS_FINE_LOCATION
  • WRITE_EXTERNAL_STORAGE

の2つのパーミションを追加し、取得に成功した場合にはtextviewの文字列をpermissionのリストに変更するサンプルです。

import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.provider.Settings
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import java.lang.StringBuilder

class MainActivity : AppCompatActivity() {

    private val PERMISSION_REQUEST_CODE = 1000

    // 必要な権限
    private val permissions = arrayOf(
        Manifest.permission.WRITE_EXTERNAL_STORAGE,
        Manifest.permission.ACCESS_FINE_LOCATION)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        permissionCheck()
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        when(requestCode) {
            PERMISSION_REQUEST_CODE -> {
                for(i in grantResults.indices) {
                    if(grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                        if (!ActivityCompat.shouldShowRequestPermissionRationale(
                                this,
                                permissions[i]
                            )) {
                            AlertDialog.Builder(this)
                                .setMessage("need permission\n\n" + permissions[i])
                                .setPositiveButton("OK", ({ _, _ -> openSetting() }))
                                .setNegativeButton("Cancel", ({ _, _ -> finish() }))
                                .show()
                        } else {
                            ActivityCompat.requestPermissions(
                                this,
                                permissions,
                                PERMISSION_REQUEST_CODE
                            )
                        }
                        return
                    }
                }
                // パーミッション全て許可
                mainFunction()
            }
            else -> {
                super.onRequestPermissionsResult(requestCode, permissions, grantResults)
            }
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        when(requestCode) {
            PERMISSION_REQUEST_CODE -> {
                permissionCheck()
            }
            else -> super.onActivityResult(requestCode, resultCode, data)
        }
    }

    private fun permissionCheck() {
        val deniedList = mutableListOf<String>()
        for(permission in permissions) {
            if(ContextCompat.checkSelfPermission(
                    this, permission) != PackageManager.PERMISSION_GRANTED) {
                deniedList.add(permission)
            }
        }

        if(deniedList.size > 0) {
            // 不許可有
            ActivityCompat.requestPermissions(
                this, deniedList.toTypedArray(), PERMISSION_REQUEST_CODE)
            return
        }

        mainFunction()
    }

    private fun mainFunction() {
        val textView = findViewById<TextView>(R.id.textResult)

        val ans = StringBuilder()
        for(permission in permissions) {
            val check = ActivityCompat.checkSelfPermission(this, permission)
            ans.append(permission).append(": ").append(check).append("\n")
        }
        textView.text = ans
    }

    private fun openSetting() {
        val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
        val uri = Uri.fromParts("package", packageName, null)
        intent.data = uri
        startActivityForResult(intent, PERMISSION_REQUEST_CODE)
    }
}