App이 어떤 권한을 갖고 있는지 확인하는 방법을 소개합니다.
- 자신의 앱이 어떤 권한을 갖고 있는지 확인
- 다른 앱이 어떤 퍼미션을 갖고 있는지 확인
Sample App
Sample App을 만들고 이 앱의 권한을 확인하는 코드를 구현할 것입니다.
다음과 같이 Sample app의 Manifest에 두개의 퍼미션을 요청했습니다.
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
그리고 앱은 INTERNET
퍼미션은 갖고 있고, READ_EXTERNAL_STORAGE
퍼미션은 갖고 있지 않은 상태입니다.
Context.checkSelfPermission()으로 권한 확인
checkSelfPermission()
는 인자로 permisison 이름을 받습니다.
public abstract int checkSelfPermission(@NonNull String permission);
Context의 App이 인자로 전달된 퍼미션을 갖고 있다면 PackageManager.PERMISSION_GRANTED
를 리턴합니다.
그렇지 않다면 PackageManager.PERMISSION_DENIED
을 리턴합니다. 즉, 이 API는 자신의 앱의 퍼미션 상태만 확인할 수 있습니다.
PackageManager.PERMISSION_GRANTED = 0;
PackageManager.PERMISSION_DENIED = -1;
Activity에서 다음과 같이 사용할 수 있습니다.
if (checkSelfPermission(Manifest.permission.INTERNET)
== PackageManager.PERMISSION_GRANTED) {
Log.d("Test", "Has INTERNET permission")
}
if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_DENIED) {
Log.d("Test", "Doesn't have READ_EXTERNAL_STORAGE permission")
}
Output:
11-14 22:27:15.014 5483 5483 D Test : Has INTERNET permission
11-14 22:27:15.014 5483 5483 D Test : Doesn't have READ_EXTERNAL_STORAGE permission
ActivityCompat API
Compatibility API를 사용하고 싶다면 ActivityCompat.checkSelfPermission(Context, Permission)
을 사용하시면 됩니다.
리턴 값은 위와 동일합니다.
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.INTERNET)
== PackageManager.PERMISSION_GRANTED) {
Log.d("Test", "Has INTERNET permission")
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_DENIED) {
Log.d("Test", "Doesn't have READ_EXTERNAL_STORAGE")
}
PackageManager.checkPermisison()으로 퍼미션 확인
checkPermisison()
은 다음과 같이 퍼미션 이름과 패키지 이름을 인자로 받습니다.
public abstract int checkPermission(@NonNull String permName, NonNull String packageName);
인자로 받은 패키지에 인자로 받은 퍼미션을 갖고 있는지 확인하고 결과를 리턴합니다. 즉, 이 API는 다른 패키지의 퍼미션 상태를 확인할 수 있습니다.
다음과 같이 App에서 사용할 수 있습니다.
if (packageManager.checkPermission(Manifest.permission.INTERNET, packageName)
== PackageManager.PERMISSION_GRANTED) {
Log.d("Test", "Has INTERNET permission")
}
if (packageManager.checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE, packageName)
== PackageManager.PERMISSION_DENIED) {
Log.d("Test", "Doesn't have READ_EXTERNAL_STORAGE permission")
}
Output:
11-14 22:30:54.999 6407 6407 D Test : Has INTERNET permission
11-14 22:30:55.000 6407 6407 D Test : Doesn't have READ_EXTERNAL_STORAGE permission
다른 패키지의 퍼미션 확인
다음과 같이 다른 앱이 특정 퍼미션을 갖고 있는지 확인할 수 있습니다. 아래 예제는 Youtube가 NFC 퍼미션을 갖고 있는지 확인하는 예제입니다.
if (packageManager.checkPermission(Manifest.permission.NFC,
"com.google.android.youtube") == PackageManager.PERMISSION_DENIED) {
Log.d("Test", "Youtube has NFC permission")
}
checkSelfPermission()과 checkPermisison()의 차이점
안드로이드의 권한은 크게 PackageManager의 Permission과 AppOps의 권한으로 나눌 수 있습니다. PackageManager의 Permission은 Manifest에 선언하는 퍼미션이고, 사용자에게 권한을 요청하여 받는 퍼미션을 말합니다. AppOps는 Appliction Operation의 의미로, App의 동작을 제한하거나 허용하는 등의 권한을 설정하는 것을 의미합니다.
Context.checkSelfPermission()
은 AppOps의 권한과 PackageManager의 Permission을 모두 확인하여 리턴합니다.
즉, PackageManager의 Permission을 갖고 있어도 AppOps로부터 제한되었다면 PERMISSION_DENIED
가 리턴될 수 있습니다.
반면에 PackageManager.checkPermisison()
은 App이 PackageManager의 Permission을 갖고 있는지만 확인합니다.
AppOps로부터 허용되었는지 제한되었는지는 알 수 없습니다.
adb shell로 퍼미션 상태를 확인하는 방법
Settings 앱에서 내 앱의 정보에서 퍼미션 상태를 확인할 수 있습니다.
하지만 adb shell
을 사용하면 개발 중에 더 쉽게 퍼미션 상태를 확인할 수 있습니다.
다음 명령어를 입력하면 터미널에 패키지 정보가 출력됩니다.
$ adb shell dumpsys package [package name]
예를 들어, 다음과 같이 youtube에 대한 패키지 정보를 출력할 수 있습니다. 그리고 그 정보에서 퍼미션 상태를 확인할 수 있습니다.
$ adb shell dumpsys package com.google.android.youtube
Packages:
Package [com.google.android.youtube] (79c836a):
userId=10121
pkg=Package{baa705b com.google.android.youtube}
declared permissions:
com.google.android.youtube.permission.C2D_MESSAGE: prot=signature, INSTALLED
requested permissions:
android.permission.INTERNET
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_WIFI_STATE
android.permission.WRITE_EXTERNAL_STORAGE: restricted=true
....
install permissions:
com.google.android.c2dm.permission.RECEIVE: granted=true
android.permission.USE_CREDENTIALS: granted=true
com.google.android.providers.gsf.permission.READ_GSERVICES: granted=true
....
User 0: ceDataInode=122890 installed=true hidden=false suspended=false distractionFlags=0 stopped=false notLaunched=false enabled=1 instant=false virtual=false
gids=[3003]
runtime permissions:
android.permission.ACCESS_FINE_LOCATION: granted=false, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]
android.permission.READ_EXTERNAL_STORAGE: granted=false, flags=[ REVOKE_WHEN_REQUESTED|USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED|RESTRICTION_UPGRADE_EXEMPT]
android.permission.ACCESS_COARSE_LOCATION: granted=false, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]
....
각각의 항목의 의미는 다음과 같습니다.
- declared permissions : 앱에서 직접 정의한 퍼미션을 의미합니다.
- requested permissions : 앱에서 요청하는 퍼미션을 의미합니다. (Manifest에서 uses-permission으로 선언한 퍼미션)
- install permissions : 앱이 갖고 있는 퍼미션입니다. install permission은 설치될 때 부여되는 퍼미션 종류를 의미합니다.
- runtime permissions : 앱이 갖고 있는 퍼미션입니다. rumtime permission은 설치될 때 부여되지 않고, 앱이 사용자에게 권한을 요청하여 부여받는 퍼미션을 의미합니다.
다음과 같이 grep
을 이용하여 granted 상태를 쉽게 확인할 수 있습니다.
$ adb shell dumpsys package com.google.android.youtube | grep READ_CONTACTS
android.permission.READ_CONTACTS
android.permission.READ_CONTACTS: granted=false, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]
Related Posts
- Android 14 - 사진/동영상 파일, 일부 접근 권한 소개
- Android - adb push, pull로 파일 복사, 다운로드
- Android 14 - 암시적 인텐트 변경사항 및 문제 해결
- Jetpack Compose - Row와 Column
- Android 13, AOSP 오픈소스 다운로드 및 빌드
- Android 13 - 세분화된 미디어 파일 권한
- Android 13에서 Notification 권한 요청, 알림 띄우기
- Android 13에서 'Access blocked: ComponentInfo' 에러 해결
- 에러 해결: android gradle plugin requires java 11 to run. you are currently using java 1.8.
- 안드로이드 - 코루틴과 Retrofit으로 비동기 통신 예제
- 안드로이드 - 코루틴으로 URL 이미지 불러오기
- Android - 진동, Vibrator, VibrationEffect 예제
- Some problems were found with the configuration of task 에러 수정
- Query method parameters should either be a type that can be converted into a database column or a List
- 우분투에서 Android 12 오픈소스 다운로드 및 빌드
- Android - ViewModel을 생성하는 방법
- Android - Transformations.map(), switchMap() 차이점
- Android - Transformations.distinctUntilChanged() 소개
- Android - TabLayout 구현 방법 (+ ViewPager2)
- Android - 휴대폰 전화번호 가져오는 방법
- Android 12 - Splash Screens 알아보기
- Android 12 - Incremental Install (Play as you Download) 소개
- Android - adb 명령어로 bugreport 로그 파일 추출
- Android - adb 명령어로 App 데이터 삭제
- Android - adb 명령어로 앱 비활성화, 활성화
- Android - adb 명령어로 특정 패키지의 PID 찾기
- Android - adb 명령어로 퍼미션 Grant 또는 Revoke
- Android - adb 명령어로 apk 설치, 삭제
- Android - adb 명령어로 특정 패키지의 프로세스 종료
- Android - adb 명령어로 screen capture 저장
- Android - adb 명령어로 System 앱 삭제, 설치
- Android - adb 명령어로 settings value 확인, 변경
- Android 12 - IntentFilter의 exported 명시적 선언
- Android - adb 명령어로 공장초기화(Factory reset)
- Android - adb logcat 명령어로 로그 출력