매우 간단한 요구 사항을 구현하려고 했을 때 이미지를 다운로드하여 로컬 저장소에 저장합니다. — 처음에는 모든 것이 괜찮아 보였습니다.
- Honor(Android 10) – 작동함
- Redmi(Android 11) – 작동함
- 샤오미(안드로이드 13) - 작동함
- 삼성(안드로이드 13) – 완전히 실패했습니다. 저장소 권한 대화 상자가 전혀 표시되지 않았습니다.
동일한 코드, 동일한 기능이지만 Android 13의 한 기기는 권한 요청 메시지를 표시하지 않았습니다. 이렇게 해서 이 작은 "이미지 다운로드" 작업이 심층 분석으로 바뀌었습니다. 범위가 지정된 저장소 그리고 외부 저장소 관리.
이 게시물은 내가 저장 권한을 어떻게 조정했는지 요약합니다. 안드로이드 11 이상, 그리고 버전별로 다른 동작을 어떻게 처리하는지 알려드리겠습니다.
1. 버그: 저장 권한 대화 상자가 표시되지 않음(Samsung Android 13)
요구 사항은 간단합니다.
이미지를 다운로드해서 기기에 저장하면 갤러리에 표시됩니다.
세 개의 테스트 장치에서:
- Honor – 안드로이드 10 → OK
- 레드미 – 안드로이드 11 → 확인
- 샤오미 – 안드로이드 13 → 확인
하지만 안드로이드 13을 실행하는 삼성 기기, 시스템 저장 권한 대화 상자가 표시되지 않았습니다., 내가 어떻게 요청하든 상관없어요.



처음에는 이것이 단지 OEM의 또 다른 특성이라고 생각했지만, Android 버전 전체에서 저장소 권한 변경 사항을 확인한 후, SDK 33을 타겟으로 할 때 Android 13에서 사실상 더 이상 사용되지 않는 동작에 의존하고 있다는 것을 깨달았습니다.
2. 근본 원인: WRITE/READ_EXTERNAL_STORAGE는 Android 13(SDK 33)에서 더 이상 사용되지 않습니다.
이전 Android 버전에서는 매니페스트에서 다음 두 가지 권한을 간단히 선언할 수 있었습니다.
외부 저장소 읽기외부 저장소 쓰기
그리고 필요할 때 런타임에 요청합니다.
Android 13(SDK 33)에서 targetSdkVersion = 33, 그 접근 방식은 깨지기 시작합니다.
외부 저장소 쓰기~이다 더 이상 사용되지 않고 사실상 쓸모가 없음 최신 안드로이드 버전에서- 추가하면
최대 SDK 버전=32이러한 권한은 Android 11/12에서도 여전히 작동합니다.
하지만 그들은 무시하다 Android 13에서 33을 타겟팅할 때 - 동시에 Play Store에서는 새 앱이 최소 SDK 33을 타겟으로 해야 합니다.
따라서 Android 11 이상에서는 다음 사항에 적응해야 합니다.
- 범위가 지정된 저장소
- 그리고 어떤 경우에는 특별 허가가 필요합니다.
외부 저장소 관리
외부 저장소 관리 앱에 모든 공유 저장소 콘텐츠(비미디어 파일 포함)에 대한 광범위한 액세스 권한을 부여합니다. ~ 아니다 다른 앱의 비공개 디렉토리에 대한 접근을 허용하지만, Google Play에서는 여전히 매우 민감한 권한으로 간주됩니다.
다양한 Android 버전을 지원하기 위해 권한 처리를 다음과 같이 분할했습니다.
- Android 11 이전(API < 30) – 이전 스타일의 외부 저장소 권한
- 안드로이드 11 이상 – 범위 지정 저장소 + 특수 처리
외부 저장소 관리엄격히 필요한 경우
3. 단계별 적응
3.1 매니페스트에 MANAGE_EXTERNAL_STORAGE 선언
에서 AndroidManifest.xml:
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />⚠️ 참고: 왜냐하면
외부 저장소 관리민감한 권한이라 Google Play에서는 제한되어 있습니다. 이미지만 저장하려는 경우의 대안은 나중에 설명하겠습니다.
3.2 권한이 부여되었는지 확인
나는 사용했다 이지퍼미션 권한 확인을 간소화합니다.
개인 fun checkPer(활동: PreViewActivity): Boolean { Build.VERSION.SDK_INT >= 30인 경우를 반환합니다. EasyPermissions.hasPermissions(활동, android.Manifest.permission.MANAGE_EXTERNAL_STORAGE) } else { EasyPermissions.hasPermissions(활동, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) } }
- ~에 안드로이드 11 이상(API >= 30): 확인해요
외부 저장소 관리 - ~에 안드로이드 10 이하: 아직도 확인 중이에요
외부 저장소 쓰기
이 분할은 중요합니다. 외부 저장소 쓰기 더 이상 최신 버전에서처럼 동작하지 않습니다.
3.3 권한이 없을 때 권한 요청
권한이 부여되지 않으면 시스템 버전에 따라 다르게 요청합니다.
private fun requestStoragePermission(activity: PreViewActivity, curImg: Int) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // Android 11+ – 시스템 "모든 파일 액세스" 설정 페이지로 리디렉션 val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION) intent.data = Uri.parse("package:" + activity.packageName) activity.startActivityForResult(intent, 200) } else { // Android 10 이하 – 일반 런타임 권한 val perm = android.Manifest.permission.WRITE_EXTERNAL_STORAGE PaperThreeVariable.isToRequestPer = true EasyPermissions.requestPermissions( PermissionRequest.Builder( activity, 200, perm ).build() ) } }
- ~에 안드로이드 11 이상: 일반 런타임 대화 상자를 그냥 "팝업"할 수 없습니다.
외부 저장소 관리
사용자를 시스템 설정 페이지로 안내하여 수동으로 "모든 파일 액세스" 권한을 부여해야 합니다. - ~에 안드로이드 10 이하: 클래식 런타임 권한 대화 상자가 계속 작동합니다.
3.4 권한 콜백 처리
EasyPermissions는 Activity의 콜백과 자체 로직을 연결하는 데 도움이 됩니다.
onRequestPermissionsResult( requestCode: Int, permissions: Array)를 재정의합니다. , grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this) } override fun onPermissionsGranted(requestCode: Int, perms: MutableList ) { AppInitUtils().saveFreshAppImageToGallery(this, curImg) PaperThreeVariable.isToRequestPer = false } onPermissionsDenied(requestCode: Int, perms: MutableList)를 재정의합니다. ) { PaperThreeVariable.isToRequestPer = false if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) { AppSettingsDialog.Builder(this) .setRationale("이 함수를 활성화하려면 저장 권한이 필요합니다.") .setNegativeButton("아니요") .setPositiveButton("예") .build() .show() } }
내가 EasyPermissions를 사용하는 이유:
- 사용자는 할 수 있습니다 영구적으로 거부하다 반복되는 요청이 자동으로 실패하게 만드는 권한
- EasyPermissions를 사용하면 다음 작업을 더 쉽게 수행할 수 있습니다.
- "영구 거부" 상태 감지
- 사용자를 안내하는 대화 상자를 표시합니다. 시스템 설정 → 앱 권한 저장소 액세스를 수동으로 활성화하려면
허가가 내려지면 전화합니다.
AppInitUtils().saveFreshAppImageToGallery(이것, curImg)
실제로 이미지를 저장하고 갤러리를 새로 고칩니다.
이러한 적응 이후, 삼성 안드로이드 13 기기는 마침내 다른 기기와 동일하게 동작했습니다.
참고: 제 Xiaomi 기기는 Android 13으로 보고되었지만 Android Studio의 "연결된 이전 기기"에서는 Android 12로 인식했습니다. 이것이 어떤 경우에는 여전히 작동하는 이유를 설명할 수 있지만, 버전 기반 권한 처리가 중요한 이유는 바로 이 때문입니다.
4. MANAGE_EXTERNAL_STORAGE 및 Google Play 제한 사항에 관하여
외부 저장소 관리 강력하다:
읽기/쓰기 액세스 권한을 부여합니다. 모든 공유 스토리지 장치에서.
이로 인해 Google Play에서는 이를 다음과 같이 처리합니다. 매우 민감한 권한:
- 주로 다음을 위해 의도되었습니다. 파일 관리자 / 백업 / 바이러스 백신 앱 입력
- 사용하려면 정당한 사유를 제출해야 합니다.
- 앱이 일반적인 소비자용 앱(예: 이미지 저장, 간단한 다운로드)인 경우 요청은 다음과 같을 가능성이 높습니다. 거부됨
따라서 귀하의 유일한 요구 사항이 다음과 같다면:
“"갤러리에 이미지를 저장하고 사용자에게 표시합니다."”
그럼 당신은해야합니다 강력히 피하는 것을 고려하세요 외부 저장소 관리 그리고 대신:
- 사용 미디어스토어 시스템 미디어 라이브러리에 이미지를 삽입하려면
- 또는 전체 파일 액세스가 필요하지 않고 이미지를 저장할 수 있는 API를 사용하세요.
다음과 같은 여러 가지 패턴이 있습니다.
- 사진을 Pictures/DCIM 디렉토리에 저장합니다.
- 미디어 스캐너에 알리거나 MediaStore를 사용하여 갤러리에서 이를 선택할 수 있도록 합니다.
- 이 모든 것을 하세요 MANAGE_EXTERNAL_STORAGE를 요청하지 않고
내부 또는 Play 스토어 외 배포(예: 기업 내부 앱 스토어)의 경우 기술적으로 계속 사용할 수 있습니다. 환경.getExternalStorageDirectory(), 하지만 2025년에 이런 방식으로 새로운 앱을 디자인하는 것은 권장하지 않습니다.
5. 버전별 요약 (Android 9 → 13)
모든 내용을 한곳에 정리하기 위해, 외부 저장소와 권한이 여러 버전에 걸쳐 어떻게 동작하는지에 대한 간략한 요약을 소개합니다.
Android 9 이하(API 28 이하)
- 권한:
외부 저장소 읽기외부 저장소 쓰기
- 행동:
- 앱은 자유롭게 접근 가능
/SD카드및 하위 디렉토리 - 앱이 제거된 후에도 앱에서 생성된 파일은 기기에 남아 있습니다.
- 앱은 자유롭게 접근 가능
- 일반적인 접근 방식:
- 외부 저장소 경로에서 직접 읽기/쓰기
Android 10(API 29) - 범위 지정 저장소 도입
- 권한:
외부 저장소 읽기아직도 작동하다외부 저장소 쓰기여전히 존재하지만 효과적인 범위가 줄었습니다.
- 행동:
- 범위가 지정된 저장소 소개됩니다:
- 앱은 해당 앱별 디렉토리로 제한됩니다.
Android/데이터/귀하의 패키지 이름/ - 다른 앱의 파일에 대한 직접 액세스가 제한됩니다.
- 앱은 해당 앱별 디렉토리로 제한됩니다.
- 미디어 파일(이미지, 비디오, 오디오)은 다음을 통해 액세스해야 합니다. 미디어스토어
requestLegacyExternalStorage=true일시적으로 오래된 행동을 유지할 수 있습니다
(하지만 이 플래그는 Android 11부터 무시됩니다)
- 범위가 지정된 저장소 소개됩니다:
- 권장되는 접근 방식:
- 이미지/비디오/오디오의 경우: 사용 미디어스토어
- 개인 파일의 경우: 사용
getExternalFilesDir()또는getDataDir()
Android 11(API 30) – 범위 지정 저장소 적용
- 권한:
외부 저장소 읽기작동하지만 MediaStore에서 관리하는 미디어에만 해당외부 저장소 쓰기효과적으로 쓸모없는 일반 외부 저장소용외부 저장소 관리특별한 "모든 파일 액세스" 사용 사례에 도입됨
- 행동:
requestLegacyExternalStorage=true더 이상 작동하지 않습니다. 범위 지정 저장소는 항상 켜져 있음- 에 대한 접근
/SD카드/루트가 막혔습니다 - 앱은 다음만 가능합니다.
- 자신의 개인 디렉토리에 접근하세요
- 공유 미디어에 액세스하려면 다음을 사용하세요. 미디어스토어
- 권장되는 접근 방식:
- 일반적인 앱의 경우:
- MediaStore를 사용하거나 SAF (
문서 열기 작업,문서 생성 작업) 사용자가 선택한 파일의 경우
- MediaStore를 사용하거나 SAF (
- 고려만 하세요
외부 저장소 관리귀하의 앱이 실제로 파일 관리자, 백업 도구, 보안 앱 등이라면.
- 일반적인 앱의 경우:
Android 13(API 33) – 미디어 권한 분할
- 권한:
미디어 이미지 읽기– 이미지 접근미디어_비디오_읽기– 비디오에 접속하세요미디어 오디오 읽기– 오디오에 액세스
- 행동:
- 미디어 권한은 다음과 같습니다. 세밀한:
- 사용자는 이미지 접근만 허용하거나, 비디오 접근만 허용할 수 있습니다.
- Android 11의 범위 지정 저장소 규칙은 그대로 유지됩니다.
- 미디어 권한은 다음과 같습니다. 세밀한:
- 권장되는 접근 방식:
- 필요한 특정 미디어 권한을 요청하세요.
- 예를 들어, 이미지로만 작업하는 경우 다음만 요청하세요.
미디어 이미지 읽기
- 예를 들어, 이미지로만 작업하는 경우 다음만 요청하세요.
- 하다 ~ 아니다 요구
외부 저장소 읽기Android 13 이상에서는 새로운 미디어 권한으로 대체되므로
- 필요한 특정 미디어 권한을 요청하세요.
빠른 매트릭스(개념적)
- 안드로이드 9 이하
- 외부 저장소에 대한 액세스는 READ/WRITE_EXTERNAL_STORAGE로 제어되는 광범위한 액세스입니다.
- 안드로이드 10
- 스코프 스토리지가 도입되었지만 탈출구가 있습니다(
요청레거시외부저장소)
- 스코프 스토리지가 도입되었지만 탈출구가 있습니다(
- 안드로이드 11
- 범위 지정 저장소가 적용되고 레거시 스위치가 제거되었습니다.
외부 저장소 관리나타나지만 매우 제한적입니다
- 안드로이드 13
- 미디어 접근은 다음과 같이 분할됩니다.
미디어 읽기*권한 - 동일한 범위 지정 저장소 규칙이지만 더 세분화된 사용자 제어가 가능합니다.
- 미디어 접근은 다음과 같이 분할됩니다.
6. 테이크어웨이
- "한 Android 13 기기에서만 작동한다"고 해서 다른 모든 기기에서 작동한다는 뜻은 아닙니다. OEM과 시스템 보고서는 일관되지 않을 수 있습니다.
- 을 위한 안드로이드 11 이상, 다음과 같은 관점에서 생각해 보세요.
- 앱 개인 디렉토리 + MediaStore + SAF, "원시"가 아닙니다
/SD카드입장"”
- 앱 개인 디렉토리 + MediaStore + SAF, "원시"가 아닙니다
- 대하다
외부 저장소 관리로서 최후의 수단 매우 구체적인 앱 유형, 특히 Google Play에 게시할 계획이라면 더욱 그렇습니다. - 항상 테스트하세요 다양한 기기와 안드로이드 버전, 특히 권한과 저장과 관련된 경우에 그렇습니다.
이 글은 제가 실제 안드로이드 프로젝트(안드로이드 13을 탑재한 삼성 기기 포함)에서 직접 디버깅하고 수정한 내용을 바탕으로 작성되었습니다. GPT는 단지 번역과 표현 다듬기에 도움을 주었을 뿐이며, 모든 기술적 내용과 결정은 저에게 있습니다.


