아래 내용은 Android Developer 공식 문서 내용을 참고하여 작성한 자습 기록입니다.



📚Android 정리 - 권한 요청

안전하고 투명한 앱을 개발하기 위해서 개발자들은 권한 요청을 사용해야 한다. 카메라, 마이크, 위치 정보와 같이 사용자의 민감한 정보들에 대해서 접근하기 이전에 안드로이드 시스템에서 사용자에게 권한을 허용할 것인지에 대한 여부를 묻는 과정과 그에 대한 동의가 필요하다. 이를 통해 사용자는 개인 정보 보호 및 보안에 대해 안전함을 느끼고 앱을 사용할 수 있다. 따라서 이번에는 권한 요청 과정에 대해 알아보고자 한다.



📔 기본 원칙

런타임 권한을 요청하기 위한 기본 원칙은 다음과 같다.

  • 사용자가 권한이 필요한 기능을 사용하기 시작할 때, 해당 컨텍스트에서 권한을 요청한다. 예를 들어, 앱에서 카메라 기능을 필요로 한다고 가정할 때, 앱이 시작했을 때 권한을 요청하기 보단 카메라 기능을 실행하려고 할 때 권한을 요청하도록 한다. 이러한 방법은 사용자가 권한이 필요한 이유를 이해할 수 있고, 권한을 부여할 가능성을 높이는 데 도움이 된다.

  • 사용자를 차단하지 않는다. 교육용 UI를 보여주는 과정(권한 요청의 이유를 설명하는 과정)에서 취소할 수 있는 옵션을 항상 제공한다. 예를 들어, 특정 기능에 대해 해당되는 권한이 필요한 이유를 설명해야 하는 경우, 사용자가 편의에 따라 해당 권한에 대해 동의할 지 또는 취소할 지에 대한 선택을 할 수 있는 교육용 UI를 제공해야 한다.

  • 사용자가 기능에 필요한 권한을 거부하거나 취소하면 권한이 필요한 기능을 사용 중지하는 등의 방법으로 앱의 성능을 단계적으로 저하시켜 사용자가 앱을 계속 사용할 수 있도록 한다.

  • 시스템 동작을 확신해선 안된다. 예를 들어 동일한 권한 그룹에 권한이 표시된다고 확신하면 안된다. 권한 그룹은 앱이 밀접하게 관련된 권한을 요청할 때 시스템에서 사용자에게 표시하는 시스템 다이얼로그의 수를 최소화하는 데만 도움이 된다. 시스템의 동작을 확신하지 않음으로써 앱이 다양한 기기 및 Android 버전에서 올바르게 작동하도록 할 수 있다.



📔 권한 요청 과정



📔 권한 요청 연습해보기

📖 Manifest 파일에 권한 설정

매니페스트 파일에서 사용하고자 하는 앱의 기능에 대한 권한을 설정한다.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

    <application
        ...
    </application>

</manifest>

📖 권한 요청

when {
    // 권한을 허용했는지 확인
    ContextCompat.checkSelfPermission(
        this,
        android.Manifest.permission.READ_MEDIA_IMAGES
    ) == PackageManager.PERMISSION_GRANTED -> {
        getImages() // 허용했다면 기능 실행
    }
    // 1회 승인 거부 시, 해당 권한이 필요한 이유에 대해 설명
    shouldShowRequestPermissionRationale(android.Manifest.permission.READ_MEDIA_IMAGES) -> {
        showRequestPermissionDialog()
    }
    else -> {
        // 즉시 권한 요청
        requestPermissions(
            arrayOf(android.Manifest.permission.READ_MEDIA_IMAGES),
            MEDIA_REQUEST_PERMISSION_CODE
        )
    }
}

📖 권한이 필요한 이유를 설명하는 다이얼로그

아래 코드를 통해 1회 승인 거부 후, 다시 승인을 요청한 사용자에게 해당 권한이 필요한 이유에 대해 설명하는 다이얼로그를 표시

private fun showRequestPermissionDialog() {
    AlertDialog.Builder(this).apply {
        setMessage("시스템에서 이미지에 접근할 권한이 필요합니다.")
        setNegativeButton("취소", null) // 취소 시, 아무런 변화 없음
        setPositiveButton("확인") { _, _ ->
        // 다시 권한 요청 
            requestPermissions(
                arrayOf(android.Manifest.permission.READ_MEDIA_IMAGES),
                MEDIA_REQUEST_PERMISSION_CODE
            )
        }
    }.show()
}

companion object {
    const val MEDIA_REQUEST_PERMISSION_CODE = 100
}

📖 권한 요청에 대한 결과 처리

아래 코드를 사용하여 권한을 허용하고 난 후 실행할 기능들에 대해서 설정할 수 있다.

override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<out String>,
    grantResults: IntArray
) {
    // 요청한 권한들의 코드별로 분리
    when(requestCode) {
        MEDIA_REQUEST_PERMISSION_CODE -> {
            // 요청이 취소되었을 경우 grantResults 배열은 빈 값이다.
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 요청이 성공적으로 완료되었을 경우, 계속해서 진행
                getImages()
            } else {
                // 요청한 권한이 거부 되었을 경우, 다운그레이드 등의 앱 설정
            }
            return
        }
    }
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}