〈kotlin〉Android studio使い方メモ11:Runtime Permission
金宏和實さんの「作ればわかる!Androidプログラミング kotlin対応」を参考に
Android studioでkotlinを使ってAndroidアプリ作成。
Runtime Permissionとは
情報にアクセスする際にユーザーに許可を求め、同意されるとアプリにアクセス権が与えられる。
Android5.0以前はアプリインストール時に一括して許可を求めていたが、
Android6.0(API23)以降は危険性の高いパーミッションについては
インストール時ではなく実行時に個別に許可を求めることとなった。
これがRuntime Permission。
Runtime Permissionの対象パーミッション
Protection levelが「dangerous」となっているものが対象。
permission | 内容 |
---|---|
READ_CALENDAR / WRITE_CALENDAR | カレンダーの読み込み/書き込み |
CAMERA | カメラ機能 |
READ_CONTACTS / WRITE_CONTACTS | 連絡先の読み込み/書き込み |
GET_ACCOUNTS | アカウントの取得 |
ACCESS_FINE_LOCATION / ACCESS_COARSE_LOCATION | 詳細な位置/大まかな位置 |
RECORD_AUDIO | マイク |
READ_PHONE_STATE/CALL_PHONE | 電話の状態/コール |
READ_CALL_LOG/WRITE_CALL_LOG | 通信履歴の取得/書き込み |
ADD_VOICEMAIL | ボイスメールの追加 |
USE_SIP | SIPの使用 |
PROCESS_OUTGOING_CALLS | 通話発信時のintent補足 |
BODY_SENSER | 身体センサーの利用 |
SEND_SMS/RECEIVE_SMS/READ_SMS | SMSの送信/受信/読み込み |
RECEIVE_WAP_PUSH | WAPPUSHの受信 |
RECEIVE_MMS | MMSの受信 |
READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE | 外部ストレージの読み込み/書き出し |
実装
必要なPermissionを指定
AndroidManifest.xmlに必要なパーミッションを記述する。
今回は詳細な位置情報を取得するACCESS_FINE_LOCATIONを指定。
<manifest> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> </manifest>
パーミッションの確認
既に指定したパーミッションを持っているかどうかcheckSelfPermission()メソッドで確認する。
class MapsActivity : AppCompatActivity(), OnMapReadyCallback { private val REQUEST_CODE = 1 private fun checkPermission() { if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){ //処理に進む }else{ requestLocationPermission() } }
checkSelfPermission()では、既に許可されていればPERMISSION_GRANTED、
許可されていなければPERMISSION_DENIEDが返ってくる。
PERMISSION_GRANTEDが返ってこれば実行したい処理に進み、
もしPERMISSION_DENIEDであれば、パーミッションを求める手順に進む。
パーミッションを求める
requestsPermission()メソッドで許可を求めるメッセージを表示する。
これと合わせ、shouldShowRequestPermissionRationale() メソッドを用いて、
ユーザーが既に許可の選択をしたことがあるか(一度拒否されているのか、初めて許可を求めるのか)を確認する。
これがtrue(拒否されたことがある)ならば、
許可の必要性を説明するメッセージを出すなど追加のアクションを設定すると良い。
private fun requestLocationPermission() { //一度許可を求めたことがあって拒否されている場合 if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.ACCESS_FINE_LOCATION)){ ActivityCompat.requestPermissions(this, arrayOf(android.Manifest. permission.ACCESS_FINE_LOCATION), REQUEST_CODE) }else{ //まだ許可を求めていない場合 ActivityCompat.requestPermissions(this, arrayOf(android.Manifest. permission.ACCESS_FINE_LOCATION), REQUEST_CODE) } }
shouldShowRequestPermissionRationale()メソッドの返り値は、
一度拒否されて「今後表示しない」が選択されてない場合にtrue、
一度拒否されて「今後表示しない」が選択されている場合と、
初めて許可を求める場合にはfalseを返す。
「今後表示しない」が選択されている場合は、
その後のrequestPermissions()メソッドがユーザーにリクエストダイアログを出さずに
PERMISSION_DENIEDを返すみたいだが、公式の記載が見つけられず、
実際のところどうなっているのかは今後検証してみることにする。
パーミッションの結果の確認
onRequestPermissionResult()メソッドでユーザーが選択した結果を受け取る。
override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) when (requestCode){ REQUEST_CODE ->{ if (permissions.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED){ //処理に進む }else{ val toast = Toast.makeText(this, "現在位置は表示できません", Toast.LENGTH_LONG) toast.show() } } }
onRequestPermissionResult()メソッドは第一引数にリクエストコードを渡す。
リクエストコードはrequestPermissions()メソッドの第三引数で渡した固定の整数で、
この定数を元にリクエストしたパーミッションの情報を管理している。
本書ではrequestPermissions / onRequestPermissionsResultを使用していたが、
ActivityResultContractsを使うとリクエストコードなしで実装できそうだった。
参考https://developer.android.com/training/permissions/requesting?hl=ja
サンプルコードhttps://github.com/android/permissions-samples