Scoped storage in Android 13 external media access transitions
0 reputation · 09 Jan 2024, 07:52 UTC
0 reputation · 09 Jan 2024, 07:52 UTC
Android 13 (API level 33) enforces stricter boundaries for apps accessing external media, moving away from direct file path access. While legacy apps targeting older versions might benefit from broader access, modern apps targeting API 33 must utilize the MediaStore API or specific URI-based permissions.
A primary challenge arises when apps attempt to rely on direct file paths for media files outside their app-specific directories. Even with MANAGE_EXTERNAL_STORAGE considered, it is restricted to specific file manager categories and is discouraged for general third-party applications. This forces a shift toward handling Content URIs and managing temporary URI permissions across process restarts.
How does the behavior of temporary URI permissions change when an app targets API 33 compared to API 32? Are there specific edge cases where maintaining access to a user-selected file fails despite using FLAG_GRANT_URI_PERMISSION?
The core mechanism of temporary URI permissions (FLAG_GRANT_URI_PERMISSION and takePersistableUriPermission()) does not change between API level 32 (Android 12L) and API level 33 (Android 13). What does change is the prerequisite permission set required to actually read the media referenced by that URI.
targetSdkVersion >= 33 no longer receive broad READ_EXTERNAL_STORAGE access. Instead they must declare one or more of the granular media permissions: READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, or READ_MEDIA_AUDIO.ACTION_OPEN_DOCUMENT, ACTION_GET_CONTENT, or the photo picker), the system grants a temporary URI permission to the app regardless of the app’s target SDK, as long as the URI is returned through those APIs.contentResolver.takePersistableUriPermission(uri, mode), the permission is lost when the process is killed or the device is rebooted.SecurityException if the app lacks the required media permission for that file type.Access failures after moving to API 33 usually stem from missing the new READ_MEDIA_* permission, not from a change in how the URI grant works. The system still grants the URI, but the subsequent read operation is blocked unless the appropriate media permission is held at runtime.
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />final int mode = Intent.FLAG_GRANT_READ_URI_PERMISSION;
getContentResolver().takePersistableUriPermission(uri, mode);
ContentResolver.openInputStream(uri) (or similar) to read the file; this will succeed only if the media permission is granted.If you are already calling takePersistableUriPermission() but still losing access after a process restart, confirm whether you are persisting the URI permission across reboots (the flag above does that) or if you are relying solely on the transient grant. Let me know if you need guidance on checking the persisted permission state.
Use comments to ask for clarification. Post a solution as an answer.
32,775 reputation · 09 Jan 2024, 08:24 UTC
In Android 13 the FLAG_GRANT_URI_PERMISSION mechanism remains unchanged, but the *ability* to actually read the content behind the URI now depends on the new granular media permissions.
takePersistableUriPermission(uri, MODE_READ_WRITE) after a picker, the URI stays valid across reboots only if you also hold the relevant READ_MEDIA_* permission; otherwise SecurityException is thrown even though the URI grant exists.MANAGE_EXTERNAL_STORAGE the app cannot open the stream; the URI grant is effectively useless.READ_EXTERNAL_STORAGE only, the system will silently ignore it for media files – you must explicitly declare the granular permission in the manifest.READ_MEDIA_* (or WRITE_MEDIA_*) permission.takePersistableUriPermission with the correct mode before the process may be killed.ACTION_OPEN_DOCUMENT_TREE or request MANAGE_EXTERNAL_STORAGE if broader access is truly required.