簡単にわかりたい人向き。

 AndroidではGPS、カメラなどを利用するときにユーザの利用の許可を求める必要がある。しかし、それもAPIレベルによって動作が違ったり、許可を求めるダイアログをユーザが強制的に表示できないようになっているので、その動作が非常に面倒なものになっている。
 基本的には以下のような流れになっている。

1)APIレベルが23以上かどうか
 →以下であれば使用可能 
2)以前に許可をもらっているか
 →許可があれば使用可能
3)ダイアログの表示が可能なら許可をもらうダイアログを表示して許可をもらう
 →許可をもらったら使用可能
4)使用不可

 まずAPIレベルをチェックする。APIレベルが23未満であればアプリのインストール時に許可を得ているので、そのまま実行することができる。23以上だと、実行時にパーミッションを得る必要があるので、今回のような処理が必要になる。
 次に以前に許可を得ているかどうかを確認する。以前に許可をもらっている場合には、その情報が端末に保存されているので、許可を得ていたらそのまま使用可能ということになる。
 そして、この段階では許可を得ていないことになるのでダイアログを表示して許可を得るという処理を行う必要がある。ここで許可を得られたら使用可能だし、ここで処理を得られなければ使用不可能ということになる。
 使用不可能になったら使用不可の場合、例えば「許可を得られないと処理ができない」などのメッセージを表示して許可をもらうことになる。

 ここで゛めんどうなのが許可を得るためのダイアログをユーザが表示させないようにできてしまうことである。よくダイアログなどで「2度と表示しない」などというチェックボックスが表示される場合があるが、これに該当する。
 もしユーザがダイアログを2度と表示しないように設定していた場合、ユーザはAndroidのSettingアプリから自分で許可しなければならないので面倒である。

 基本的な許可を得る流れは以下のようになっている。
 パーミッションを求めるコマンドを実行すると、ユーザが「2度と表示しない」を選択していなければダイアログが表示されるので、ユーザが何らかのボタンを押すとイベントが発生してコールバックされる。
 コールバックされたメソッド内では、使用許可を求めたデバイスの一覧と、使用の許可/不許可が返ってくるので、それによって判断して様々な処理を続ける。
 コールバックメソッドはすでにActivityに実装されているので、それをoverrideするだけでよい。


//実行時に許可をもらうメソッド
//第二引数は許可をもらうデバイスの文字列を配列で入れる
//第三引数はパーミッションの種類を識別する任意の数値を入れる ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1)

//AppCompatActibityにこのメソッドがあるのでoverrideする
//requestCodeはrequestPermissionsの第三引数の数値が入るので、どの処理であるが区別できる
//第二引数は許可を求めたデバイス 第三引数には許可/不許可が入る
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) when (requestCode) { 1 -> { for (i: Int in permissions.indices) { if ((permissions[i] == Manifest.permission.ACCESS_FINE_LOCATION) && (grantResults[i] == PackageManager.PERMISSION_GRANTED)) {
//許可されてデバイスがここでわかるので何らかの処理をする mGetPermission = true } } } } }
 それでは、上記を実際に組み込んでみるとこういう形になる。
 流れ的にわかりやすいように、面倒な書き方だが順番に確認していき必要な処理を行うようにしている。詳しくはソースにコメントとして書いてあるので読んでみてほしい。


class MapsActivity : AppCompatActivity() {

//許可を得られたかどうかを格納しておくメンバ変数 private var mGetPermission: Boolean = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_maps) //許可を得るための自作メソッド
doCheckPermission() }
//許可を得るための自作のメソッド private fun doCheckPermission(): Unit {

//APIレベルが23未満だと、何もせず実行していい if (Build.VERSION.SDK_INT < 23) {
//ここで何かしらの処理を実行して終了 this.mGetPermission = true return }

//すでに許可を得られていたら実行可能 if (checkPermission()) { //ここで何かしらの処理を実行して終了 this.mGetPermission = true return }
//ダイアログが表示可能であれば使用許可を求めるダイアログを表示して返事を待つ
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) { ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1) //許可待ちなのでこのメソッドは終了 return }

//ここまで来てしまった場合には許可もなくダイアログも表示できない状態 Log.v("nullpo", "(´・ω・`) ") }
//checkSelfPermissionはAPIレベル23以上なので互換性レベルの関係から実行できない
//そのため別メソッドにしてコンパイラに知らせておく(アノテーション) @TargetApi(23) private fun checkPermission(): Boolean { return ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED }
//許可を求めるダイアログで何らかのボタンが押されたときに発生するイベント override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) when (requestCode) { 1 -> { for (i: Int in permissions.indices) { if ((permissions[i] == Manifest.permission.ACCESS_FINE_LOCATION) && (grantResults[i] == PackageManager.PERMISSION_GRANTED)) { mGetPermission = true } } } } } }