본문으로 바로가기


본 포스팅은 안드로이드 디벨로퍼스(https://developer.android.com/training/permissions/requesting.html?hl=ko#perm-check)를 참고하여 작성하였습니다. 


안녕하세요. PEACE-입니다.


오늘은 퍼미션 관련 정의와 체크에 대해 간단하게 짚고 넘어가겠습니다. 안드로이드 버전 6.0(Marshmallow) 부터는 안드로이드 폰에 대한 권한 설정이 엄격해졌습니다. 이전에는 메니페스트에서 퍼미션만 추가해주면 됐지만, 또 다른 방법으로 처리를 해야합니다. 매우 불편할지도 모르지만, 안드로이드 폰을 사용하는 사용자를 위한 작업이니 따를 수 밖에 없다고 생각합니다.




1. 권한 체크 사이클 예


* 권한 필요 -> 권한 체크 -> 권한 요청 -> OK (BY USER)

* 권한 필요 -> 권한 체크 -> 권한 요청 -> CANCEL (BY USER) 

-> 권한 필요 -> 권한 체크 -> 권한 요청 -> OK (BY USER)

권한 필요 -> 권한 체크 -> 권한 요청 -> CANCEL (BY USER) 

-> 권한 필요 -> 권한 체크 -> 권한 체크의 필요성 알림(NOTICE) or 권한 요청 -> OK (BY USER)


일반적으로는 두 번째 사이클을 추천합니다. 그러나 사용자를 배려하여 권한 체크에 대한 필요성을 언급해야한다면, 세 번째 사이클을 추천합니다.




2. 권한 체크


권한 체크 방법은 아래 코드를 활용한다. permissionCheck는 퍼미션을 체크하여 권한에 대해 OK를 받았는지 CANCEL을 받았는지를 리턴받는다. 앱에 권한이 있는 경우 이 메서드는 PackageManager.PERMISSION_GRANTED를 반환하고, 앱이 작업을 계속 진행할 수 있습니다. 앱에 권한이 없는 경우 이 메서드는 PackageManager.PERMISSION_DENIED를 반환하고, 앱이 사용자에게 명시적으로 권한을 요청해야 합니다. 즉, IF문을 통해 이를 비교하여 권한을 받았는지 못받았는지를 가려낼 수 있습니다.

// Assume thisActivity is the current activity
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
       
Manifest.permission.WRITE_CALENDAR);


권한을 요청을 수행하는 샘플은 아래와 같습니다. requestPermissions 메서드를 통해 권한 요청 창을 띄워줍니다.

지만 그 인자로 MY_PERMISSIONS_REQUEST_READ_CONTACTS라는 변수가 들어가는데,

이는 권한 요청 코드로 INT형이며 사용자가 임의로 정할 수 있습니다.

마치 INTENT에서 결과를 받기위해 보내는 코드와 같은 의미입니다.

그리고 가장 중요한 것은 아래와 같이 requestPermissions을 통해 권한을 요청했을때 호출되는 콜백 메서드입니다.

그 메서드는 onRequestPermissionsResult로 바로 아래에서 다루겠습니다.

// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
               
Manifest.permission.READ_CONTACTS)
       
!= PackageManager.PERMISSION_GRANTED) {


       
ActivityCompat.requestPermissions(thisActivity,
               
new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS
);
}




3. onRequestPermissionsResult 콜백 메서드


onRequestPermissionsResult 메서드는 requestPermissions에 의해 호출되며 권한 요청 결과를 판단합니다.

requestCode는 요청할 때 보낸 요청코드이며, grantResults는 요청에 OK를 했을 때의 정보를 갖습니다. 

grantResults[0]에는 PackageManager.PERMISSION_GRANTED 값을 갖습니다. 

만약 요청이 거절되었다면 grantResults에는 아무런 데이터도 존재하지 않게됩니다.

그렇게 IF문은 권한에 대해 OK 받았을 때 수행할 작업이 들어가며 ELSE에는 권한에 대해 CANCEL을 받았을 때의 코드를 넣어줍니다.

@Override
public void onRequestPermissionsResult(int requestCode,
       
String permissions[], int[] grantResults) {
   
switch (requestCode) {
       
case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
           
// If request is cancelled, the result arrays are empty.
           
if (grantResults.length > 0
               
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {

               
// permission was granted, yay! Do the
               
// contacts-related task you need to do.

           
} else {

               
// permission denied, boo! Disable the
               
// functionality that depends on this permission.
           
}
           
return;
       
}

       
// other 'case' lines to check for other
       
// permissions this app might request
   
}
}




4. 권한 취소에 대한 알림


사용자가 권한 체크를 CANCEL했을 때, 계속해서 권한을 묻는다면 사용자의 입장이 곤란할 것입니다. 그렇다고 권한이 필요할 수도 있는데 권한을 묻지 않을 수는 없습니다. 그래서 shouldShowRequestPermissionRationale를 통해 권한을 한 번 취소했던 이력이 있다면 이것에 대해 설명해주는 NOTICE를 주는 등, 여러가지 작업을 수행할 수 있습니다. 

첫 번째 IF문은 위에서 설명한대로 권한을 체크하는 조건문입니다. 두 번째 IF, IF ELSE문은 권한체크에 CANCEL한 이력이 있는지를 판단해 사용자에게 어떠한 NOTICE, 또는 권한 요청을 할지에 대한 코드를 작성할 수 있게합니다.

// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
               
Manifest.permission.READ_CONTACTS)
       
!= PackageManager.PERMISSION_GRANTED) {

   
// Should we show an explanation?
   
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
           
Manifest.permission.READ_CONTACTS)) {

       
// Show an expanation to the user *asynchronously* -- don't block
       
// this thread waiting for the user's response! After the user
       
// sees the explanation, try again to request the permission.

   
} else {

       
// No explanation needed, we can request the permission.

       
ActivityCompat.requestPermissions(thisActivity,
               
new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS
);

       
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
       
// app-defined int constant. The callback method gets the
       
// result of the request.
   
}
}