The Image component requires READ permission on Android 11+, even if the image belongs to the app. This is a bug and should finally be fixed. I've pointed this out several times already. This is all the more necessary since Google hasn't allowed READ_MEDIA_IMAGES permissions on Android 13+ since May 2025. Furthermore, the image component also requests READ when a contentUri is used. This makes the problem even worse.
In addition, the Play Store version of the Companion app doesn't even declare READ_MEDIA_IMAGES and READ_MEDIA_VIDEO permissions anymore (for the reason stated above), so a permission error is thrown there as well. @ewpatton
You are right, and this is a known bug with two layers to it.
The first layer is at the manifest level. Image.java declares READ_EXTERNAL_STORAGE as a class-level @UsesPermissions annotation, so the permission appears in the manifest unconditionally whenever an Image component is present in a project, even when the image is loaded from assets. Other media components like Player.java handle this correctly by placing the storage permission at the method level on the Source property setter, so it only gets pulled into the manifest when that property is actually used.
The second layer is at runtime. Even after moving the manifest declaration to the method level, TiramisuUtil.requestImagePermissions still runs for every path passed to the Picture setter, including paths that should not need any permission (like app-owned files or content URIs). That runtime behavior is a separate concern and is what PR #2773 addresses.
Correct, READ_EXTERNAL_STORAGE is of course unnecessary, but not problematic, as Google has no issues with it up to Android 12. On Android 13+, however, READ_MEDIA_IMAGES must be requested, and Google has not allowed this since May 2025 (without prior approval from Google).
Therefore, the unnecessary declaration of the READ_EXTERNAL_STORAGE permission is only relevant up to Android 12 anyway.
No, the Player component declares basicallyREAD_EXTERNAL_STORAGEandREAD_MEDIA_AUDIO in the Manifest. Both permissions are unnecessary here as well, but harmless since Google has no issues with either. However, I always remove these permissions from the Manifest of my Play Store apps beforehand.
As I've been saying for years, requesting storage permissions should, without exception, be left to the app developer! In the past—before the introduction of the Scoped Storage concept—it might have made sense to declare them. Definitely not anymore! It only creates confusion, conflicts, and problems.
We are aware of this but beginners just drag and drop and publish the app to play store and get notice of app suspension, and even the Google never tell actual reason which leads to console account suspension. Temp solution: set bg image to arrangement instead of image component.
Internet permission is declared by default and as I said READ_EXTERNAL_STORAGE permission is unnecessary, but harmless, as Google will not object to it.
Thank you for the correction. I get it now that Player.java is not a good reference here since it also declares unnecessary storage permissions. I should not have called it a correct reference and the point about Google requiring prior approval for READ_MEDIA_IMAGES since May 2025 is important. My PR originally added that permission to the manifest, which would make Play Store submissions worse rather than better. I have reworked the PR to remove READ_MEDIA_IMAGES and only move READ_EXTERNAL_STORAGE from class level to method level, matching what VideoPlayer.java does for its Source property.
One more thing:
In App Inventor, permissions are declared in the Manifest as soon as they are requested in the corresponding blocks. It doesn't matter whether they are actually requested; it's sufficient that they are present somewhere throughout the block area.
So we don't need to worry about declaring the permissions, but only about knowing exactly what permissions are required. However, there's no getting around that.
Of course, my statements only apply insofar as access is to files either from the assets or the PrivateDir.
On devices with Android ≤ 10 (API 29) and ≥ 4.4 (API 19), READ_/WRITE_EXTERNAL_STORAGE must always be requested when accessing files from external storage (excluding the ASD).
On devices with Android < 4.4 (API < 19), however, storage permission must also be requested (more precisely, it must only be declared in the Manifest, because permission is then granted at install-time) when accessing files in ASD. Strictly speaking, requesting WRITE_EXTERNAL_STORAGE is sufficient, as this implicitly also grants READ_EXTERNAL_STORAGE.
However, the request for permissions will only be visible to the user if, firstly, it involves dangerous permissions and occurs on devices with Android ≥ 6 (API ≥ 23, i.e., after the introduction of runtime permissions).
However, since some components and many extensions require a minSdkVersion ≥ 21 (Android 5) and declare this in the Manifest, point 3 is usually not relevant.