갤러리에서 사진을 선택하는 작업은 앱에서 정말 많이 사용되는 작업입니다
그렇지만 앱에서 갤러리나 위치 등 개인 정보를 사용하려면 필수적으로 권한을 받아야 했는데요
권한 없이도 갤러리에 접근할 수 있는 방법이 있습니다
바로 Photo Picker 입니다!
포토피커를 사용하기 전에,
🤔 왜 권한을 받지 않게 되었을까요?
많은 사용자들이 앱이 어떤 파일에 접근할지 모르기 때문에 파일 및 미디어 권한이 귀찮다고 하였고,
이에 Android 13에서는 READ_EXTERNAL_STORAGE , WRITE_EXTERNAL_STORAGE 권한을 deprecated 시켰다고 합니다
이전에는 앱이 미디어 파일에 접근하기 위해서는 무조건 READ_EXTERNAL_STORAGE 권한을 요청했고
자체 미디어 선택 경험을 구현하려고 하니 개발자들에게 많은 부담이 되었으며 개발 및 유지보수에 많은 비용이 필요했다고 합니다
또는 ACTION_GET_CONTENT / ACTION_OPEN_CONTENT 를 통해 시스템이 기본적으로 제공하는 파일 선택기에 의존했지만 앱에 적합한 UX가 아니라는 의견이 많았다고 합니다
그래서 가급적 이미지, 동영상과 같은 미디어 파일에 대한 엑세스를 제공할때는 Photo Picker를 활용하는 것을 추천한다고 합니다!
추가적으로, Android 13부터 READ_EXTERNAL_STORAGE 권한은 deprecated 되었기 때문에 Android 13 이상 버전에서 권한 설정을 할 땐 세분화된 미디어 권한을 잘 체크해주어야 합니다
참고!
📷 Photo Picker란?
위에서 설명한 문제들 때문에 Android 13부터는 사용자가 미디어 라이브러리에 접근 권한을 허용하지 않아도 미디어 파일을 선택할 수 있도록 해주는 Photo Picker가 등장하게 되었습니다
Photo Picker는 문서 선택기 기능이 확장된 것인데요
(그래서 Photo Picker를 지원하지 않는 버전에선 기존의 문서 선택기가 등장합니다,,)
별도의 권한 요청이 없다는 것 이외에도 장점이 많습니다
우선 최근 날짜부터 오래된 날짜순으로 미디어를 정렬해주고
미디어 라이브러리 전체가 아닌 선택한 이미지 및 동영상에 대해서만 접근 권한을 부여하도록 합니다
또한 크게 Photos와 Albums 탭이 존재하여 Albums 탭에서는 카테고리 별로 유저가 탐색할 수 있도록 제공하며
기본적으로 바텀시트 기반의 UI로 되어있어 표준화된 내장 UI를 제공해줍니다
그리고 단일 선택, 다중 선택에 따라 분기해서 선택을 할 수도 있습니다!
(PickVisualMedia -> 단일 선택
PickMultipleVisualMedia -> 다중 선택)
그렇지만 한가지 단점은 Photo Picker는 Android 13 이상, Android 11, 12의 경우 SDK Extensions의 버전이 2 이상일 경우에만 지원이 가능하다는 것입니다
따라서 사용 전에 버전 체크를 해주어야 하는데요
✅ 지원 버전 확인하기
Android 13 이상, Android 11, 12의 경우 SDK EXtensions 버전이 2 이상일 경우에만 지원이 가능하기 때문에
isPhotoPickerAvailble() 함수를 이용해 지원 버전을 확인해줍니다
private fun isPhotoPickerAvailable(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
true
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
getExtensionVersion(Build.VERSION_CODES.R) >= 2
} else {
false
}
}
위 코드를 확인해보면
1. TIRAMISU 버전 (SDK33) 이상, REDVELVET CAKE 버전 (SDK 30) 이상에서는 SDK Extension 버전이 2 이상일 경우에 Photo Picker를 지원,
2. 이외의 하위 버전에서는 Photo Picker를 호출해도 기존의 문서 선택기가 호출됩니다
(이때는 다중 선택에서 설정한 미디어 선택 최대 개수가 무시됩니다)
그렇지만 30 미만을 지원해야 하는 경우에도 방법이 있는데요
바로 백포팅입니다
Android 4.4(API 수준 19)~Android 10(API 수준 29)을 실행하는 이전 기기와 Google Play 서비스를 지원하는 Android 11 또는 12를 실행하는 Android Go 기기에는 사진 선택 도구의 백포팅 버전을 설치하면 됩니다. Google Play 서비스를 통해, 백포팅된 사진 선택 도구 모듈의 자동 설치를 사용 설정하려면 앱의 매니페스트 파일에서 <application> 태그에 다음 항목을 추가하세요.
<!-- Trigger Google Play services to install the backported photo picker module. -->
<service android:name="com.google.android.gms.metadata.ModuleDependencies"
android:enabled="false"
android:exported="false"
tools:ignore="MissingClass">
<intent-filter>
<action android:name="com.google.android.gms.metadata.MODULE_DEPENDENCIES" />
</intent-filter>
<meta-data android:name="photopicker_activity:0:required" android:value="" />
</service>
위 코드를 manifest의 application 태그에 추가해주면 30 미만도 지원이 가능하다고 합니다
(그런데 제가 했을 땐 Unresolved package 'metadata' 코드 상에서 에러가 발생했는데요,
컴파일 단계에선 해당 파일을 찾을 수 없다고 에러가 발생한 것처럼 보였는데
런타임 때는 해당 파일이 제자리에 있어서 빌드 시엔 에러 없이 실행되었습니다
왜 그럴까요..? 혹시 아시는 분 있으면 댓글,, 부탁드립니다)
👩🏻💻 사용 방법
1. 위에 있는 isPhotoPickerAvailble() 함수를 이용해 지원 버전 확인
2. 미디어 파일 단일 선택 (PickVisualMedia)
// 하나의 미디어 파일만 선택할 때
val pickMedia = registerForActivityResult(PickVisualMedia()) { uri ->
if (uri != null) {
// 미디어 파일 선택한 경우
Log.d("PhotoPicker", "Selected URI: $uri")
} else {
// 미디어 파일을 선택하지 않은 경우
Log.d("PhotoPicker", "No media selected")
}
}
// 이미지와 비디오 모두 선택
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageAndVideo))
// 이미지만 선택
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))
// 비디오만 선택
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.VideoOnly))
// 설정한 type만 선택 가능, ex) .gif
val mimeType = "image/gif"
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.SingleMimeType(mimeType)))
단일 선택의 경우 PickVisualMedia()를 활용하고
갤러리에서 파일 선택 후 돌아와 가공해야 하기 때문에 registerForActivityResult를 활용해 콜백 형식으로 구현합니다
PickVisualMediaRequest() 메소드에 VisualMediaType을 파라미터로 전달하면 해당 타입의 미디어들만 필터링되어 제공해줍니다
제공해주는 VisualMediaType은 ImageAndVideo, ImageOnly, VideoOnly, SingleMimeType(val mimeType)으로 4가지 입니다
(이는 다중 선택에서도 똑같이 제공해줍니다!)
위 이미지와 같이 단일 선택은 기본적으로 Half Expanded로 바텀시트가 절반만 차지하는 형태로 열리게 됩니다
3. 미디어 파일 다중 선택 (PickMultipleVisualMedia)
// 미디어 다중 선택
val pickMultipleMedia =
registerForActivityResult(PickMultipleVisualMedia(5)) { uris ->
if (uris.isNotEmpty()) {
// 파일을 선택한 경우
Log.d("PhotoPicker", "Number of items selected: ${uris.size}")
} else {
// 파일을 선택하지 않은 경우
Log.d("PhotoPicker", "No media selected")
}
}
pickMultipleMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageAndVideo))
다중 선택의 경우 PickMultipleVisualMedia()를 활용하며 파일 갯수 제한을 위해
PickMultipleVisualMedia()에 원하는 파일의 개수(maxItems)를 전달해줍니다
이때 maxItems는 무조건 1 보다 큰 수를 주어야 합니다
(위 코드의 init 부분 확인!)
다중 선택 시엔 바텀시트가 Expanded 된 상태로 화면의 전체를 차지하게 되고
설정해놓은 maxItems 이상 이미지를 선택하려고 하면 최대 선택 가능 스낵바가 뜨며 설정한 개수 이상 선택이 불가능 합니다
4. 미디어 파일 액세스 유지
보통 Android에서는 앱이 멈추기 전까지만 파일에 접근할 수 있는 권한을 부여하는데요
앱이 종료된 후에도 계속 파일 접근이 필요한 경우 (ex. 대용량 파일 업로드 등 장기 실행 작업) 에는 takePersistableUriPermission()을
호출해서 사용하면 됩니다
val flag = Intent.FLAG_GRANT_READ_URI_PERMISSION
context.contentResolver.takePersistableUriPermission(uri, flag)
🍀 정리
사실 저는 사진 개수 제한을 위한 방법을 찾다가 Photo Picker를 알게 되었는데요
권한 없이 갤러리 접근부터 다양한 파일 지원까지 장점이 정말 많은 것 같습니다
평소에 버전 별 권한 분기 할때마다 머리가 아팠는데 유용하게 사용할 수 있을 것 같습니다
Android 13 이상부터 지원 가능하다는 점이 조금 아쉽지만..!
모두들 Photo Picker 하세요 :)
📚 참고 자료
https://developer.android.com/training/data-storage/shared/photopicker?hl=ko
사진 선택 도구 | Android Developers
DataStore offers a more modern way of storing local data. You should use DataStore instead of SharedPreferences. Read the DataStore guide for more information. 이 페이지는 Cloud Translation API를 통해 번역되었습니다. 사진 선택 도구 컬
developer.android.com
https://developer.android.com/about/versions/13/behavior-changes-13?hl=ko#granular-media-permissions
동작 변경사항: Android 13 이상을 타겟팅하는 앱 | Android Developers
Android 13 이상을 타겟팅하는 앱에 영향을 미치는 Android 13의 변경사항을 알아봅니다.
developer.android.com
https://medium.com/androiddevelopers/permissionless-is-the-future-of-storage-on-android-3fbceeb3d70a
Permissionless is the future of Storage on Android
Whether it’s to change a profile avatar, share vacation pictures, or add an attachment to an email, selecting and sharing media files are…
medium.com
'Android' 카테고리의 다른 글
[Android] 앱 배포하기04_ AAB 파일 만들기 (0) | 2024.09.04 |
---|---|
[Android] 앱 배포하기03_ Proguard로 코드 난독화하기 (1) | 2024.09.02 |
[Android] 앱 배포하기02_ 안드로이드 스튜디오 Release build (0) | 2024.08.28 |
[Android] 앱 배포하기01_ 안드로이드 스튜디오에서 APK 서명 키 만들기 (0) | 2024.08.27 |
[Android] 액티비티 생명주기 (Activity Lifecycle) (0) | 2023.10.04 |