안드로이드 6.0 - 권한 관리 문제

안드로이드 6.0(마쉬멜로우) 버전이 배포된지 10개월이 지났지만, 아직도 많은 애플리케이션이 마쉬멜로우의 새로운 기능들을 지원하지 못하고 있다. 여러 사유가 있겠지만, 영향을 미치는 원인 중 하나는 새로운 기능들에 대응할 여력이 부족하기 때문일 것이다. 그 중 대표적인 기능인 권한(Permission) 이슈에 대해 정리해보았다.

2016. 08. 17.

안드로이드 6.0(마쉬멜로우) 버전이 배포된지 10개월이 지났지만, 아직도 많은 애플리케이션이 마쉬멜로우의 새로운 기능들을 지원하지 못하고 있다. 이는 두나무의 카카오증권 앱도 마찬가지이며, 비교적 최근까지도 타깃 SDK 버전이 21에서 벗어나지 못하고 있었다.

여러 사유가 있었지만, 가장 영향을 크게 미쳤던 것은 타깃 SDK를 23 이상으로 업데이트하면서 생기는 새로운 기능들에 대응할 여력이 부족했기 때문이다. 그 중 대표적인 이유인 권한(Permission) 이슈에 대해 정리해보았다.

Dangerous Permissions

6.0 업데이트 이후, 안드로이드는 권한 관리에 대해 매우 깐깐해졌다. 특히 메시지나 카메라 등의 민감 정보에 접근하는 권한은 Dangerous Permissions(위험 권한)이라는 등급으로 분류되었는데, 이들 권한은 다음과 같은 특징을 가진다.

  • 사용자가 애플리케이션 설정에서 권한을 끄고 켤 수 있다.
  • 권한이 필요한 기능을 사용하는 시점에 사용자로부터 권한을 승인받는다.

아이폰과 유사한 보안 정책으로 변경되었다. 기존에는 단순히 앱 설치 시점에 모든 권한을 승인해왔던 만큼, 새로운 정책으로 인해 발생할 수 있는 예외적 시나리오에 대한 충분한 검토와 테스트가 필요하다.

상황 예시

사용자가 권한이 필요한 기능을 처음 사용하는 경우

예를 들어, 어떤 앱에서 문자 메시지 읽어오기 권한이 필요한 기능을 처음 사용하는 경우 "○○○ 앱이 메시지 접근 권한을 요청합니다" 등의 메시지가 뜨게 된다.

스크린샷 1

시스템 앱임에도 번역에 문제가 많다...

위 스크린샷처럼 요청 화면에는 거부 / 허용 버튼이 있으며, "다시 묻지 않음" 옵션이 존재한다. 거부 버튼을 누르면 당연히 해당 권한이 필요한 기능은 동작하지 않는다. 이러한 경우 다행히도 크래시는 발생하지 않으며, 예외 처리는 가능하다.

사용자가 "다시 묻지 않음"을 선택 후 권한 요청을 거부했을 경우

개발자의 입장에서는 꽤나 번거로운 상황이다. 권한 요청을 위해 사용하는 ActivityCompat.requestPermissions() 를 호출해도, onRequestPermissionsResult() 에서 PERMISSION_DENIED를 반환하며 더 이상 권한을 요청 다이어로그를 띄우지 않는다. 이런 경우 사용자가 설정 화면에서 다시 허용하지 않는 이상 해당 기능은 사용이 불가능하다.

다행히도 권한 요청이 거부되었음을 확인 후 설정 화면으로 이동하는 것은 아래와 같이 구현 가능하다.

Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
        .setData(Uri.parse("package:" + context.getPackageName()));
context.startActivity(intent);

고려해야할 점

각각의 권한을 어떤 시점에 요청할 것인가?

이러한 런타임 권한의 최대 장점은 해당 권한이 필요한 시점에만 끄고 켤 수 있다는 점이다. 개발적으로는 모든 권한을 앱을 실행할 때 승인받는 것이 가장 간단하겠지만, 이는 유저에게 불쾌감을 선사할 수 있으며 런타임 권한의 존재 의의를 생각하면 별로 좋지 않은 방식이기도 하다.

때문에 권한을 요청하는 시점을 UX에 잘 녹이는 것은 중요한 일이다. 가장 권장하는 방법은 권한이 필요한 화면에 접근할 때 요청하는 것이지만, UX가 너무 부자연스럽다면 어느 정도 조절하는 것도 무방하다고 본다.

권한 획득 플로우

안드로이드에서 기본적으로 지원하는 메소드는 여러가지 불편한 점이 많기 때문에, 직접 권한을 관리하는 유틸리티를 구현하는 편을 추천한다. 대략 아래와 같은 분기 작업이 필요할 것이다.

  1. SDK 버전이 23 미만일 경우 → 무조건 작업 실행
  2. 권한 승인 여부 확인 후 허용되어있다면 → 작업 실행
  3. requestPermissions()를 통해 권한 요청 후 onRequestPermissionsResult()에서 권한 허용을 확인했다면 → 작업 실행
  4. onRequestPermissionsResult()에서 권한 거부를 확인했다면 → 권한이 필요한 이유를 유저에게 설명한 후 설정 화면으로 이동

런타임 권한은 아니지만 유저가 거부 가능한 권한

또 다른 예외로, 런타임 권한은 아니지만 유저가 설정에서 거부 가능한 권한이 존재한다.

스크린샷 2

이들 권한은 지금까지 설명했던 런타임 권한 로직으로는 처리가 불가능하며, 각각 아래와 같이 개별적으로 구현해야만 한다.

SYETEM_ALERT_WINDOW

설정 화면에서의 '다른 앱 위에 그리기'에 해당하는 것으로, 이름 그대로 모든 앱들의 최상단에 자신의 앱을 띄울 수 있도록 하는 권한이다. 주로 팝업 창 등을 띄울 때 사용된다.

아래와 같은 방식으로 설정 화면으로 유도하는 것이 가능하다.

Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
startActivity(intent);

해당 권한을 허용했는지에 대한 확인은 다음의 메소드로 확인이 가능하다.

Settings.canDrawOverlays()

WRITE_SETTINGS

설정 화면에서의 '시스템 설정 수정'에 해당하는 권한이다. 마찬가지로 아래와 같은 방식으로 설정 화면으로 유도하는 것이 가능하다.

Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
startActivity(intent);

권한의 허용 여부는

Settings.System.canWrite()

메소드를 통해 확인할 수 있다.

만약 위의 두 권한이 필요한 로직이 존재한다면, 위 메소드를 적절한 위치에 삽입하여 제대로 작동하는지 확인해야할 필요가 있다.

크리에이티브 커먼즈 라이선스

이 저작물은 크리에이티브 커먼즈 저작자표시-동일조건변경허락 4.0 국제 라이선스에 따라 이용할 수 있습니다.

© 2011 - 2020 Do Hoerin, LYnLab