오늘 포스팅은 안드로이드 퍼미션에 관한 내용이다.


안드로이드 마시멜로우 OS가 등장함에 따라,


기존 환경에서 바뀐점들이 있다. 

(https://developer.android.com/about/versions/marshmallow/android-6.0-changes.html)


그 중, 제일 골치썩는 문제는 Runtime Permission이 아닐까 싶다.


아래의 글은 위 URL 에서 발췌한 내용중 하나이다.

Runtime Permissions


This release introduces a new permissions model, where users can now directly manage app permissions at runtime. This model gives users improved visibility and control over permissions, while streamlining the installation and auto-update processes for app developers. Users can grant or revoke permissions individually for installed apps.

On your apps that target Android 6.0 (API level 23) or higher, make sure to check for and request permissions at runtime. To determine if your app has been granted a permission, call the newcheckSelfPermission() method. To request a permission, call the new requestPermissions() method. Even if your app is not targeting Android 6.0 (API level 23), you should test your app under the new permissions model.

For details on supporting the new permissions model in your app, see Working with System Permissions. For tips on how to assess the impact on your app, see Permissions Best Practices.



간단하게 해석해보면, 


사용자가 접근 권한이 필요한 기능( 예를 들자면, 전화 바로 걸기)을 수행할때,


사용자로 하여금 해당 권한을 앱에 허락 할 것인지 묻고, 개발자가 아닌 사용자가 


자신의 디바이스의 접근 권한을 결정하는 방식이다.



이전 버전에서(API 22 이하 버전)의 접근 권한 수용방식은 앱을 설치할때,


사용자로 하여금 해당 권한을 사용한다는 것만 보여준다. 


즉, 앱을 설치하면 해당 권한등을 동의하는 것으로 간주된다.



API 22 아래 버전.


위 경우에서 개발자는 단순히 Manifest.xml에 권한 추가후 코딩하면 되겠지만,


아래와 같이 마시멜로우 버전에서의 런타임 퍼미션 체크방식 일 시, 코딩하기 녹록지 않다.


API 23 이상 버전.




하지만 모든 권한을 사용자로 하여금 확인받아야 하는 것은 아니다.


개인적인 생각이지만, 개인정보와 관련있는 권한은 확인 받지만


관련이 없는 권한은 확인을 안받아도 되는것 같다.


아래는 확인 받아야 할 권한 목록이다.



출처 : https://developer.android.com/guide/topics/security/permissions.html?hl=ko#normal-dangerous

Permission GroupPermissions
CALENDAR
CAMERA
CONTACTS
LOCATION
MICROPHONE
PHONE
SENSORS
SMS
STORAGE


지금부터 메시멜로우 os의 런타임 퍼미션을 위해 필요한 코딩등을 소개한다.

총 4가지의 메서드를 사용 할 것이다.

  • ContextCompat.checkSelfPermission()
  • ActivityCompat.shouldShowRequestPermissionRationale()
  • ActivityCompat.requestPermissions()
  • onRequestPermissionsResult()



첫번째 부터 세번째 까지의 메서드는 매개변수로 Context만 넣어줄 수 있다면, 어디서든 사용가능하다.


네번째 메서드는 Activity 안에서의 오버라이드 메서드 이다.


이름에서 볼 수 있다시피, 퍼미션 여부를 수행한 후 결과가 들어오는 곳이다.


아래의 예제를 보자.


1
2
3
4
5
6
7
8
/**
  해당 권한이 승낙 상태인지 거절 상태인지 확인한다.
*/
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_GRANTED){
   //Manifest.permission.READ_CALENDAR이 접근 승낙 상태 일때
} else{
   //Manifest.permission.READ_CALENDAR이 접근 거절 상태 일때
}
cs


최초 앱 실행시, 당연히 접근 권한은 없으므로 else 블록을 타게 된다.


위 이미지에서 보는 것 처럼 권한 설정 요구 다이얼로그를 뜨게 하려면


아래 예시처럼 requestPermission() 메서드를 추가해야 한다.


1
2
3
4
5
6
7
8
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_GRANTED){
   //Manifest.permission.READ_CALENDAR이 접근 승낙 상태 일때
} else{
   //Manifest.permission.READ_CALENDAR이 접근 거절 상태 일때
  
   //사용자에게 접근권한 설정을 요구하는 다이얼로그를 띄운다.
   ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_CALENDAR},0);
}
cs


requestPermission 메서드는 매개변수로 Context, String 배열, int형 변수 를 원한다.


int형 변수는 후에 onRequestPermissionsResult() 메서드에 결과물이 전돨될 시,


결과물들을 구분 짓는 index 번호이다.


onActivityResult 메서드랑 똑같이 보면 될 것이다.




만약 사용자가 다이얼로그를 보고 승낙을 누른다면 좋겠지만,


만약 거절을 누른다면,


더 나아가 다시 보지 않기 체크 박스에 체크후 거절 버튼을 누른다면


상황은 복잡해진다.


그러한 상황을 캐치 하기 위해 ActivityCompat.shouldShowRequestPermissionRationale() 메서드를 써야한다.


해당 메서드를 쓰기 앞서 


사용자가 다이얼로그를 띄웠을 시, 할 수 있는 경우의 수를 계산 해보자.


1. 승낙하는 경우.


2. 거절하는 경우.


3. 다시 보기 않기 체크 후 거절 하는 경우.


이렇게 3가지 이다.


2번의 경우의 수인 그냥 거절 하는 경우, 후에 다시 앱을 킬때 


ActivityCompat.shouldShowRequestPermissionRationale() 메서드를 사용하면 true 가 리턴이 된다.


즉, 사용자가 거절한 이력이 있나 없나를 알 수 있는 메서드이다.  


이 메서드는 조심해서 써야한다. 


사용자가 최초 앱 접속시 뜨는 다이얼로그는 거절 이력이 없기때문에


ActivityCompat.shouldShowRequestPermissionRationale() 메서드를 사용시 false 가 리턴된다.


또한, 사용자가 3번 경우의 수를 선택 했을 경우도 마찬가지로  false가 리턴된다.


사용자가 3번 경우의 수를 선택 했을 경우는 후에 앱이 다시 켜질때,


requestPermission() 메서드를 쓰더라도 구글이 만든 권한 설정 요구 다이얼로그가 뜨질 않는다.


그 후, 곧바로 OnRequestPermissionResult 메서드가 실행된다.


따라서, 개발자 자체적으로 다이얼로그를 띄어 사용자가 직접 설정에 들어가 권한을 설정하게끔 유도를 해야한다.



아래는 ActivityCompat.shouldShowRequestPermissionRationale() 메서드를 추가한 예시이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_GRANTED){
   //Manifest.permission.READ_CALENDAR이 접근 승낙 상태 일때
else{
   //Manifest.permission.READ_CALENDAR이 접근 거절 상태 일때
   if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.READ_CALENDAR)){
      //사용자가 다시 보지 않기에 체크를 하지 않고, 권한 설정을 거절한 이력이 있는 경우
   } else{
      //사용자가 다시 보지 않기에 체크하고, 권한 설정을 거절한 이력이 있는 경우
   }
 
   //사용자에게 접근권한 설정을 요구하는 다이얼로그를 띄운다.
   //만약 사용자가 다시 보지 않기에 체크를 했을 경우엔 권한 설정 다이얼로그가 뜨지 않고,
   //곧바로 OnRequestPermissionResult가 실행된다.
   ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_CALENDAR},0);
   
}
cs


최종 결과값은 OnRequestPermissionResult() 메서드로 받아야 한다.


아래의 코드는 예시이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResult){
  super.onRequestPermissionsResult(requestCode, permissions, grantResults);
  //위 예시에서 requestPermission 메서드를 썼을시 , 마지막 매개변수에 0을 넣어 줬으므로, 매칭
  if(requestCode == 0){
     // requestPermission의 두번째 매개변수는 배열이므로 아이템이 여러개 있을 수 있기 때문에 결과를 배열로 받는다.
     // 해당 예시는 요청 퍼미션이 한개 이므로 i=0 만 호출한다.
     if(grantResult[0== 0){
        //해당 권한이 승낙된 경우.
     }else{
        //해당 권한이 거절된 경우.
     }
  }
}
cs


onRequestPermissionResult 메서드는 사용자가 무얼 선택하던, 무조건 타는 메서드 이다.


따라서 이 메서드를 통해 사용자가 권한을 거절했을 경우 대처해야한다.


필자는 복잡한 권한체크를 해야한다는 부담감과 설령 구현하더라도 해당 코드들이 난잡하게 섞이는게 싫어서, 


자체적으로 라이브러리를 만들었다.


손쉽게 권한체크를 하고싶은 독자들은 아래의 Github 주소를 참고 하길 바란다.


 

Github에서 Star를 눌러준다면, 더 좋은 오픈소스를 만들 수 있다.



  https://github.com/Mommoo/MommooPermission




포스팅이 도움 되셨다면, 커피 한잔 후원해주세요!
더 좋은 포스팅 작성에 큰 힘이 됩니다.

Buy me a coffeeBuy me a coffee

+ Recent posts