본문 바로가기
Android/Basic

Permissions

by jaesungLeee 2021. 9. 4.

어플리케이션이 사용자의 민감한 정보를 필요로 할 때, 사용자에게 권한을 요청할 수 있다. 여기서 권한을 Permission이라고 하는데, Permission에서 Runtime Permission은 어플리케이션에서 사용자에게 요청을 하고 사용자가 허용해야 받을 수 Permission을 말한다. 따라서, Permission을 요구하는 특정한 API를 사용하는 경우에는 반드시 사용자에게 먼저 요청을 해야하며, 사용자가 요청을 거부하는 경우에 대한 예외처리도 반드시 필요할 것이다.

이번 포스팅은 API Level 23 이상부터 지원하게 되는 Runtime Permission, 즉, 사용자에게 직접 권한을 요청하는 경우에 대한 포스팅이다. (API Level 23 이하는 어플리케이션 설치 시 권한을 요청하여 획득하는 Install Permission을 사용함)

 


1. 권한 요청 Workflow

Android 공식문서에 따르면 아래와 같이 Runtime Permission을 선언하고 요청할 때 사용되는 Workflow를 제시한다. 

출처 : https://developer.android.com/training/permissions/requesting?hl=ko

 

어플리케이션에서 Runtime Permission을 선언하고 요청해야 한다고 판단될 때의 단계를 다이어그램으로 제시하는데, 아래에 해당 단계의 순서들을 확인해본다.

 

1. Permission 선언

 

2. 어플리케이션의 특정 작업에 알맞은 Runtime Permission과 연결되도록 UX 설계

 

3. 어플리케이션의 특정 작업을 사용자가 호출할 때까지 대기

 

4. 사용자가 어플리케이션에 필요한 Runtime Permission을 부여했는지 확인

 

4-Yes (8a). 어플리케이션에서 사용자의 정보에 접근할 수 있음.

 

4-No (5a). 사용자에게 어플리케이션에서 해당 Permission을 요청하는 이유를 설명 (UI 요소 사용)

 

6. 어플리케이션에서 Runtime Permission을 요청

 

7. 사용자가 Runtime Permission을 승인했는지 거부했는지 사용자의 응답 확인

 

7-Yes (8a). 어플리케이션에서 사용자의 정보에 접근할 수 있음.

 

7-No (8b). Permisson이 필요 없어도 사용자에게 기능을 제공할 수 있도록 어플리케이션 환경의 성능을 단계적으로 저하

 

위의 단계 중 구현에 있어서 고려해야할 단계들을 아래에 순차적으로 살펴본다.


2. Permission 선언 (1)

어플리케이션의 Manifest.xml 파일에 어플리케이션에서 요청할 권한을 선언한다.

<manifest ...>
    
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.SEND_SMS" />
    <uses-permission android:name="android.permission.VIBRATE" />
    
    <application ...>
    	...
    </application>
    
</manifest>

위와 같이 <uses-permission> 태그를 이용하여 사용자에게 요청할 권한들을 선언할 수 있다. 이 외에도 다양한 Permission들이 존재한다.


3. 사용자가 Runtime Permission을 부여 했는지 확인 (4)

사용자가 이미 어플리케이션에 특정 권한을 부여했는지 확인하기 위해 checkSelfPermission( ) Method를 사용한다. 해당 Method는 권한 부여 여부에 따라 PERMISSION_GRANTED 혹은 PERMISSION_DENIED를 반환한다. 아래와 같이 구현할 수 있다.

 

if (ComtextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE) 
    == PackageManager.PERMISSION_GRANTED) {
    // 권한 허용
}
else {
    // 권한 거부
}

 

4. 사용자에게 어플리케이션이 해당 권한이 필요한 이유 설명 (5a)

ContextCompat.checkSelfPermission( ) Method가 PERMISSION_DENIED를 호출하면 사용자에게 어플리케이션이 해당 권한이 필요한 이유를 설명하기 위한 교육용 UI를 호출한다. 해당 교육용 UI에서는 사용자가 어플리케이션을 사용할 때, 특정 기능에 대해 왜 이 권한이 필요한지에 대한 이유를 설명해야 한다. 교육용 UI 호출은 shouldShowRequestPermissionRationale( ) Method를 사용하고, true를 반환할 때 교육용 UI를 호출한다.

 


5. Runtime Permission 직접 요청 (6)

시스템에서 Runtime Permission 요청을 관리하도록 허용하며 권한에 대한 Request Code를 직접 관리할 수 있다. requestPermissions( ) Method를 사용한다. 첫 번째 Parameter로 Permissions Array, 두 번째 Parameter로 사용할 Request Code를 넣는다. 

 

위에서 설명한 3, 4, 5의 구현을 when 구문을 이용하여 아래와 같이 구현할 수 있다.

 

when {
    // 이전에 ReadExternalStorage 권한이 성공적으로 부여 되었을 때
    ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED -> {
        navigatePhotos()
    }

    // 한번 거부 후 다시 요청 시
    shouldShowRequestPermissionRationale(android.Manifest.permission.READ_EXTERNAL_STORAGE) -> {
        showPermissionPopup()
    }

    else -> {
        requestPermissions(arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE), 1000)    // 권한에 따라 requestCode를 다르게 주면 됨
    }
}

 

requestPermissions( )에서 사용자가 응답하게 되면 시스템은 onRequestPermissionsResult( ) Method를 호출한다. 아래와 같이 구현할 수 있다.

 

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)

    when (requestCode) {
        1000 -> {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 권한 부여 되었음, 사진 불러오기
                navigatePhotos()
            }
            else Toast.makeText(this, "권한을 거부하였습니다.", Toast.LENGTH_LONG).show()
        }
        else -> {

        }
    }
}

 

requestPermissions( )에서 READ_EXTERNAL_STORAGE에 대한 Runtime Permission의 Request Code로 1000을 사용하였다. 마찬가지로, onRequestpermissionsResult( )에서 1000을 이용하여 해당 권한이 허용되었는지 불허용 되었는지 확인할 수 있다. grantResults Array의 0번째 Index에서 확인할 수 있다.

 

 

References

https://developer.android.com/training/permissions/requesting?hl=ko 

 

앱 권한 요청  |  Android 개발자  |  Android Developers

앱 권한 요청 모든 Android 앱은 액세스가 제한된 샌드박스에서 실행됩니다. 앱이 자체 샌드박스 밖에 있는 리소스나 정보를 사용해야 하는 경우 권한을 선언하고 이 액세스를 제공하는 권한 요청

developer.android.com

'Android > Basic' 카테고리의 다른 글

Android Component : 2. Service 개요  (0) 2021.11.08
Context  (1) 2021.08.26
Android Component : 1. Activity와 생명 주기  (0) 2021.08.24