본문 바로가기

Programming/Android

[Android] Permission 체크 하나의 메소드로 해결해보기

안드로이드 마시멜로우 이후 구글의 퍼미션 정책이 바뀌어 중요 퍼미션을 사용해야 하는 기능마다 그 기능을 사용할 때 퍼미션 권한 획득에 대해 물어보게 되었다. 소스코드가 어려운 것은 아니냐 내용이 적지 않으므로 매 퍼미션 사용시 그 코드를 사용하면 코드의 가독성이 떨어질 뿐더러 중복성이 증가하게 된다. 그렇기 때문에 메소드 하나를 생성해 더욱 편리하게 퍼미션 관리를 하는 방법이 없을까 고민해 보았다. 물론 퍼미션 라이브러리가 존재하나 개인적으로 라이브러리를 상속해 쓰다보면 그 라이브러리와 내가 써야하는 코드의 방법이 중복되어 난관에 부딪힐 확률이 높다고 생각하고, 그에 따라 메소드를 불러오는 형식을 선호하여 이러한 방식을 사용하는 것을 보시는 분은 이해해 주셨으면 한다.


일단 퍼미션 관련 메소드의 기본 형식은 이러하다.


- 해당 권한을 이미 가지고 있는지 체크.


ContextCompat.checkSelfPermission()


- 해당 권한을 가져와야 하는 이유를 설명해야 하는 경우.


shouldShowRequestPermissionRationale()


- 해당 권한을 요청할 때.


requestPermissions()



위의 세가지 메소드를 쓰게 되는데, 퍼미션 권한을 획득하기 위해선 두가지 단계를 거쳐야 한다. 마시멜로우 이하 버전인 경우와 마시멜로우 이상 버전인 경우, 그리고 이미 권한이 획득된 경우와 획득되지 않은 경우. 이 두 단계를 거쳐야 퍼미션 권한을 획득할 수 있다. 그러므로 경우의 수는 네개가 된다.


if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // 안드로이드 버전 체크. 마시멜로우 이상 true, 아니면 false
int permissionResult = mContext.checkSelfPermission(permissionChk); // 해당 퍼미션 체크.
if (permissionResult == PackageManager.PERMISSION_DENIED) { // 해당 퍼미션이 거부상태면 true, 아니면 false
/*
* 해당 권한이 거부된 적이 있는지 유무 판별 해야함.
* 거부된 적이 있으면 true, 거부된 적이 없으면 false 리턴
*/

if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permissionChk)) {
// 거부된 전적이 있으므로 더욱 상세한 설명을 동반한 퍼미션 권한 요구.
} else {
// 거부된 전적이 없음. 최초 퍼미션 권한 요구.
}
} else {
// 이미 권한을 지님.
}
} else {
// 마시멜로우 이하 버전일 경우. 그냥 실행.
}


기본적으로 이러한 단계를 거치게 되고, 네 가지의 경우의 수가 나오게 된다.

마시멜로우 미만의 경우, 사용자가 이미 권한을 허용해 권한을 가지고 있는 경우 - 두 가지의 경우는 실행할 코드를 삽입하면 된다

or 마시멜로우 이상이지만 사용자가 처음 기능을 접하는 경우, 사용자가 이미 권한이 필요하다는 메세지를 받고 거부한 경우 - 각각 권한을 요청하는 코드를 삽입해야 한다.


구글에서는 사용자에게 처음 권한 획득 요청을 할때는 간략히 표시하고, 사용자가 거절하여 다시 재차 권한 요청을 해야 하는 상황에서는 해당 기능이 왜 필요한지에 대해 설명을 하여 설득을 하도록 말하고 있으나 이는 개발자들 사이에서 최초에 설명을 해도 되지 않나 등등의 의견이 다분한 상황이므로 본 게시글에서는 구글 정책에 따라서 초기 간략히 요청 후 재차 자세한 요청을 하는 코드를 작성하도록 한다.



http://stex.tistory.com/30


해당 글을 읽어보면 알겠지만 해당 글은 클릭했을 시에 해당 액티비티 내에 삽입되는 코드이고, 따로 메소드를 만드려고 하면 여러 필요한 부분 때문에 실행이 되지 않아 약간의 수정을 가해야 한다.


- Permission Check 메소드 구현.

permissionCheck.class

public class permissionCheck {

String permissionChk;
boolean result = false;
Activity activity;
Context mContext;

public boolean isCheck(final Activity act, final Context context, String per, String permissionText) {
permissionChk = per;
this.mContext = context;
this.activity = act;


Log.d("permission", permissionChk);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // 사용자의 안드로이드 OS버전이 마시멜로우 이상인지 체크. 맞다면 IF문 내부의 소스코드 작동.
// 사용자의 단말기에 "전화 걸기" 기능이 허용되어 있는지 확인.
int permissionResult = mContext.checkSelfPermission(permissionChk); // 해당 퍼미션 체크.

if (permissionResult == PackageManager.PERMISSION_DENIED) { // 해당 퍼미션 권한여부 체크.

/*
* 해당 권한이 거부된 적이 있는지 유무 판별 해야함.
* 거부된 적이 있으면 true, 거부된 적이 없으면 false 리턴
*/
if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permissionChk)) { // 거부된 적이 있으면 해당 권한을 사용할 때 상세 내용을 설명. 거부한 적 있으면 true 리턴.
AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
dialog.setTitle("권한이 필요합니다.")
.setMessage("이 기능을 사용하기 위해서는 단말기의 \"" + permissionText + "\"권한이 필요합니다. 계속 하시겠습니까?")
.setPositiveButton("네", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
activity.requestPermissions(new String[]{String.valueOf(permissionChk)}, 1000);
result = true;
}
}
})
.setNegativeButton("아니오", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(activity, "기능을 취소했습니다", Toast.LENGTH_SHORT).show();
result = false;
}
}).create().show();
} else {
activity.requestPermissions(new String[]{Manifest.permission.CALL_PHONE}, 1000);
}
} else {
result = true;
}
} else {
result = true;
}
return result;
}

public void sendIntent(Intent i) {
Intent temp = i;
activity.startActivity(temp);
}

}


해당 클래스를 이용하는 방법은 간단하다. 원하는 액티비티에서 permissionCheck 클래스를 선언한 뒤에 isCheck 메소드에 현재 Activity와 Context, 그리고 원하는 permission 과 alertDialog 작동시 알림에 들어갈 알림말을 넣어주기만 하면 된다. 


해당 퍼미션에 대해 이미 권한을 획득했으면 true를 반환하고 그렇지 않으면 false를 반환한다. 이를 이용해 원하는 기능의 작동 여부를 판단하여 좀 더 편리하게 퍼미션 관련 이슈를 해결할 수 있다.