概要
Androidアプリにて、端末の様々な情報へのアクセスや機能の利用をユーザーに伝え、そのアクセスや機能の許可を促すための仕組み、「パーミッション」。
ストレージ、カメラ等にアクセスするアプリは、このパーミッション機能を必ず実装する必要があります。で、そのパーミッション機能、ベタで書いたら、案外コード量が多く複雑なものになりがちなのですが、"PermissionDispatcher" というライブラリを使うと、カンタンに実装できることができます。
カメラ・外部ストレージ書き込みのパーミッション実装
Android アプリで頻出しそうなケースであること、そしてkotlinでいいサンプルが見当たらなかったのカメラ(android.permission.CAMERA)と外部ストレージ書き込み(android.permission.WRITE_EXTERNAL_STORAGE) のパーミッションチェックをPermissionDispatcher で実装しました。
https://github.com/rochefort8/PermissionCheck-android-sample
環境
上記GitHub の動作・開発環境です。
Host
MacBook Pro (Retina, 13-inch, Mid 2014)
macOS High Sierra 10.13.6
Android Project
- Android Studio : 3.3.1
- Grade : 4.10.1
- Android Plugin version : 3.3.2
- Target SDK version : 28
動作確認
- Xperia XZ1 (Android 8)
- Nexus 5 (Android 6.0.1)
- Genymotion Google Pixel
手順
以下の記事に手順、機能詳細が書いてあります。
【Android】 パーミッション判定の複雑なコードを解決!PermissionsDispatcherライブラリを試してみた
以下、この記事に沿って作成したときの手順です。
-
新規プロジェクト作成
略 -
PermissionDispatcher ライブラリ利用のための記述
app の方のbuild.gradleに以下を追記してSyncする。
...
// 追記
apply plugin: 'kotlin-kapt'
dependencies {
....
// 以下の4行を追記
implementation ('com.github.hotchemi:permissionsdispatcher:3.3.1'){
exclude module: "support-v13"
}
kapt "com.github.hotchemi:permissionsdispatcher-processor:3.3.1"
}
<!-- Permission -->
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
-
新しいActiivty ”PermissionCheckActivity”を作成
ここにPermission Check を実装。 -
Permission Check で使う文字列の定義
<string name="alert_diaglog_message_for_permission">アプリがこの操作を実行するには次の権限の許可が必要です。\n
カメラ\nストレージ\n\n権限を許可するには、[アプリ情報]→[許可]に移動してください。</string>
<string name="button_name_app_info">アプリ情報</string>
- Launcher Activity をPermisshinCheckActivity にする
// アクティビティを「入れ替え」
<activity android:name=".MainActivity">
</activity>
<activity android:name=".PermissionCheckActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- PermissionCheckActivity.kt 実装
package com.rochefort10.permissiondispatcher_sample
import android.Manifest
.....
@RuntimePermissions
class PermissionCheckActivity : AppCompatActivity() {
var isWriteExternalStorageAllowed = false
var isCameraAllowed = false
val REQUEST_CODE_MAGIC = 1212
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
startPermissionCheck()
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
// NOTE: delegate the permission handling to generated function
onRequestPermissionsResult(requestCode, grantResults)
}
// ---------- WRITE_EXTERNAL_STORAGE ----------
@NeedsPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
fun showWriteExternalStorage() {
isWriteExternalStorageAllowed = true
showCameraWithPermissionCheck()
}
// @OnShowRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)
// fun showWriteExternalStoraga(request: PermissionRequest) {
// showRationaleDialog("Reason to use external storage.",request)
// }
@OnPermissionDenied(Manifest.permission.WRITE_EXTERNAL_STORAGE)
fun onWriteExternalStorageDenied() {
isWriteExternalStorageAllowed = false
showCameraWithPermissionCheck()
}
@OnNeverAskAgain(Manifest.permission.WRITE_EXTERNAL_STORAGE)
fun onWriteExternalStorageNeverAskAgain() {
isWriteExternalStorageAllowed = false
showCameraWithPermissionCheck()
}
// ----------- CAMERA ----------
@NeedsPermission(Manifest.permission.CAMERA)
fun showCamera() {
isCameraAllowed = true
startNextActivity()
}
// @OnShowRationale(Manifest.permission.CAMERA)
// fun showRationaleForCamera(request: PermissionRequest) {
// showRationaleDialog("Reason to use camera access.",request)
// }
@OnPermissionDenied(Manifest.permission.CAMERA)
fun onCameraDenied() {
isCameraAllowed = false
startNextActivity()
}
@OnNeverAskAgain(Manifest.permission.CAMERA)
fun onCameraNeverAskAgain() {
isCameraAllowed = false
startNextActivity()
}
private fun startPermissionCheck() {
showWriteExternalStorageWithPermissionCheck()
}
private fun startNextActivity() {
if ((isCameraAllowed == true) && (isWriteExternalStorageAllowed == true)) {
// Every permission are set, moving to the next step
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
finish()
} else {
// Not enough permissions, finish with some message
if (!isCameraAllowed)
Log.d("CAM", "No")
if (!isWriteExternalStorageAllowed)
Log.d("STO", "No")
AlertDialog.Builder(this)
.setPositiveButton(android.R.string.cancel) { _, _ ->
finish()
}
.setNegativeButton(R.string.button_name_app_info) { _, _ ->
val uriString = "package:$packageName"
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse(uriString))
startActivityForResult(intent, REQUEST_CODE_MAGIC)
}
.setCancelable(false)
.setMessage(R.string.alert_diaglog_message_for_permission)
.show()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
super.onActivityResult(requestCode, resultCode, intent)
if (requestCode == REQUEST_CODE_MAGIC) {
// Start again
startPermissionCheck()
}
}
}