기록장
[안드로이드] 일반 권한, 위험 권한 본문
권한은 앱 내에서 단말에 대한 기능들을 사용할 수 있도록 허가를 해주는 것으로 일반 권한과 위험 권한으로 나뉜다.
이름에서와 같이 일반보다 위험이 더 뭔가 중요한 정보를 다루는 느낌이 든다.
마시멜로(API 23)부터는 앱을 설치하는 시점이 아니라 실행하는 시점에서 권한을 부여받도록 변경되었다. 설치 시점에 권한을 부여해주면 앱을 설치하는 사용자는 대체로 읽지 않고 그냥 설치하는 경우가 많기 때문이다.
그래서 실행되는 시점에서 사용자가 직접 허용할지 말지를 선택할 수 있도록 바뀌었다.
앞서 언급하였듯이 일반 권한은 설치 시 판단, 위험 권한은 설치 후 실행 시 판단할 수 있도록 만든 것이란걸 알 수 있다.
보통 위험 권한으로 분류된 것들을 보면 개인정보와 관련이 많다.
- LOCATION - ACCESS_FINE_LOCATION / ACCESS_COARSE_LOCATION
- CAMERA - CAMERA
- MICROPHONE - RECORD_AUDIO
- CONTACTS - READ_CONTACTS / WRITE_CONTACTS / GET_ACCOUNTS
- PHONE - READ_PHONE_STATE / CALL_PHONE / READ_CALL_LOG / WRITE_CALL_LOG / ADD_VOICEMAIL / USE_SIP / PROCESS_OUTGOING_CALLS
- SMS - SEND_SMS / RECEIVE_SMS / READ_SMS / RECEIVE_WAP_PUSH / RECEIVE_MMS
- CALENDAR - READ_CALENDAR / WRITE_CALENDAR
- SENSORS - BODY_SENSORS
- STORAGE - READ_EXTERNAL_STORAGE / WRITE_EXTERNAL_STORAGE
이제 사용자에게 위험 권한을 판단하는 창을 띄워보도록 하겠다.
방법으로는 외부라이브러를 사용하는 것과 직접 만드는 방법이 있다.
공통적으로 하는 부분은 다음과 같다.
SD카드에 접근하기 위한 권한과 문자 메시지 관련 권한을 추가해준다.(모두 위험 권한)
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
먼저 직접 만드는 방법 코드를 알아보도록 하겠다.
코드
xml은 존재만 하면됨
MainActivity.java
public class MainActivity extends AppCompatActivity {
String[] permissions = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECEIVE_SMS};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkPermissions(permissions);
}
//권한이 있는지 없는지 확인
public void checkPermissions(String[] permissions){
ArrayList<String> targetList = new ArrayList<>();
for(int i=0;i<permissions.length;i++){
String curPermission = permissions[i]; //확인할 권한을 curPermission에 넣고
int permissionCheck = ContextCompat.checkSelfPermission(this, curPermission); //승인 여부 확인하여 int형 반환
if(permissionCheck == PackageManager.PERMISSION_GRANTED){
Log.i("태그", curPermission+"대한 권한 있음");
}
else{
Log.i("태그", curPermission+"대한 권한 없음");
if(ActivityCompat.shouldShowRequestPermissionRationale(this, curPermission)){ //권한에 대한 설명이 필요한지 아닌지 여부 판단
Log.i("태그", curPermission+"대한 권한 설명이 필요함");
}
else{
Log.i("태그", curPermission+"은 권한 추가를 위해 리스트에 추가됨");
targetList.add(curPermission); //허가되지 않은 권한들만 모아서 아래 코드에서 요청
}
}
}
String[] targets = new String[targetList.size()];
targetList.toArray(targets);
if(targets.length > 0)
ActivityCompat.requestPermissions(this, targets, 1);
}
//권한이 부여됐는지 아닌지 알 수 있도록 callback 메소드 정의
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case 1: {
if (grantResults.length > 0) {
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
int number = i+1;
Log.i("태그", ""+number+"번째 권한 승인");
} else {
int number = i+1;
Log.i("태그", ""+number+"번째 권한 거부");
}
}
}
return;
}
}
}
}
한 번 물어본 권한은 ActivityCompat.shouldShowRequestPermissionRationale 부분에서 설명이 필요하다는 표시로 넘어간다.(targetList에 담기지 않는다는 말이다)
만약 권한을 앱을 실행할 때 마다 계속 묻고 싶다면
if(ActivityCompat.shouldShowRequestPermissionRationale(this, curPermission)){ //권한에 대한 설명이 필요한지 아닌지 여부 판단
Log.i("태그", curPermission+"대한 권한 설명이 필요함");
}
else{
Log.i("태그", curPermission+"은 권한 추가를 위해 리스트에 추가됨");
targetList.add(curPermission); //허가되지 않은 권한들만 모아서 아래 코드에서 요청
}
이 부분을 지워주면 된다. 물론 물어볼 권한을 담는 targetList.add(curPermission); 남겨두고 지워주면 된다.
결과
실행하여 로그를 보면 권한이 있는지 없는지 여부를 체크되어 찍히는 것을 볼 수 있다.
실행하고 허용, 거부를 선택한다. (난 EXTERAL_STORAGE 관련은 거부하고 SMS는 허용하였음)
선택을 하고 로그를 보면 어떤 것이 허용되고 거부되었는지 알 수 있다.
여기서 앱을 종료하였다가 다시 실행하면 재차 묻지 않는다.
권한이 있는건 당연히 묻지 않겠고, 없는건 권한 설명이 필요함으로 빠진 것을 볼 수 있다.
다음은 외부 라이브러리를 이용하여 구현하는 방법이다.
외부 라이브러리를 사용하므로 추가해준다.
implementation 'com.github.pedroSG94:AutoPermissions:1.0.3'
+ 빌드그래들(앱) 내에 추가
allprojects{
repositories {
maven{url 'https://jitpack.io'}
}
}
코드
위와 마찬가지로 xml은 기본이여도 상관없음
MainActivity.java
//외부 라이브러리 내에 있는 AutoPermissionsListener 상속
public class MainActivity extends AppCompatActivity implements AutoPermissionsListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AutoPermissions.Companion.loadAllPermissions(this, 1); //모든 권한에 대한 요청
}
//권한이 부여됐는지 아닌지 callback 메소드
//콜백 메소드가 없으면 onGranted(), onDenied() 메소드 반응 안함
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
AutoPermissions.Companion.parsePermissions(this, requestCode, permissions, this);
}
//상속하면 onDenied와 onGranted를 오버라이드 해야한다.
//권한에 대해 허가하면 onGranted의 파라미터 strings 배열에 추가되고 거부하면 onDenied의 파라미터 strings에 추가된다.
//권한명이 추가되는 것
@Override
public void onDenied(int i, String[] strings) {
Log.i("태그","거부된 권한 수: " + strings.length);
}
@Override
public void onGranted(int i, String[] strings) {
Log.i("태그","허가된 권한 수: " + strings.length);
}
}
결과
아까와 똑같이 실행하고 나서 권한을 허용할지 말지 결정한다.
그 다음 로그를 보면 어떤 권한이 승인되었고 거절되었는지 알 수 있다.
부족한 점, 피드백 환영합니다.
감사합니다.
참고
정재곤, 『Do it! 안드로이드 앱 프로그래밍 - 개정 6판』, 이지스퍼블리싱(주)
'안드로이드' 카테고리의 다른 글
[안드로이드] UI, Activity(액티비티)-View(뷰) 이해 및 기초 뷰 활용 (0) | 2021.01.18 |
---|---|
[안드로이드] Database(데이터베이스) SQLite / SQLiteOpenHelper (0) | 2021.01.16 |
[안드로이드] Broadcast Receiver(브로드캐스트 리시버) / 브로드캐스트 리시버 종류 (0) | 2021.01.14 |
[안드로이드] Service(서비스) 이해하기 (0) | 2021.01.13 |
[안드로이드] RecyclerView(리사이클러뷰) (0) | 2021.01.12 |