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 permissionActivityCompat 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 명령어로 로그 출력