퍼미션(permission)이란 앱의 특정 기능에 부여하는 접근 권한을 말한다. 내가 개발하는 앱이 다른 앱이나 안드로이드 시스템에서 보호하는 특정 기능을 이용할 때 퍼미션 사용을 설정해야 한다.
앱의 컴포넌트를 보호하고 싶을 때 매니페스트 파일에서 퍼미션을 설정할 수 있고, 퍼미션으로 보호받는 앱을 이용하는 외부 앱은 매니페스트 파일에 해당 퍼미션을 사용하겠다고 설정해야 한다.
매니페스트 파일에 퍼미션을 설정할 때는 <permission>
태그와 다음 속성을 사용한다.
name
: 퍼미션의 이름label
, description
: 퍼미션을 설명protectionLevel
: 보호 수준
- 퍼미션 설정
<permission android:name="com.example.permission.TEST_PERMISSION" android:label="Test Permission" android:description="@string/permission_desc" android:protectionLevel="dangerous" />
normal
: 낮은 수준의 보호. 사용자에게 권한 허용을 요청하지 않아도 된다.dangerous
: 높은 수준의 보호. 사용자에게 권한 허용을 요청해야 한다.signature
: 같은 키로 인증한 앱만 실행한다.signatureOrSystem
: 안드로이드 시스템 앱이거나 같은 키로 인증한 앱만 실행한다.protectionLevel
의 속성값은 보통 normal
, danger
, signature
를 사용한다. normal
은 퍼미션 사용 설정을 해야 하지만 사용자에게 권한 허용을 요청하지 않아도 되고 dangerous
는 퍼미션 사용 설정은 물론 사용자에게도 권한 허용을 요청해야 한다.
- 퍼미션 사용 설정
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
매니페스트 파일에 <permission>
을 설정했다고 해서 컴포넌트가 보호되지 않는다. <permission>
을 설정한 다음 이 퍼미션으로 보호하려는 컴포넌트에 적용해야 한다. 퍼미션을 컴포넌트에 적용할 때는 android:permission
속성을 이용한다.
- 컴포넌트에 퍼미션 적용
<activity android:name=".OneActivity" android:permission="com.example.TEST_PERMISSON"> <intent-filter> <action android:name="android.intent.action.PICK" /> </intent-filter> </activity>
이제 이 컴포넌트는 com.example.TEST_PERMISSON
에 의해 보호되며 이 컴포넌트를 이용하는 곳에서는 매니페스트 파일에 <uses-permission>
을 선언해야 정상으로 실행된다.
이처럼 외부 앱과 연동할 때 퍼미션 사용을 설정해야 하지만 안드로이드 시스템에서 보호하는 기능을 사용할 때도 매니페스트 파일에 사용 설정을 해야 한다. 시스템이 보호하는 기능은 대표적으로 다음과 같다.
ACCESS_FINE_LOCATION
: 위치 정보 접근ACCESS_NETWORK_STATE
: 네트워크 정보 접근ACCESS_WIFI_STATE
: 와이파이 네트워크 정보 접근BATTERY_STATS
: 배터리 정보 접근BLUETOOTH
: 블루투스 장치에 연결BLUETOOTH_ADMIN
: 블루투스 장치를 검색하고 페어링CAMERA
: 카메라 장치에 접근INTERNET
: 네트워크 연결READ_EXTERNAL_STORAGE
: 외부 저장소에서 파일 읽기WRITE_EXTERNAL_STORAGE
: 외부 저장소에 파일 쓰기READ_PHONE_STATE
: 전화기 정보 접근SEND_SNS
: 문자 메시지 발신RECEIVE_SMS
: 문자 메시지 수신RECEIVE_BOOT_COMPLETED
: 부팅 완료 시 실행VIBRATE
: 진동 울리기API 레벨 23 버전부터 허가제가 되었다. 개발자가 <uses-permission>
으로 선언했더라도 사용자가 이를 거부할 수 있다.
만약 사용자가 앱의 권한 설정에서 특정 퍼미션을 거부하면 <uses-permission>
을 선언하지 않은 것과 같으며 앱에서는 해당 기능을 이용할 수 없다. 결국 API 레벨 23부터는 매니페스트 파일에 <uses-permission>
을 선언하는 것뿐만 아니라 앱을 실행할 때 사용자가 퍼미션을 거부했는지 확인하고 만약 거부했으면 다시 퍼미션을 허용해 달라고 요청해야 한다.
앱을 설치한 후 초기 퍼미션은 모두 거부 상태이다. 따라서 필요한 권한을 허용해 달라고 사용자에게 요청해야 한다.
사용자가 퍼미션을 허용했는지 확인하려면 checkSelfPermission()
함수를 이용한다.
- 퍼미션 허용 확인 함수
open static fun checkSelfPermission ( @NonNull context : Context, @NonNull permission : String ) : Int
두 번째 매개변수가 퍼미션을 구분하는 이름이며 결괏값은 다음 중 하나의 상수로 전달된다.
PackageManager.PERMISSION_GRANTED
: 권한을 허용한 경우PackageManager.PERMISSION_DENIED
: 권한을 거부한 경우
- 퍼미션 허용 확인 예
val status = ContextCompat.checkSelfPermission(this, "android.permission.ACCESS_FINE_LOCATION") if (status == PackageManager.PERMISSION_GRANTED) { Log.d("log", "permission granted") } else { Log.d("log", "permission denied") }
만약 퍼미션을 거부한 상태라면 사용자에게 해당 퍼미션을 허용해 달라고 요청해야 한다. 사용자에게 퍼미션 허용을 요청할 때는 AcitivityResultLauncher
를 이용한다. 이 클래스는 액티비티에서 결과를 돌려받아야 할 때 사용하며 대표적으로 퍼미션 허용 요청과 다른 액티비티를 실행하고 결과를 돌려 받을 때이다.
ActivityResultLauncher
객체는 registerForActivityResult()
함수를 호출해서 만든다.
- registerForActivityResult() 함수
public final <I, O> ActivityResultLauncher<I> registerForActivityResult ( @NonNull ActivityResultContract<I, O> contract, @NonNull ActivityResultCallback<O> callback)
이 함수는 매개변수가 2개이다. 첫 번째 매개변수는 어떤 요청인지 나타내는 ActivityResultContract
타입 객체이며 다양한 요청에 대응하는 서브 클래스들이 있다. 대표적으로 다른 액티비티를 실행하고 결과를 돌려받을 때는 StartActivityForResult
, 퍼미션 허용을 요청할 때는 RequestPermission
을 사용한다.
두 번째 매개변수는 결과를 받았을 때 호출되는 콜백이다.
- 퍼미션 허용 요청 확인
val requestPermissionLauncher = registerForActivityResult( ActivityResultContracts.RequestPermission() ) { isGranted -> if (isGranted) { Log.d("log", "callback, granted...") } else { Log.d("log", "callback, denied...") } }
registerForActivityResult()
함수로 ActivityResultLauncher 객체를 만들었다면 필요한 곳에서 ActivityResultLauncher
객체의 launch()
함수를 호출하여 요청을 실행한다.
- 퍼미션 허용 요청 실행
requestPermissionLauncher.launch("android.permission.ACCESS_FINE_LOCATION")
요청 결과는 registerActivityResult()
함수의 두 번째 매개변수로 등록한 콜백으로 전달된다. 위 예제는 퍼미션 허용 요청과 결과를 받는 방법이었고 액티비티를 실행하고 결과를 돌려받는 방법은 이후에 다루겠다.