본문 바로가기
Kotlin

[Kotlin / Android] 10. 다이얼로그와 알림 이용하기 - 퍼미션 설정하기

by 쀼르쀼르 2024. 3. 18.

10-2 퍼미션 설정하기


 

 

퍼미션(permission)

- 앱의 특정 기능에 부여하는 접근 권한

 

내가 개발하는 앱이 다른 앱이나

안드로이드 시스템에서 보호하는 특정 기능을 이용할 때

퍼미션 사용을 설정해야 함

 

내가 만든 기능을 다른 앱에서 사용할 수 없도록 보호하고

권한을 얻은 앱에서만 허용하고 싶을 때 퍼미션 설정함

 

퍼미션 설정과 사용 설정

A 앱의 컴포넌트를 B 앱에서 사용하는 상황 예시

 

외부 앱 연동

B 앱에서 A 앱의 컴포넌트와 연동하는 코드만 잘 구현하면

A 앱의 컴포넌트를 B 앱에서 얼마든지 사용 가능

but 만약 A 앱의 컴포넌트에 퍼미션을 설정하면

B앱에서 연동할 때 문제가 발생함

 

퍼미션 설정

A 앱의 개발자가 매니페스트 파일에 <permission> 태그로 퍼미션을 설정하면

이를 이용하는 B 앱의 코드를 아무리 잘 구현하더라도 실행 불가

이때는 B 앱의 매니페스트 파일에 <uses-permission> 태그로

해당 퍼미션을 이용하겠다고 설정해 줘야 함

  • <permission> : 기능을 보호하려는 앱의 매니페스트 파일에 설정함
  • <uses-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" />

 

name 속성값은 개발자가 정하는 이름으로, 퍼미션을 구별하는 식별자 역할을 함

 

labeldescription 속성값은

이 퍼미션을 이용하는 외부 앱에서 권한 인증 화면에 출력할 퍼미션의 정보임

 

protectionLevel 속성값은 보호 수준을 의미하며 다음과 같은 값을 지정할 수 있음

  • normal : 낮은 수준의 보호. 사용자에게 권한 허용을 요청하지 않아도 됨
  • dangerous : 높은 수준의 보호. 사용자에게 권한 허용을 요청해야 함
  • signature : 같은 키로 인증한 앱만 실행
  • signatureOrSystem : 안드로이드 시스템 앱이거나 같은 키로 인증한 앱만 실행 

 

protectionLevel의 속성값은 보통 normal, dangerous, signature을 사용함

 

normal로 설정 시

이 기능을 사용하는 앱이 퍼미션 사용 설정을 해야 하지만

사용자에게 권한 허용을 요청하지 않아도 되므로 덜 부담스러움

 

dangerous로 설정 시

퍼미션 사용 설정은 물론 사용자에게도 권한 허용을 요청해야 함

 

· 퍼미션 사용 설정

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

 

ACCESS_NETWORK_STATEACCESS_FINE_LOCATION

시스템에 선언된 퍼미션각각 네트워크에 접근하고 사용자 위치를 추적하는 데 필요함

 

ACCESS_NETWORK_STATEprotectionLevelnormal이고

ACCESS_FINE_LOCATIONdangerous로 설정되어 있음

 

앱 설치한 후 앱의 권한 화면*을 보면 보호 수준이 dangerous로 설정된 퍼미션만 나옴

* 앱의 권한 화면은

  안드로이드 기기의 [설정→애플리케이션(또는 '앱 정보')] 메뉴에서 앱을 선택하면 확인할 수있음

 

앱의 권한 화면

 

매니페스트 파일에 <permission>을 설정했다고 해서 컴포넌트가 보호되지는 않음

<permission>을 설정한 다음 이 퍼미션으로 보호하려는 컴포넌트에 적용해야 함

퍼미션을 컴포넌트에 적용할 때는 android:permission 속성을 이용함

 

· 컴포넌트에 퍼미션 적용

<activity android:name=".OneActivity" android:permission="com.example.TEST_PERMISSION">
    <intent-filter>
        <action android:name="android.intent.action.PICK" />
    </intent-filter>
</activity>

 

이 컴포넌트는 com.example.TEST_PERMISSION에 의해 보호되며

이 컴포넌트를 이용하는 곳에서는

매니페스트 파일에 <uses-permission>을 선언해 줘야 정상으로 실행됨

 

· 퍼미션 사용 설정

<uses-permission android:name="com.example.permission.TEST_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_SMS : 문자 메시지 발신
  • RECEIVE_SMS : 문자 메시지 수신
  • RECEIVE_BOOT_COMPLETED : 부팅 완료 시 실행
  • VIBRATE : 진동 울리기

 

퍼미션 허용 확인

 

API 레벨 23 이전에는

개발자가 매니페스트 파일에 <uses-permission>으로 선언만 하면

보호받는 기능을 앱에서 이용하는 데 문제가 없었음

 

why?

사용자는 앱의 권한 화면에서 이 앱이 어떤 기능을 이용하는지 확인만 할 수 있었음

 

API 레벨 23 버전부터 허가제로 바뀜

개발자가 <uses-permission>으로 선언했더라도사용자가 권한 화면에서 이를 거부할 수 있게 되었음

 

퍼미션 거부

 

사용자가 앱의 권한 설정에서 특정 퍼미션을 거부하면

<uses-permission>을 선언하지 않은 것과 같으며 해당 기능 이용할 수 없음

 

API 레벨 23 버전부터는

매니페스트 파일에 <uses-permisson>을 선언하는 것뿐만 아니라

앱 실행할 때 사용자가 퍼미션 거부했는지 확인하고

거부했으면 다시 퍼미션을 허용해 달라고 요청해야 함

 

구글 지도 앱 설치 후 권한 화면

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

앱을 설치한 후 초기 퍼미션은 모두 거부 상태임

따라서 필요한 권한을 허용해 달라고 사용자에게 요청해야 함

 

사용자가 퍼미션을 허용했는지 확인하려면 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("kkang", "permission granted")
} else {
    Log.d("kkang", "permission denied")
}

 

퍼미션 요청 다이얼로그

 

 

 

 

 

 

 

 

 

 

 

 

 

퍼미션 거부한 상태라면

사용자에게 해당 퍼미션을 허용해 달라고 요청해야 함

 

퍼미션 허용 요청할 때는ActivityResultLauncher를 이용함

 

이 클래스는액티비티에서 결과를 돌려받아야 할 때 사용함

 

대표적으로 퍼미션 허용 요청

다른 액티비티 실행하고 결과 돌려받을 때 사용

 

ActivityResultLauncher 객체는

registerForActivityResult( ) 함수를 호출해서 만듦

 

· registerForActivityResult( ) 함수

public final <I, O> ActivityResultLauncher<I> register
ForActivityResult(
    @NonNull ActivityResultContract<I, O> contract,
    @NonNull ActivityResultCallback<O> callback)

 

registerForActivityResult( ) 함수는 매개변수가 2개

 

첫 번째 매개변수

어떤 요청인지를 나타내는 ActivityResultContract 타입 객체

다양한 요청에 대응하는 서브 클래스들이 있음

  • StartActivityForResult : 다른 액티비티를 실행하고 결과 돌려받을 때
  • RequestPermission : 퍼미션 허용을 요청할 때

두 번째 매개변수

결과를 받았을 때 호출되는 콜백

 

· 퍼미션 허용 요청 확인

val requestPermissionLauncher = registerForActivityResult(
    ActivityResultContracts.RequestPermission()
) { isGranted ->
    if (isGranted) {
        Log.d("kkang", "callback, granted..")
    } else {
        Log.d("kkang", "callback, denied..")
    }
}

 

· 퍼미션 허용 요청 실행

requestPermissionLauncher.launch("android.permission.ACCESS_FINE_LOCATION")

 

요청 결과는

registerForActivityResult( ) 함수의 두 번째 매개변수로 등록한 콜백으로 전달됨