Posted at

Android Mのパーミッション制御をKotlinのasync/awaitで簡単にした

More than 1 year has passed since last update.


みじかくまとめ


  • async/await (もといコルーチン)を使ってAndroidのRuntime Permissionを簡単にできるライブラリ、AsyncPermissionsを作りました。

  • 2017年5月現在、コルーチン自体がexperimentalなので取り扱いにはご注意ください。


ことの始まり:async/awaitでRxをやめたい

async/awaitはKotlin 1.1から実現された非同期処理をわかりやすく書くことができる記法です。

(詳細については手前味噌ですがこちらの記事こちらの記事をご覧ください)

現在、Android開発における非同期処理はRxJavaがメインストリームですが、async/awaitはこれをほとんどの場合で代替可能です。

しかしながらRxJavaに依存した便利ライブラリなども結構あるため、依存を剥がすのにはそれなりの手間がかかります。

中でもRxPermissionsという、Android M以降に搭載された複雑極まりないRuntime Permissionを簡単に制御できる素敵ライブラリが使えなくなってしまうのは大きな痛手です。

そこで、async/awaitでRxPermissionsばりに簡単にRuntime Permissionを制御できるライブラリ、AsyncPermissionsを作りました。


使い方

まずはbuild.gradleに依存性を定義します。


app/build.gradle

repositories {

maven { url "https://jitpack.io" }
}

dependencies {
compile 'com.github.k-kagurazaka:async-permissions:0.0.1-alpha'
}


次にAppCompatActivity内でAsyncPermissionsクラスのインスタンスを作成します。


MainActivity.kt

private lateinit var permissions: AsyncPermissions

override fun onCreate() {
...
permissions = AsyncPermissions(this)
}


AsyncPermissions#requestメソッドでパーミッションをリクエストします。

このメソッドはsuspending functionで、パーミッションの取得結果が得られるまで呼び元のコルーチンを中断します。


MainPresenter.kt

suspend fun onCameraButtonClick() {

// カメラのパーミッションをリクエスト
permissions.request(Manifest.permission.CAMERA)
.let { handlePermissionResult(it) }
}

suspend fun handlePermissionResult(result: PermissionResult) {
// パーミッションリクエストの結果で分岐
when (result) {
is PermissionResult.Granted -> {
// パーミッションが取得できた場合
}
is PermissionResult.Denied -> {
// パーミッションが拒否された場合
}
is PermissionResult.NeverAskAgain -> {
// 「二度と表示しない」にチェックされた上でパーミッションが拒否された場合
// 多くの場合、パーミッションの必要性を表示してアプリの設定画面に飛ばす処理を行うと思います
}
is PermissionResult.ShouldShowRationale -> {
// 一度拒否された後に再びリクエストがされた場合
// パーミッションが必要な根拠をユーザに表示するのが推奨されています
showRationale(result)
}
}
}


PermissionResult.ShouldShowRationaleが結果として得られた場合は、次のように結果インスタンスからパーミッション取得のプロセスを進めることができます。


MainPresenter.kt

fun showRationale(result: PermissionResult.ShouldShowRationale) {

AlertDialog.Builder(this)
.setPositiveButton("おっけー!") { _, _ ->
// proceedメソッドは再びパーミッション許可ダイアログを表示してその結果を返します
launch(UI) { result.proceed().let { handlePermissionResult(it) } }
}
.setNegativeButton("やだ") { _, _ ->
// cancelメソッドは直ちにPermissionResult.Deniedを返します
launch(UI) { result.cancel().let { handlePermissionResult(it) } }
}
.setCancelable(false)
.setMessage("このパーミッションはこういう理由で必要だから、次のダイアログで許可ボタンを押してね♥")
.show()
}

proceedメソッドを即時呼ぶことで、根拠の表示をせずに直接パーミッション許可ダイアログを出すこともできます。


MainPresenter.kt

is PermissionResult.ShouldShowRationale -> result.proceed()


簡単ですね!


まとめ

RxJavaをasync/awaitで代替するときにRxPermissionsの代わりとなれるライブラリ、AsyncPermissionsの紹介をしました。

async/await自体がまだexperimentalなためalpha版という扱いですが、Kotlin 1.2でasync/awaitがstableになったタイミングで1.0.0を出す予定ですので、RxJava止めたいという人は是非お試しください。