Play 콘솔에서 사진·동영상 권한 때문에 앱이 거절되면 READ_MEDIA_IMAGES가 어디서 선언되는지부터 확인해야 합니다. Android 13 이상을 대상으로 하는 앱은 Photo Picker로 충분하면 이 권한을 매니페스트에서 제거해야 합니다. 아래에서 원인 가설을 하나씩 배제하는 순서를 보여 드립니다.
Play 사진 권한 거절은 왜 선언서 작성보다 매니페스트 확인이 먼저인가요
정책 문구가 요구하는 기본값은 "권한을 쓰는 이유를 설명하라"가 아니라 "피커로 충분하면 권한을 빼라"입니다. Play 지원 문서의 사진·동영상 권한 정책은 다음과 같이 적고 있습니다.
Apps that target Android 13 or later (API level 33+) may only request the READ_MEDIA_IMAGES and READ_MEDIA_VIDEO permissions if system pickers (like the Android Photo Picker), are not sufficient for your app to provide core functionality.
Android 13(API 33) 이상을 대상으로 하는 앱은 Android Photo Picker 같은 시스템 피커로 핵심 기능을 제공할 수 없을 때만 두 권한을 요청할 수 있다는 뜻입니다. 같은 문서의 일정 항목에는 "May 28, 2025: Full policy compliance is mandatory for all developers, including those who requested an extension."이라고 적혀 있어, 유예를 받았던 개발자도 2025-05-28 이후에는 제거 대상이 될 수 있습니다. 이 글의 확인 일시는 2026-10-06입니다.
가설 1: 갤러리 앱이 아니어도 선언서만 쓰면 통과하나요
통과 가능성은 낮은 가설입니다. 같은 문서는 "Apps whose core function includes managing and maintaining all of users' photos/videos (such as "gallery apps") would need broad access"라고 예시를 들고, 그 밖에는 "where the picker is not technically sufficient"인 경우를 말합니다. 프로필 사진 한 장 고르기, 게시글 첨부, 영수증 업로드는 피커로 충족되는 전형적인 사례입니다. 이런 앱이 선언서에 "사진 업로드 기능"이라고 쓰는 것은 정책 문구와 맞지 않습니다.
가설 2: 직접 만든 커스텀 갤러리 화면이라서 예외인가요
예외가 아닙니다. 정책 FAQ는 "Apps that have custom pickers are not automatically qualified to use the permission"이라고 답하며, Play 콘솔에서 Android Photo Picker로 부족한 이유를 선언해야 한다고 설명합니다. 앨범 탐색 UI를 직접 만들었다는 사실은 기술적으로 피커가 부족하다는 증명이 아닙니다.
가설 3: image_picker를 쓰니 내 앱에는 사진 권한이 없나요
플러그인 쪽은 깨끗합니다. 2026-10-06에 내려받은 image_picker_android의 AndroidManifest.xml에서 READ_MEDIA 검색 결과는 0건이었습니다. README에는 "On Android 16 and above, gallery image, video, and mixed-media picks always use the Android Photo Picker."라고 적혀 있고, Android 15 이하에서는 선택 기능으로 제공됩니다. 그러므로 image_picker만 사용한다면 권한을 선언한 주체는 플러그인이 아니라 앱 자체나 다른 의존성일 가능성이 큽니다.
이 판단은 제가 가장 먼저 의심하라고 권하는 지점입니다. 많은 분이 "라이브러리가 넣었겠지"라고 생각하고 선언서를 쓰거나 플러그인을 교체하지만, 먼저 확인할 곳은 내 앱의 android/app/src/main/AndroidManifest.xml입니다. permission_handler README는 미디어 접근에 READ_MEDIA_IMAGES를 쓰고 Permission.photos로 요청하라고 안내하므로, 문서를 따라 매니페스트에 한 줄을 추가해 둔 앱이 남아 있을 수 있습니다. 또한 photo_manager의 라이브러리 매니페스트는 READ_EXTERNAL_STORAGE를 maxSdkVersion="32"로만 선언하고 READ_MEDIA_*는 선언하지 않았습니다.
가설 4: 매니페스트에서 지웠는데 왜 아직 권한이 남아 있나요
병합 결과를 확인하지 않았기 때문일 수 있습니다. 앱 매니페스트에서 지워도 라이브러리 같은 다른 매니페스트가 같은 권한을 선언하면 병합 결과에는 남습니다. 공식 문서는 tools:node="remove"를 이렇게 설명합니다.
Remove this element from the merged manifest. Used when you discover an element in your merged manifest that you don't need that was provided by a lower-priority manifest file that's out of your control (such as an imported library).
가져온 라이브러리처럼 직접 통제할 수 없는 하위 우선순위 매니페스트가 넣은 요소를 병합 결과에서 제거할 때 쓴다는 뜻입니다. 앱 매니페스트에 xmlns:tools를 선언한 뒤 아래처럼 적용합니다. 자세한 규칙은 매니페스트 병합 공식 문서에서 확인할 수 있습니다.
<uses-permission
android:name="android.permission.READ_MEDIA_IMAGES"
tools:node="remove" />
<uses-permission
android:name="android.permission.READ_MEDIA_VIDEO"
tools:node="remove" />
어떤 순서로 확인하면 가설을 빨리 배제할 수 있나요
아래 표는 가설별 확인 명령과 판단 기준입니다. 명령은 앱 프로젝트 루트에서 실행하는 점검용 예시이며, 빌드 경로는 AGP 버전과 프로젝트 구성에 따라 다를 수 있습니다.
| 순서 | 확인 대상 | 명령 | 결과 해석 |
|---|---|---|---|
| 1 | 소스 매니페스트 | grep -rn READ_MEDIA android/app/src |
나오면 앱이 직접 선언한 것입니다. |
| 2 | 병합 결과 | find android/app/build -path '*merged_manifests*' -name AndroidManifest.xml | xargs grep -n READ_MEDIA |
소스에는 없는데 여기서만 나오면 의존성이 넣은 것입니다. |
| 3 | 업로드할 APK | aapt2 dump permissions app-release.apk |
Play에 올라가는 최종 권한 목록입니다. |
| 4 | 코드 사용처 | grep -rn "Permission.photos" lib |
피커 호출 전에 권한을 먼저 요청하는 코드가 있는지 봅니다. |
Photo Picker로 바꾸는 최소 수정은 무엇인가요
Flutter에서는 image_picker의 갤러리 선택만 호출하면 되고, 권한 요청 코드는 삭제합니다. Android 공식 문서는 PickVisualMedia 계약을 제공하며, 네이티브 코드는 아래와 같이 작성합니다.
// Flutter: 권한 요청 없이 갤러리 선택
final picker = ImagePicker();
final XFile? image = await picker.pickImage(source: ImageSource.gallery);
// Android 네이티브: READ_MEDIA_IMAGES 없이 사용
val pickMedia = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
// uri가 null이면 사용자가 선택하지 않은 것입니다.
}
pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
Photo Picker는 Android 11(API 30) 이상에서 사용할 수 있고, Android 4.4부터 10까지는 Google Play 서비스로 설치되는 백포트 버전이 있다고 Play 문서가 설명합니다. 선택한 항목만 앱에 전달되므로 앱은 전체 사진첩을 읽지 못합니다. Android 14의 부분 접근 변경은 공식 변경 문서에서 확인할 수 있습니다.
이 글의 설명은 무엇을 근거로 하나요
이 글의 설명은 2026-10-06 기준으로 확인한 Google Play 정책 문서, Android 매니페스트 병합 문서, image_picker_android·photo_manager 저장소의 매니페스트와 README, permission_handler README에 근거합니다. 패키지 버전은 pub.dev 기준 image_picker 1.2.3, image_picker_android 0.8.13+25, permission_handler 13.0.2입니다. 위 표의 확인 명령은 제가 앱 프로젝트에서 실행한 결과가 아니라 점검 절차로 제시하는 예시이므로, 프로젝트마다 빌드 경로가 다를 수 있습니다.
Play 사진 권한 거절에 대응하는 우선순위
우선순위는 병합 매니페스트 확인, 권한 제거와 피커 전환, 그래도 필요할 때만 선언서 순서입니다. 갤러리 관리처럼 정말 전체 접근이 핵심이라면 선언서에 피커로는 불가능한 기술적 이유를 구체적으로 적어야 합니다. 그렇지 않다면 권한 한 줄을 제거하는 쪽이 심사 대응도 사용자 신뢰도 쉽습니다. 같은 Play 정책 대응 흐름은 targetSdk 36 연장 현황과 compileSdk 37 요구 오류 글에서도 이어서 볼 수 있습니다.
참고 자료
'Android' 카테고리의 다른 글
| Play 지오펜싱 포그라운드 서비스 삭제 기한 2027년 1월 27일: Flutter 권한 점검 (0) | 2026.10.08 |
|---|---|
| Play READ_CONTACTS 연락처 권한 선언 요구: 2027년 1월 27일 전 Contact Picker 전환 판단 (0) | 2026.10.07 |
| Android compileSdk 37 요구 오류: AGP 9.1 없이 라이브러리만 올리면 빌드가 멈추는 이유 (0) | 2026.10.03 |
| Android 17 리플렉션 오류: 앱 크래시와 Espresso·Robolectric 테스트 실패 (1) | 2026.09.28 |
| Android Studio 업데이트 후 Gradle 오류: AGP 9.4·Gradle 9.6 맞추는 순서 (0) | 2026.09.26 |