권한 요청 dialog를 불러오는 부분에 대해서는 이전에 "외부 저장소에서 폴더 생성하기" 글에서 간략하게 올린 적이 있다.
한 번만 요청하는 건 사용자가 거부할 수도 있고, 다시 묻지 않기를 누를 수도 있다.
이번에는 조금 더 진화된(?) 느낌으로 권한 허용을 요청하도록 해보자.
가장 쉬운 방법은 처음 시작할 때 권한 허용을 위한 화면을 만드는 것이다. 해당 화면을 지나가지 않으면 아예 다음 화면으로 넘어갈 수 없도록.
본인은 해당 프로젝트에서 요구 받은 사항으로 권한 허용에 대한 화면은 없다. 그렇기 때문에 처음 시작할 때 권한 요청 dialog 만을 활용하여 모든 권한이 허용되어야 앱을 사용할 수 있도록 하여야 한다.
override fun onStart() {
super.onStart()
if (!hasPermission(Manifest.permission.ACCESS_FINE_LOCATION) ||
!hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) ||
!hasPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
) {// 권한 허용이 되어 있지 않다면
ActivityCompat.requestPermissions(
this,
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
), REQUEST_LOCATION_PERMISSION
)
} else {// 권한 허용이 되어 있다면
scanEnable()
}
}
//permission 체크 함수
private fun Context.hasPermission(permission: String) =
ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
사용자가 수락했는 지, 거절했는 지에 따라 다시 권한을 요청하도록 한다.
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == 1 && grantResults.isNotEmpty()) {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(
this,
Manifest.permission.WRITE_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(
this,
Manifest.permission.READ_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
) { // 권한이 거절된 상태
if (ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) || ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.WRITE_EXTERNAL_STORAGE
) || ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.READ_EXTERNAL_STORAGE
)
) {
// 승인 거절
permissionCheck = false
val toast = Toast.makeText(this, "앱을 사용하려면 권한을 허용해주세요.", Toast.LENGTH_LONG)
toast.show()
Handler().postDelayed({
ActivityCompat.requestPermissions(
this,
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
), REQUEST_LOCATION_PERMISSION
)
}, 1500)
} else { // 다시 묻지 않음 옵션을 선택, 승인요청을 한적이 없는 경우
val snackBar = Snackbar.make(
findViewById(R.id.mainLayout),
"권한을 허용해야 앱을 사용할 수 있습니다. 확인을 누르면 설정 화면으로 이동합니다.",
Snackbar.LENGTH_INDEFINITE
)
snackBar.setAction("확인") {
val intent = Intent()
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
val uri = Uri.fromParts("package", packageName, null)
intent.data = uri
startActivity(intent)
}
snackBar.show()
}
} else { // 4. 권한이 승인된 상태
scanEnable()
}
}
}
주석이 처리가 되어 있지만 설명하자면, if (requestCode == 1 && grantResults.isNotEmpty()) {
를 통해 사용자 event 결과를 확인한다.
권한을 거절한 상태라면 1. 승인을 거절한 경우, 2. 다시 묻지 않음 옵션을 선택한 경우 & 승인 요청을 한적 없는 경우. 로 나뉜다.
승인을 거절한 경우, Toast 로 권한을 요청하라고 안내 문구가 띄워지고 다시 권한을 요청한다.
Toast로 띄우는 코드와 권한을 요청하는 코드(ActivityCompat.requestPermissions)를 그냥 같이 쓸 경우, Toast가 아주 잠시 나오고 바로 요청에 대한 dialog가 나온다. 이를 방지 하기 위해 handler를 사용하여 Toast가 나오고, 1500ms 이후 요청할 수 있도록 하였다.
snackBar를 활용하여 확인 버튼을 눌렀을 때 intent를 통해 바로 설정 화면으로 이동할 수 있도록 한다.
본인은 이 권한에 대한 부분을 고찰하면서 snackBar를 처음 접했다. dialog나 Toast 처럼 유용하게 사용될 수 있을 듯 하다.
해당 코드를 통해 권한 허용이 되지 않은 경우에는 절대로 앱을 동작할 수 없게 된다.
반복하여 사용되는 부분은 함수로 만들기
권한에 대해 array로 만들어놓은 다음 활용하기
한달 정도 지나 이 글을 다시 읽어보니 권한 허용이 필요한 부분을 실행할 때마다 권한에 대한 클래스나 함수를 만들어 flag를 체크하는 방식으로 구현해도 좋을 거 같다 😏 방법은 자기가 편한대로~