앱 권한 권장사항

권한 요청은 기기에서 사용할 수 있는 민감한 정보를 보호하는 것이 목적이므로, 앱 작동을 위해 정보에 관한 액세스 권한이 필요한 경우에만 요청해야 합니다. 이 문서에서는 이러한 정보에 액세스하지 않고도 동일한(혹은 더 나은) 기능을 구현할 수 있는 도움말을 제공합니다. Android 운영체제에서 권한이 사용되는 방식의 전체 내용을 다루지는 않습니다.

Android 권한과 관련된 일반적인 내용은 권한 개요를 참조하세요. 코드에서 권한을 사용하는 방법을 자세히 알아보려면 앱 권한 요청을 참조하세요.

Android 권한 사용 원칙

Android 권한을 사용할 때는 다음 원칙을 따르시기 바랍니다.

#1: 앱이 작동하는 데 필요한 권한만 사용하세요. 권한을 사용하는 방법에 따라 민감한 정보에 액세스하지 않고 다른 방법(시스템 인텐트, 식별자, 통화 시 백그라운드 전환)을 통해 필요한 작업을 할 수 있는 경우도 있습니다.

#2: 라이브러리에서 요구하는 권한에 주의하세요. 라이브러리를 포함하면 권한 요구사항도 상속됩니다. 포함하는 항목, 필요한 권한, 권한 사용 목적을 알고 있어야 합니다.

#3: 투명해야 합니다. 권한을 요청할 때는 액세스하는 정보와 이유를 명확하게 밝혀 사용자가 제대로 이해한 상태로 결정할 수 있도록 해야 합니다. 이러한 정보를 설치, 런타임 또는 업데이트 권한 대화상자 등의 권한 요청과 함께 표시하세요.

#4: 시스템 액세스를 명확하게 알리세요. 카메라나 마이크 등 민감한 기능에 액세스할 때 권한 사용 메시지를 계속 표시하면 사용자에게 언제 데이터를 수집하는지 명확하게 알릴 수 있으며 은밀하게 데이터를 수집한다는 인식을 피할 수 있습니다.

이 가이드의 나머지 섹션에서는 Android 애플리케이션 개발과 관련하여 권한 사용 규칙을 자세히 설명합니다.

Android 6.0 이상에서의 권한

Android 6.0 Marshmallow는 앱이 설치 전이 아닌 런타임 시 사용자에게 권한을 요청할 수 있도록 하는 새로운 권한 모델을 도입했습니다. 새로운 모델을 지원하는 앱은 서비스 또는 서비스에 의해 보호되는 데이터가 실제로 필요할 때 권한을 요청합니다. 이 모델이 전체적인 앱 동작을 반드시 달라지게 하지는 않지만, 민감한 사용자 데이터가 처리되는 방식과 관련하여 몇 가지 변화를 유도합니다.

향상된 상황별 컨텍스트: 사용자는 앱의 컨텍스트 내에서 해당 권한 그룹이 담당하는 기능에 액세스할 권한을 런타임 시 요청받습니다. 사용자는 권한이 요청되는 컨텍스트에 더 민감하기 때문에, 앱에서 요청하는 권한과 목적이 일치하지 않는 경우 사용자에게 권한을 요청하는 이유를 자세히 설명하는 것이 더욱 중요합니다. 따라서 가능하다면 요청하는 시점과 사용자가 요청을 거부한 경우 이후의 대화상자, 모두 요청에 관한 설명을 제공해야 합니다.

권한 부여 유연성 향상: 사용자는 권한 요청을 받았을 때와 마찬가지로 설정에서도 개별 권한에 관한 액세스를 거부할 수 있지만, 권한 요청 거부로 인해 기능이 제대로 작동하지 않을 때 당황스러울 수 있습니다. 따라서 Google 애널리틱스를 사용하는 등의 방법으로 권한을 거부하는 사용자 수를 모니터링하여 해당 권한에 의존하지 않도록 앱을 리팩터링하거나 앱이 제대로 작동하기 위해 권한이 필요한 이유를 더 효과적으로 설명하는 것이 좋습니다. 또한 사용자가 권한 요청을 거부하거나 설정에서 권한을 사용 중지하는 경우 나타나는 예외를 앱에서 처리할 수 있도록 해야 합니다.

트랜잭션 부담 증가: 사용자는 권한 그룹에 관한 액세스를 그룹 단위가 아니라 개별적으로 부여하도록 요청받습니다. 이렇게 되면 권한을 부여하는 데 있어, 사용자의 부담이 증가하고 요청 중 하나 이상이 거부될 가능성이 커지기 때문에 요청하는 권한의 수를 최소화하는 것이 매우 중요합니다.

불필요한 권한 요청 피하기

권한을 요청할 때마다 사용자에게 결정을 강요하게 되므로 요청 횟수를 최소화해야 합니다. 사용자가 Android 6.0(API 레벨 23) 이상을 실행하는 경우 권한이 필요한 일부 새로운 앱 기능을 사용하려고 할 때마다 앱에서 권한을 요청하며 사용자의 작업을 방해하게 됩니다. 반면에 사용자가 이전 버전의 Android를 실행한다면 앱을 설치할 때 앱의 모든 권한을 부여해야 하는데 이때 목록이 너무 길거나 부적절해 보이면 앱을 설치하지 않을 수도 있습니다. 그렇기 때문에 앱에 필요한 권한의 수를 최소화해야 합니다.

이 섹션에서는 요청하는 권한의 수를 제한하는 데 도움이 되는 일반적인 사용 사례의 대안을 제공합니다. 사용자에게 요청되는 권한의 수와 유형은 더 적은 권한을 요청하는 유사한 앱과 비교할 때 다운로드에 영향을 미치므로 불필요한 기능을 위한 권한은 요청하지 않는 것이 좋습니다.

인텐트를 대신 사용하기

대부분의 경우 앱이 작업을 진행하는 방법으로 두 가지 중에서 선택할 수 있습니다. 앱이 직접 작업을 진행하기 위해 권한을 요청하거나 인텐트를 사용하여 다른 앱에서 작업을 진행하도록 할 수 있습니다.

예를 들어 앱에서 기기의 카메라로 사진을 찍어야 한다고 가정해 보겠습니다. 앱에서 카메라에 직접 액세스할 수 있도록 허용하는 CAMERA 권한을 요청할 수 있습니다. 권한이 부여되면 앱에서 카메라 API를 사용하여 카메라를 제어하고 사진을 찍습니다. 이 방법을 사용하면 앱에서 사진 프로세스 전체를 제어하고 카메라 UI를 앱에 통합할 수 있습니다.

그러나 사용자 데이터에 관한 액세스를 자주 요구하지 않는 경우 즉, 데이터에 액세스해야 할 때마다 런타임 대화상자와 함께 권한 요청 메시지가 표시되는 것을 사용자가 어느 정도 용인할 수 있을 때는 인텐트 기반 요청을 사용할 수 있습니다. Android는 애플리케이션에서 권한을 요구하지 않고 사용할 수 있는 시스템 인텐트를 제공합니다. 이는 사용자가 인텐트 기반 요청이 표시되는 시점에 앱과 공유할 권한을 선택하기 때문에 가능합니다.

예를 들어 MediaStore.ACTION_IMAGE_CAPTURE 또는 MediaStore.ACTION_VIDEO_CAPTURE 인텐트 작업 유형을 사용하여 Camera 개체를 직접 사용하지 않고(또는 권한을 요구하지 않고) 이미지나 동영상을 촬영할 수 있습니다. 이 경우 이미지를 촬영할 때마다 앱을 대신하여 시스템 인텐트에서 사용자의 권한을 요청합니다.

마찬가지로 전화를 걸거나 사용자의 연락처에 액세스해야 할 때도 적절한 인텐트를 만들어 작업하거나, 권한을 요청하여 적절한 개체에 직접 액세스할 수 있습니다. 각 방법에는 장단점이 있습니다.

권한을 사용하는 경우:

  • 작업을 진행할 때 앱에서 사용자 환경을 완전히 제어합니다. 그러나 적절한 UI를 디자인해야 하므로 이러한 광범위한 컨트롤이 코드를 더 복잡하게 만듭니다.
  • 사용자의 Android 버전에 따라 런타임 시 또는 앱을 설치할 때 권한 요청 메시지가 사용자에게 한 번 표시됩니다. 이후에는 앱에서 사용자에게 추가로 권한을 요청하지 않고 작업할 수 있습니다. 그러나 사용자가 권한을 부여하지 않거나 나중에 권한을 취소하면 앱에서 작업을 전혀 진행하지 못합니다.

인텐트를 사용하는 경우:

  • 작업을 위해 UI를 디자인할 필요가 없습니다. 인텐트를 처리하는 앱이 UI를 제공합니다.
  • 사용자가 선호하는 앱을 작업에 사용할 수 있습니다. 예를 들어 사용자가 즐겨 사용하는 사진 앱을 선택하여 사진을 찍습니다.
  • 작업에 사용하는 기본 앱이 없는 경우 시스템에서 사용자에게 앱을 선택하라는 메시지를 표시합니다. 사용자가 기본 핸들러를 지정하지 않으면 작업할 때마다 대화상자를 추가로 확인해야 합니다.

사용자에게 부담을 주지 않도록 주의하기

사용자가 Android 6.0(API 레벨 23) 이상을 실행 중인 경우 앱을 실행하는 동안 앱에 권한을 부여해야 합니다. 한꺼번에 많은 권한을 사용자에게 요청할 경우 사용자가 부담을 느끼고 앱 사용을 중단할 수 있습니다. 따라서 필요한 권한만 요청해야 합니다.

하나 이상의 권한이 반드시 앱에 필요한 경우도 있습니다. 이러한 필수 권한은 앱이 실행되는 즉시 모두 요청하는 것이 좋습니다. 예를 들어 사진 앱을 제작한다면 앱에서 기기의 카메라에 액세스해야 합니다. 이 경우 앱이 처음으로 실행될 때 카메라 사용 권한을 요청하더라도 사용자는 자연스럽게 받아들입니다. 그러나 이 앱에 사용자의 연락처에 있는 사람과 사진을 공유하는 기능이 있다면 처음 실행할 때 READ_CONTACTS 권한은 요청하지 말아야 합니다. 대신 사용자가 '공유' 기능을 사용하려고 할 때까지 기다린 다음 권한을 요청하세요.

앱에서 가이드를 제공한다면 가이드의 마지막 부분에서 앱의 필수 권한을 요청하는 것이 좋습니다.

오디오 포커스가 끊어진 이후에 미디어 일시중지하기

이 경우에는 사용자가 통화 중일 때 애플리케이션이 백그라운드로 전환되고 통화가 종료된 후에만 포커스를 재조정해야 합니다.

이러한 상황(예: 통화 중에 미디어 플레이어가 음소거 또는 일시중지됨)에서 일반적으로 PhoneStateListener를 사용하거나 android.intent.action.PHONE_STATE의 브로드캐스트를 수신하여 통화 상태의 변경사항을 수신합니다. 이 방법의 문제점은 READ_PHONE_STATE 권한이 요구된다는 점입니다. 이 경우, 사용자에게 기기 및 SIM 하드웨어 ID, 수신 전화의 전화번호와 같은 민감한 정보에 광범위하게 액세스할 수 있는 권한을 부여하도록 강요합니다.

앱에서 명시적인 권한을 요구하지 않는(민감한 정보에 액세스하지 않으므로) AudioFocus를 요청함으로써 READ_PHONE_STATE 또는 MODIFY_PHONE_STATE 권한을 사용하지 않고 사용자가 통화 중인지 확인할 수 있습니다. 오디오를 백그라운드로 전환하는 데 필요한 코드인 onAudioFocusChange() 를 이벤트 핸들러에 삽입하기만 하면 OS에서 오디오 포커스를 이동할 때 코드가 자동으로 실행됩니다. 방법에 관한 더 자세한 문서는 여기에서 확인하세요.

인스턴스가 실행 중인 기기 확인하기

이 경우에는 앱의 인스턴스가 실행 중인 기기를 확인하기 위한 고유 식별자가 필요합니다.

애플리케이션에 기기별 환경설정이나 메시지가 있을 수 있습니다. 예를 들면 사용자의 기기별 재생목록을 클라우드에 저장하여 사용자가 자동차와 집에서 다른 재생목록을 이용할 수 있습니다. 일반적으로는 기기 IMEI와 같은 기기 식별자를 활용하는 방법이 있지만, 이렇게 하려면 기기 ID 및 통화 정보 권한 그룹(M 이상에서는 PHONE)이 필요합니다. 또한 재설정할 수 없으며 모든 앱에서 공유되는 식별자를 사용합니다.

이 유형의 식별자 대신 다음 두 가지 방법을 사용할 수 있습니다.

  1. com.google.android.gms.iid InstanceID API를 사용합니다. getInstance(Context context).getID() 가 애플리케이션 인스턴스의 고유 기기 식별자를 반환합니다. 결과적으로 앱에 관한 정보를 저장할 때 키로 사용될 수 있으며 사용자가 앱을 다시 설치하는 경우 재설정되는 앱 인스턴스 범위 식별자가 생성됩니다.
  2. randomUUID()와 같은 기본 시스템 함수를 사용하여 앱의 저장소로 범위가 지정되는 자체 식별자를 생성합니다.

광고 또는 사용자 분석을 위한 고유 식별자 생성하기

이 경우에는 앱에 로그인하지 않은 사용자의 프로필을 작성하기 위한 고유 식별자가 필요합니다(예: 광고 타겟팅 또는 전환 측정 목적).

광고 및 사용자 분석을 위한 프로필 작성에는 다른 애플리케이션과 공유되는 식별자가 필요할 때도 있습니다. 일반적으로는 기기 ID 및 통화 정보 권한 그룹(API 레벨 23 이상에서는PHONE)이 필요하지만 사용자가 재설정할 수는 없는 기기 식별자(예: 기기 IMEI)를 활용하는 해결방법이 있습니다. 하지만 이 방법은 재설정할 수 없는 식별자를 사용하고 사용자에게 비정상적으로 보일 수 있는 권한을 요청하는 것 외에도 Play 개발자 프로그램 정책을 위반하게 됩니다.

안타깝게도 이러한 경우에는 com.google.android.gms.iid InstanceID API 또는 시스템 함수를 사용하여 앱 범위 ID를 생성하는 방법은 적절한 해결 방법이 아닙니다. ID가 여러 앱 간에 공유되어야 하기 때문입니다. 또 다른 해결책은 getId() 메서드를 통해 AdvertisingIdClient.Info 클래스에서 사용할 수 있는 광고 식별자를 사용하는 것입니다. getAdvertisingIdInfo(Context) 메서드를 사용하여 AdvertisingIdClient.Info 객체를 만들고 getId() 메서드를 호출하여 식별자를 사용할 수 있습니다. 이 메서드는 차단 기능이 있으므로 기본 스레드에서 호출해서는 안 됩니다. 이 메서드에 관한 자세한 설명은 여기에서 확인하세요.

작업 중인 라이브러리 이해

앱에서 사용하는 라이브러리에 권한이 필요한 경우가 있습니다. 예를 들어 광고 및 분석 라이브러리에서 필수 기능을 구현하기 위해 위치 또는 ID 권한 그룹에 액세스해야 할 수 있습니다. 그러나 사용자의 관점에서는 라이브러리가 아닌 앱에서 권한이 요청됩니다.

사용자가 더 적은 권한을 사용하여 동일한 기능을 제공하는 앱을 선택하는 것처럼 개발자도 라이브러리를 검토하고 불필요한 권한을 사용하지 않는 타사 SDK를 선택해야 합니다. 예를 들어 앱에서 권한이 필요한 이유를 사용자에게 명확하게 제공할 수 없다면 ID 권한 그룹이 필요한 라이브러리는 사용하지 않도록 해야 합니다. 특히 위치 기능을 제공하는 라이브러리의 경우 위치 기반 타겟팅 기능을 사용하지 않는 한 FINE_LOCATION 권한을 반드시 요청할 필요는 없습니다.

권한이 필요한 이유 설명

requestPermissions() 를 호출하면 시스템에서 표시하는 권한 대화상자에는 앱에서 원하는 권한이 무엇인지는 표시되지만 이유는 제시되지 않습니다. 이 때문에 사용자가 당혹스러워하는 경우도 있습니다. requestPermissions()를 호출하기 전에 앱에서 권한을 요청하는 이유를 사용자에게 설명하는 것이 좋습니다.

연구에 따르면 사용자가 앱에서 권한이 필요한 이유를 알고 있을 때 권한 요청을 훨씬 더 편안하게 느낀다고 합니다. 사용자 연구의 결과는 다음과 같이 나타났습니다.

...모바일 앱에서 사용자의 요청된 권한 수락 여부는 해당 권한과 관련된 목적에 크게 영향을 받습니다. 예를 들어 사용자가 위치 정보 액세스 권한을 부여할 것인지 여부는 앱의 핵심 기능을 지원하기 위해 필요한 요청인지, 광고 네트워크 또는 분석 회사와 정보를 공유하기 위한 목적인지에 따라 달라집니다1

CMU의 제이슨 I. 홍 교수는 그룹 연구를 바탕으로 다음과 같은 일반적인 결론을 내렸습니다.

...사람들이 앱에서 위치와 같이 민감한 정보를 사용하는 이유(예: 타겟팅된 광고를 표시하기 위해)를 알고 있는 경우가 단지 앱에서 위치 정보를 사용한다고 알려줄 때보다 권한 요청을 더 편안하게 느낍니다1

따라서 권한 그룹에 속하는 API 호출 중 일부만 사용하고 있다면 앱에서 사용 중인 권한과 그 이유를 명시적으로 나열하는 것이 좋습니다. 예를 들면 다음과 같습니다.

  • 대략적 위치만 사용 중인 경우 앱 설명이나 앱 도움말에 이 정보를 표시하여 사용자가 알 수 있도록 합니다.
  • 사기로부터 사용자를 보호하는 인증 코드를 받기 위해 SMS 메시지에 액세스해야 한다면 이 사실을 앱 설명을 통해 사용자에게 알리거나 데이터에 처음 액세스할 때 표시합니다.

    참고: 앱에서 Android 8.0(API 레벨 26) 이상을 타겟팅하는 경우 사용자 인증 정보를 확인하는 과정에서 READ_SMS 권한을 요청하지 마세요. 대신 createAppSpecificSmsToken()을 사용하여 앱별 토큰을 생성한 다음 인증 SMS 메시지를 전송할 수 있는 다른 앱이나 서비스로 이 토큰을 전달하세요.

특정 조건에서는 사용자에게 민감한 정보 액세스를 실시간으로 알리는 것이 효과적일 수 있습니다. 예를 들어 카메라나 마이크에 액세스한다면 앱의 특정 위치 또는 알림 목록(애플리케이션이 백그라운드에서 실행 중인 경우)에 알림 아이콘을 표시하여 사용자에게 앱에서 데이터를 은밀하게 수집하지 않음을 알리는 것이 좋습니다.

앱에서 기능을 사용하기 위해 권한을 요청해야 하지만 사용자 입장에서 이유가 명확하지 않은 경우 가장 민감한 권한이 필요한 이유를 사용자에게 알릴 방법을 찾으세요.

두 가지 권한 모델 테스트

Android 6.0(API 레벨 23)부터 사용자는 앱을 설치하는 시점이 아닌 런타임 시 앱 권한을 부여하고 취소합니다. 따라서 다양한 조건에서 앱을 테스트해야 합니다. Android 6.0 이전에는 앱이 실행되면 앱 매니페스트에 선언된 모든 권한이 있다고 합리적으로 추측할 수 있었습니다. 그러나 Android 6.0부터는 사용자가 API 레벨 22 이하를 타겟팅하는 앱을 포함하여 모든 앱에서 권한을 허용하거나 중지할 수 있습니다. 그러므로 권한 부여 여부와 관계없이 앱이 정상적으로 작동하는지 테스트해야 합니다.

다음은 API 레벨 23 이상을 실행하는 기기에서 권한 관련 코드 문제를 찾는 데 도움이 되는 팁입니다.

  • 앱의 현재 권한 및 관련 코드 경로를 확인합니다.
  • 권한 보호 서비스 및 데이터 전반에서 사용자 플로우를 테스트합니다.
  • 부여되거나 취소된 권한의 다양한 조합을 테스트합니다. 예를 들어 카메라 앱의 매니페스트에는 CAMERA, READ_CONTACTS, ACCESS_FINE_LOCATION 권한이 나열되어 있을 수 있습니다. 이러한 권한을 하나씩 설정 및 해제한 상태로 앱을 테스트하여 앱이 모든 권한 구성을 정상적으로 처리할 수 있는지 확인해야 합니다.
  • adb 도구를 사용하여 명령줄에서 권한을 관리합니다.
    • 그룹별로 권한 및 상태를 나열합니다.
      $ adb shell pm list permissions -d -g
    • 하나 이상의 권한을 부여하거나 취소합니다.
      $ adb shell pm [grant|revoke] <permission-name> ...
  • 앱에서 권한을 사용하는 서비스를 분석합니다.

추가 리소스

참고자료

[1] Modeling Users’ Mobile App Privacy Preferences: Restoring Usability in a Sea of Permission Settings, - J. Lin B. Liu, N. Sadeh 및 J. Hong. SOUPS 2014 기록 참조.