사진 및 동영상에 대한 일부 액세스 권한 부여

Android 14에서는 사용자가 앱에 권한을 부여할 수 있는 선택된 사진 액세스 권한을 도입합니다. 특정 이미지 및 동영상에 대한 액세스 권한을 Google에 부여하는 대신 모든 미디어에 액세스할 수 있습니다.

이 변경사항은 앱이 Android 14 (API 수준 34) 또는 더 높습니다. 아직 사진 선택 도구를 사용하지 않는 경우 이미지 및 동영상을 선택하는 데 일관된 환경을 제공합니다. 또한 스토리지를 요청하지 않고도 사용자 개인 정보 보호를 강화합니다. 권한을 부여할 수 있습니다

저장소 권한을 사용하여 자체 갤러리 선택 도구를 유지관리하고 있으며 앱 구현을 완벽하게 제어하고 구현을 조정하세요. 새 READ_MEDIA_VISUAL_USER_SELECTED 권한을 사용해야 합니다. 앱이 앱이 새 권한을 사용하지 않으면 시스템은 호환성 환경에서 앱을 실행합니다. 모드로 설정합니다.

타겟 SDK READ_MEDIA_VISUAL_USER_SELECTED개 선언됨 선택한 사진 액세스 사용 설정됨 UX 동작
SDK 33 아니요 아니요 해당 사항 없음
앱에서 제어
SDK 34 아니요 시스템에 의해 제어(compat 동작)
앱에서 제어

자체 갤러리 선택 도구를 만들려면 광범위한 개발 및 유지보수가 필요합니다. 앱이 명시적인 사용자 동의를 얻기 위해 저장소 권한을 요청해야 합니다. 사용자는 이러한 요청을 거부할 수 있습니다. 또는 앱이 Android 14 및 앱이 Android 14 (API 수준 34) 이상을 타겟팅함 선택한 미디어에 액세스할 수 없습니다. 다음 이미지는 미디어를 선택하는 방법을 보여줍니다.

<ph type="x-smartling-placeholder">
</ph> .
그림 1. 새 대화상자를 통해 사용자는 특정 대화 상자를 사진과 동영상뿐만 아니라 전체 액세스 권한을 부여하거나 모든 액세스를 거부할 수 있습니다.

이 섹션에서는 자체 갤러리를 만드는 데 권장되는 방법을 보여줍니다. MediaStore를 사용하여 선택 도구 이미 앱의 갤러리 선택 도구를 유지관리하는 경우 완벽하게 관리해야 하는 경우 이 예를 사용하여 있습니다. 선택한 이벤트를 처리하기 위해 구현을 업데이트하지 않는 경우 사진 액세스가 있으면 시스템에서 앱을 호환성 모드로 실행합니다.

권한 요청

먼저 Android 매니페스트에서 올바른 저장소 권한을 요청합니다. 선택합니다.

<!-- Devices running Android 12L (API level 32) or lower  -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />

<!-- Devices running Android 13 (API level 33) or higher -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

<!-- To handle the reselection within the app on devices running Android 14
     or higher if your app targets Android 14 (API level 34) or higher.  -->
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />

그런 다음 OS 버전에 따라 올바른 런타임 권한을 요청합니다.

// Register ActivityResult handler
val requestPermissions = registerForActivityResult(RequestMultiplePermissions()) { results ->
    // Handle permission requests results
    // See the permission example in the Android platform samples: https://github.com/android/platform-samples
}

// Permission request logic
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
    requestPermissions.launch(arrayOf(READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_VISUAL_USER_SELECTED))
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
    requestPermissions.launch(arrayOf(READ_MEDIA_IMAGES, READ_MEDIA_VIDEO))
} else {
    requestPermissions.launch(arrayOf(READ_EXTERNAL_STORAGE))
}

일부 앱은 권한이 필요하지 않음

Android 10 (API 수준 29)부터 앱은 스토리지 권한이 없어도 파일을 공유 저장장치에 저장할 수 있습니다. 즉, 앱이 갤러리에 이미지를 추가할 수 있습니다. 동영상을 녹화하여 공유 저장장치에 저장하거나 Google Cloud Storage를 사용하지 않습니다 앱이 공유 폴더에만 파일을 추가하는 경우 이미지나 동영상을 쿼리하지 않는 경우 권한을 부여하고 AndroidManifest.xml에서 maxSdkVersion를 API 28로 설정합니다.

<!-- No permission is needed to add files to shared storage on Android 10 (API level 29) or higher  -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="28" />

미디어 재선택 처리

Android 14의 선택된 사진 액세스 기능을 사용하면 앱이 미디어를 제어하는 새 READ_MEDIA_VISUAL_USER_SELECTED 권한 사용자가 앱에 액세스 권한을 부여할 수 있도록 앱 인터페이스를 업데이트하세요. 다양한 이미지와 동영상에 광고를 게재할 수 있습니다 다음 이미지는 권한 요청 및 미디어 다시 선택:

<ph type="x-smartling-placeholder">
</ph> .
그림 2. 또한 새 대화상자에서는 사용자가 사진과 동영상을 제공할 수 있습니다.
를 통해 개인정보처리방침을 정의할 수 있습니다.

선택 대화상자를 열면 다음에 따라 사진, 동영상 또는 둘 다 표시됩니다. 권한을 부여할 수 있습니다 예를 들어 READ_MEDIA_IMAGES 권한이 없는 READ_MEDIA_VIDEO 권한만 사용자가 파일을 선택할 수 있도록 UI에 동영상이 표시됩니다.

// Allow the user to select only videos
requestPermissions.launch(arrayOf(READ_MEDIA_VIDEO, READ_MEDIA_VISUAL_USER_SELECTED))

앱의 기기 액세스 권한이 전체, 부분 또는 거부되었는지 확인할 수 있습니다. 적절하게 인터페이스를 업데이트하세요. 다음 권한 요청 저장공간 액세스가 필요할 때) 명심하세요. 권한 부여는 onStartonResume 앱 간에 변경할 수 있습니다. 사용자가 별도의 설정 없이 설정에서 액세스를 변경할 수 있기 때문에 수명 주기 콜백에 앱을 종료할 수 있습니다

if (
    Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
    (
        ContextCompat.checkSelfPermission(context, READ_MEDIA_IMAGES) == PERMISSION_GRANTED ||
        ContextCompat.checkSelfPermission(context, READ_MEDIA_VIDEO) == PERMISSION_GRANTED
    )
) {
    // Full access on Android 13 (API level 33) or higher
} else if (
    Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE &&
    ContextCompat.checkSelfPermission(context, READ_MEDIA_VISUAL_USER_SELECTED) == PERMISSION_GRANTED
) {
    // Partial access on Android 14 (API level 34) or higher
}  else if (ContextCompat.checkSelfPermission(context, READ_EXTERNAL_STORAGE) == PERMISSION_GRANTED) {
    // Full access up to Android 12 (API level 32)
} else {
    // Access denied
}

기기 라이브러리 쿼리

적절한 저장용량 권한에 액세스할 수 있는지 확인한 후에는 다음을 수행할 수 있습니다. MediaStore와 상호작용하여 기기 라이브러리를 쿼리합니다 (동일한 접근 방식이 작동함). 부분 또는 전체 액세스)에 따라 달라집니다.

data class Media(
    val uri: Uri,
    val name: String,
    val size: Long,
    val mimeType: String,
)

// Run the querying logic in a coroutine outside of the main thread to keep the app responsive.
// Keep in mind that this code snippet is querying only images of the shared storage.
suspend fun getImages(contentResolver: ContentResolver): List<Media> = withContext(Dispatchers.IO) {
    val projection = arrayOf(
        Images.Media._ID,
        Images.Media.DISPLAY_NAME,
        Images.Media.SIZE,
        Images.Media.MIME_TYPE,
    )

    val collectionUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        // Query all the device storage volumes instead of the primary only
        Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL)
    } else {
        Images.Media.EXTERNAL_CONTENT_URI
    }

    val images = mutableListOf<Media>()

    contentResolver.query(
        collectionUri,
        projection,
        null,
        null,
        "${Images.Media.DATE_ADDED} DESC"
    )?.use { cursor ->
        val idColumn = cursor.getColumnIndexOrThrow(Images.Media._ID)
        val displayNameColumn = cursor.getColumnIndexOrThrow(Images.Media.DISPLAY_NAME)
        val sizeColumn = cursor.getColumnIndexOrThrow(Images.Media.SIZE)
        val mimeTypeColumn = cursor.getColumnIndexOrThrow(Images.Media.MIME_TYPE)

        while (cursor.moveToNext()) {
            val uri = ContentUris.withAppendedId(collectionUri, cursor.getLong(idColumn))
            val name = cursor.getString(displayNameColumn)
            val size = cursor.getLong(sizeColumn)
            val mimeType = cursor.getString(mimeTypeColumn)

            val image = Media(uri, name, size, mimeType)
            images.add(image)
        }
    }

    return@withContext images
}

다음 코드 스니펫은 MediaStore와 상호작용하는 방법을 설명하기 위해 단순화한 것입니다. 프로덕션에 즉시 사용할 수 있는 앱에서는 Paging 라이브러리를 사용하여 성능을 향상할 수 있습니다.

마지막 선택 항목 쿼리

Google Play 시스템 업데이트를 지원하는 Android 15 이상 및 Android 14의 앱은 부분 액세스 시 사용자가 마지막으로 선택한 이미지 및 동영상 쿼리 QUERY_ARG_LATEST_SELECTION_ONLY를 사용 설정하여 다음을 실행합니다.

if (getExtensionVersion(Build.VERSION_CODES.U) >= 12) {
    val queryArgs = bundleOf(
        QUERY_ARG_SQL_SORT_ORDER to "${Images.Media.DATE_ADDED} DESC"
        QUERY_ARG_LATEST_SELECTION_ONLY to true
    )

    contentResolver.query(collectionUri, projection, queryArgs, null)
}

기기가 업그레이드될 때 사진 및 동영상 액세스 권한이 유지됨

앱이 이전 Android 버전에서 Android 14로 업그레이드되는 기기에 있는 경우 시스템은 사용자의 사진과 동영상에 대한 전체 액세스 권한을 유지하며 앱에 일부 권한을 자동으로 부여합니다. 정확한 동작은 기기가 Android 14로 업그레이드되기 전에 앱에 부여되는 권한 집합에 따라 다릅니다.

Android 13의 권한

다음 상황을 고려해보세요.

  1. 앱이 Android 13을 실행하는 기기에 설치되어 있습니다.
  2. 사용자가 앱에 READ_MEDIA_IMAGES 권한과 READ_MEDIA_VIDEO 권한을 부여했습니다.
  3. 그런 다음 기기가 앱이 여전히 설치되어 있는 동안 Android 14로 업그레이드됩니다.
  4. 앱에서 Android 14 (API 수준 34) 이상을 타겟팅하기 시작합니다.

이 경우에도 앱은 사용자의 사진 및 동영상에 대한 전체 액세스 권한을 보유합니다. 시스템도 앱에 부여된 READ_MEDIA_IMAGESREAD_MEDIA_VIDEO 권한을 자동으로 유지합니다.

Android 12 이하 권한

다음 상황을 고려해보세요.

  1. 앱이 Android 13을 실행하는 기기에 설치되어 있습니다.
  2. 사용자가 앱에 READ_EXTERNAL_STORAGE 권한 또는 WRITE_EXTERNAL_STORAGE 권한을 부여했습니다.
  3. 그런 다음 기기가 앱이 여전히 설치되어 있는 동안 Android 14로 업그레이드됩니다.
  4. 앱에서 Android 14 (API 수준 34) 이상을 타겟팅하기 시작합니다.

이 경우에도 앱은 사용자의 사진 및 동영상에 대한 전체 액세스 권한을 보유합니다. 시스템도 READ_MEDIA_IMAGES 권한과 READ_MEDIA_VIDEO 권한을 앱에 자동으로 부여합니다.

권장사항

이 섹션에는 READ_MEDIA_VISUAL_USER_SELECTED 권한 사용을 위한 여러 권장사항이 포함되어 있습니다. 자세한 내용은 권한 권장사항을 참고하세요.

권한 상태를 영구적으로 저장하지 않음

SharedPreferences 또는 DataStore를 포함하여 권한 상태를 영구적인 방식으로 저장하지 마세요. 저장된 상태가 실제 상태와 동기화되지 않을 수 있습니다. 권한 재설정 후 권한 상태가 변경될 수 있습니다. 앱 최대 절전 모드, 사용자가 시작한 앱 설정 변경, 또는 앱이 백그라운드로 전환됩니다 대신 ContextCompat.checkSelfPermission()

사진 및 동영상에 대한 전체 액세스 권한이 있다고 가정하지 않음

Android 14에 도입된 변경사항에 따라 앱에 일부 버전만 기기의 사진 라이브러리에 액세스할 수 있습니다. 앱이 ContentResolver를 사용하여 쿼리될 때 MediaStore 데이터를 캐시하는 경우 캐시가 최신 상태가 아닐 수 있습니다.

  • 저장된 캐시를 사용하는 대신 항상 ContentResolver를 사용하여 MediaStore를 쿼리합니다.
  • 앱이 포그라운드에 있는 동안 결과를 메모리에 유지합니다.
  • 앱이 onResume 앱 수명 주기를 진행할 때 결과 새로고침 왜냐하면 사용자가 권한 설정을 엽니다.

URI 액세스를 임시로 취급

사용자가 시스템 권한에서 사진 및 동영상 선택을 선택하는 경우 대화상자가 표시되면 선택한 사진 및 동영상에 대한 앱의 액세스 권한이 결국 만료됩니다. 앱은 Uri에 액세스할 수 없는 경우를 항상 처리해야 합니다. 그들의 권위가 중요합니다.

권한에 따라 선택 가능한 미디어 유형 필터링

선택 대화상자는 요청된 권한 유형에 따라 달라집니다.

  • READ_MEDIA_IMAGES만 요청하면 선택 가능한 이미지만 표시됩니다.
  • READ_MEDIA_VIDEO만 요청하면 선택할 수 있는 동영상만 표시됩니다.
  • READ_MEDIA_IMAGESREAD_MEDIA_VIDEO을 모두 요청하면 전체 선택할 수 있습니다.

앱의 사용 사례에 따라 적합한 API 또는 사용자 경험을 저해할 수 있습니다. 특성이 동영상을 선택하려면 READ_MEDIA_VIDEO개만 요청해야 합니다.

단일 작업에서 권한 요청

사용자에게 여러 시스템 런타임 대화상자가 표시되지 않도록 하려면 단일 작업에서 READ_MEDIA_VISUAL_USER_SELECTED, ACCESS_MEDIA_LOCATION, '미디어 읽기' 권한(READ_MEDIA_IMAGES, READ_MEDIA_VIDEO 또는 둘 다)을 요청하세요.

사용자가 선택사항을 관리하도록 허용

사용자가 부분 액세스 모드를 선택할 때 앱은 다음과 같이 가정해서는 안 됩니다. 기기의 사진 라이브러리가 비어 있으며, 할 수 있습니다.

사용자는 권한 설정을 적용할 수 있습니다.

호환성 모드

저장소 권한을 사용하여 자체 갤러리 선택 도구를 유지하지만 아직 보유하지 않은 경우 새 READ_MEDIA_VISUAL_USER_SELECTED를 사용하도록 앱을 조정함 사용자가 다른 작업을 요청할 때마다 시스템에서 앱을 호환성 모드로 실행합니다. 미디어를 선택하거나 다시 선택해야 합니다.

초기 미디어 선택 중 동작

처음 선택할 때 사용자가 '사진 및 동영상 선택'을 선택하는 경우 ( 그림 1), READ_MEDIA_IMAGESREAD_MEDIA_VIDEO 권한은 다음과 같습니다. 임시 권한 부여를 제공하고 사용자가 선택한 사진 및 동영상에 대한 임시 액세스 권한 앱이 백그라운드로 돌아가거나 사용자가 앱을 적극적으로 종료하면 시스템은 결국 는 이러한 권한을 거부합니다. 이 동작은 다른 일회성 권한과 비슷합니다.

미디어를 다시 선택하는 동안의 동작

나중에 앱에서 추가 사진과 동영상에 액세스해야 하는 경우 READ_MEDIA_IMAGES 권한을 수동으로 요청해야 합니다. READ_MEDIA_VIDEO 권한을 다시 부여할 수도 있습니다. 시스템은 다음에서와 동일한 흐름을 따릅니다. 사용자에게 사진과 동영상을 선택하도록 메시지를 표시하여 초기 권한 요청을 수행합니다 (자세한 내용은 그림 2).

앱이 권한 권장사항을 준수하는 경우 이 변경사항은 적용하면 안 됩니다. 앱을 중단시킬 수 있습니다. 앱이 이 URI를 가정하지 않는 경우 특히 그렇습니다. 유지되거나 시스템 권한 상태를 저장하거나 표시되는 모든 이미지를 변경할 수 있습니다. 그러나 이 동작은 앱의 사용 사례에 따라 이상적입니다 최상의 경험을 제공하기 위해 사진 선택 도구를 구현하거나 앱의 갤러리 선택 도구를 이용해 READ_MEDIA_VISUAL_USER_SELECTED 권한