웹뷰 기반 안드로이드 앱에서 사용자가 사진을 여러 장 선택해 업로드할 수 있도록 기능을 제공했다. 그런데 갤럭시 S21, 안드로이드 15에서 기본 갤러리 앱을 사용할 때, 여러 장 선택이 불가능하고 1장만 선택되는 문제가 있었다. 다른 사진 앨범 앱에서는 다중 선택이 됐다. 코드 레벨이나 기기 문제라기보다 삼성 기본 갤러리 앱 자체의 동작 방식 차이 로 추정했다.
문제 상황
안드로이드의 웹뷰에서 WebChromeClient의 onShowFileChooser 콜백을 구현해 파일 선택 인텐트를 실행한다. 보통 갤러리 사진을 선택하게 유도할 때 아래와 같이 Intent.ACTION_PICK을 많이 사용한다.
// 갤러리 인텐트 설정
val contentSelectionIntent = Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
)
contentSelectionIntent.type = MediaStore.Images.Media.CONTENT_TYPE
if (isMultiple) {
contentSelectionIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
}
하지만 삼성 갤러리 앱은 ACTION_PICK 인텐트를 처리할 때 Intent.EXTRA_ALLOW_MULTIPLE 옵션을 무시하는 경우가 많다. 이로 인해 사용자는 여러 장을 드래그하거나 선택할 수 없고 단일 이미지만 선택할 수밖에 없게 된다.
앱의 사진 선택 버튼에서 기본 갤러리로 이동할 수는 있었지만, 갤러리 화면에는 여러 항목을 고르는 상태가 나타나지 않았다. 실제 제품 화면과 사진은 제외하고 앱 선택 단계와 단일 선택 상태만 남겼다.
해결 과정
1. ACTION_GET_CONTENT 사용 권장
안드로이드 공식 문서와 커뮤니티에서는 파일 다중 선택을 위해 ACTION_PICK보다는 Intent.ACTION_GET_CONTENT를 사용할 것을 권장한다. 파일 종류나 개수에 상관없이 콘텐츠를 가져오는 안드로이드 표준 방식이기 때문에 호환성이 더 높다.
ACTION_GET_CONTENT에서는 시스템 콘텐츠 선택기를 거쳐 사진 앱이나 파일 앱을 선택할 수 있고, 선택기에서 여러 항목을 고를 수 있다. 하지만 곧바로 갤러리가 열리기보다 '파일' 앱들이 먼저 뜨는 경우가 많아 UX 측면에서 불편할 수는 있다.
stackoverflow.com
Trying To Pick images From Samsung's Gallery
I want to give to user the option to pick multiple images. This is my code in order to let the user choose the wanted gallery and pick images from there: public void pickImages() { Intent
github.com
Multiple selection is not available from Samsung Gallery application (Samsung Galaxy Android) · Issue #846 · miguelpruivo/flutter_file_picker
Before creating an issue, make sure that you are on the latest file_picker version and that there aren't already any similar opened inssues. Also, check if it isn't described on the Wiki, specially...
2. 삼성 갤러리 비공식 옵션 적용
삼성 갤러리에서 다중 선택을 강제하기 위한 비공식 파라미터를 추가할 수 있다.
if (isMultiple) {
contentSelectionIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
// 삼성 디바이스 호환성을 위한 추가 설정
contentSelectionIntent.putExtra("multi-pick", true)
contentSelectionIntent.putExtra("return-data", false)
}
이렇게 multi-pick 파라미터를 명시하니까 다중 선택이 가능했었다.
github.com
Multiple selection is not available from Samsung Gallery application (Samsung Galaxy Android) · Issue #846 · miguelpruivo/flutter_file_picker
Before creating an issue, make sure that you are on the latest file_picker version and that there aren't already any similar opened inssues. Also, check if it isn't described on the Wiki, specially...
응답(Result) 파싱 규격 대응
여기서 주의할 점이 있다. multi-pick 옵션으로 응답을 받으면 안드로이드 표준 규격인 ClipData가 아니라, 마치 파일을 공유하는 것처럼 ACTION_SEND_MULTIPLE 형태의 독자적인 규격으로 데이터가 넘어온다.
// standard
😀 registerForActivityResult 콜백 ActivityResult{resultCode=RESULT_OK, data=Intent { dat=content://com.google.android.apps.photos.contentprovider/-1/1/content://media/external/images/media/63/ORIGINAL/NONE/image/jpeg/89489492 flg=0x1 clip={text/uri-list U:content://com.google.android.apps.photos.contentprovider/-1/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F63/ORIGINAL/NONE/image%2Fjpeg/89489492} }}
// samsung multi pic
😀 registerForActivityResult 콜백 ActivityResult{resultCode=RESULT_OK, data=Intent { act=android.intent.action.SEND_MULTIPLE flg=0x1 (has extras) }}
10:21:06.813 D ----------------- Extras Dump -----------------
10:21:06.814 D Key: selectedCount, Value: 4, Value Type: java.lang.Integer
10:21:06.815 D Key: selectedItems, Value: [content://media/external/images/media/62, ...], Value Type: java.util.ArrayList
10:21:06.815 D ---------------------------------------------
디버깅을 위해 응답 인텐트의 extras를 덤프떠서 확인해봤다. selectedItems라는 키에 Uri 목록이 담겨서 반환되므로, onActivityResult나 registerForActivityResult 콜백에서 이 분기를 별도로 처리해야 한다.
val SAMSUNG_MULTI_PICK_KEY = "selectedItems"
// 1. 안드로이드 표준 규격 처리
if (data.clipData != null) {
// ClipData에서 URI 추출
}
// 2. 삼성 갤러리 독자 규격 처리
else if (data.hasExtra(SAMSUNG_MULTI_PICK_KEY)) {
val uris = mutableListOf<Uri>()
// API 33(Tiramisu) 이상과 미만 호환성 분기
val parcelableUris = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
data.getParcelableArrayListExtra(SAMSUNG_MULTI_PICK_KEY, Uri::class.java)
} else {
@Suppress("DEPRECATION")
data.getParcelableArrayListExtra(SAMSUNG_MULTI_PICK_KEY)
}
parcelableUris?.let {
uris.addAll(it)
}
// 웹뷰 콜백으로 Uri 배열 반환
filePathCallbackLollipop?.onReceiveValue(uris.toTypedArray())
filePathCallbackLollipop = null
}
이와 같이 삼성 전용 파라미터와 결과 처리 로직을 추가하면 기본 갤러리 앱에서도 다중 선택 기능을 온전히 제공할 수 있다.