-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(android): Removed read and write media permissions to allow to use Android photo picker #866 #889
Conversation
As it stands, this PR will break picking content from the gallery. The PR simply removes the READ_MEDIA_* permissions and reduces the WRITE_EXTERNAL_STORAGE permission to max 30. I understand that the photo picker requires API 30, so starting with API 30 the photo picker could be implemented and API 29 and lower can do what the plugin currently does. Is the intent to have another PR implement the photo picker to cover the gallery use case? |
Also #890 is merged so if you rebase, it will get the new CI config for the android tests. |
As per information present in the below page (shared in #866 by Fantikor), https://medium.com/androiddevelopers/permissionless-is-the-future-of-storage-on-android-3fbceeb3d70a This plugin is using ACTION_GET_CONTENT intent, so this new photo picker is actually used under the hood. So I modified this plugin and removed the code that requests permissions (for READ_MEDIA_IMAGES and READ_MEDIA_VIDEO) as they were previously only required for Android API levels 33 and above and for the versions 29 and below the plugin would retain the same behavior as before. If I am not wrong the gallery use case is also working as expected and no other changes are required. Let me know if you see something is missing or If I misunderstood it. |
Ok this is good... I thought we were using some other intent and didn't actually realise The bad news is, simply using the picker and removing the permissions isn't the complete solution. Bear with me this will be quite a lengthy post... but this will explain the situation. To be clear, this is not the fault of this PR or anything, just things that Cordova has done in the past because it seemed like a good idea at the time and never has updated or introduced the breaking changes required to move to newer concepts and now Cordova is getting a bite of those consequences. First, I've done all my testing using the Cordova takes primarily two different paths when using the camera API:
Sourcing new content from the camera does work, regardless of permissions or API level. This works because the native receives a Sourcing existing content from the gallery however doesn't do file copy. It instead simply resolves the content:// to the external file system path and returns that. Both READ_EXTERNAL_STORAGE and READ_MEDIA_* permission requirements comes from the fact that the API shares these external URIs. They are required if you use the Filesystem APIs instead of the MediaStore APIs. In API 30, Android has a concept of FUSE filesystem that maps external FS kernel calls to the media store to enforce access but this does not grant the application temporary access that the content:// urls does when using the media store. Scope storage exists in API 29 which also lacks this FUSE filesystem so I believe this is currently completely broken on API 29 devices. Solution 1
So the quick solution which will fix API 29, and should also allow us to eliminate the storage permissions is to do what we do when sourcing content from the camera. Use the content resolver to obtain the content and write it to app-specific cache and return those uris instead of external paths. This isn't a breaking change, we aren't changing the public API. But the reason why this approach is problematic is, copying large files obviously will take time. So picking videos will likely not give a good user experience, depending on the size of the video. Image content is usually manageable in terms of file size. Here are some code references:
The problematic returns are likely:
Other ThoughtsI've also explored passing content:// uris directly to the webview, which poses several issues:
cordova-android platform could solve the first issue by mapping a path inside the WebViewAssetLoader that can resolve to the content:// uri and make use of the content resolver and return that content. But the other 2 issues will be prevalent without a media store API. There are third-party plugins available for a media store API but I don't think Apache Cordova should build the core plugins to rely on third-party plugins. Being able to use content:// uris (even indirectly) is probably much better, but will require a lot of other moving parts to occur first. Additionally, requiring the use of a media store plugin for android also isn't ideal when iOS will need to continue to use the file plugin APIs. Cordova code is meant to be shared across platform, so we can't have a plugin API that requires using the result in two different ways depending on the platform. Therefore Cordova ideally needs to figure out how it can incorporate content:// uris in the file plugin APIs so that usage can be consistent cross platform. Final ThoughtsDue to time constraints, I don't think the content:// solution is viable, so I think we are stuck with the first Solution. I know this is a lot, I'm not sure if this is still something you are willing to work on. If not, then that's okay too, we can probably still make use of what you've done in this PR and implement the rest in another PR. |
I've done a bit more testing using content urls and wanted to follow up with some more details. Using content urls directly simply doesn't work and I still don't know why. Using Filesystem does have some support for using file APIs against content urls, though permissions may limit the actions you can take on content uri sources, but I've tested the following:
First caveat is content urls have a filename that contains a But this might actually make the content path usage viable, especially if we can fix the asset loader in cordova-android. |
Thank you for the clear explanation, didn't reliaze that the selecting photos from Gallery (external file system) is broken for API levels 29 and below. I was under the assumption that functionality should still work on devices with 29 and below as READ_MEDIA_IMAGES and READ_MEDIA_VIDEO permissions were previously only added from 33 and above in the plugin and for 29 and below it didn't require these permissions. Probably then this is an existing issue in the plugin that selecting the files from the external system didn't work. I, myself didn't check this behavior, will check once. |
The actual link is apache/cordova-plugin-file#629 (it's a different repo) And the reason that relates is because this PR will cause apache/cordova-plugin-file#629 makes the content uris consumable by the file plugin allowing you to use We are going to have to add some documentation I think, there are significant differences and applications will have to adapt their usage. For example access to the |
Thanks for the info @breautek. Yeah, I was tricked by the wrong auto-link. As long as the final URIs work from the WebView (like |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the changes are good and helps us get more aligned to what Google wants app developers to do.
Tests passes (except for browser/chrome tests, which is unrelated to this PR).
Manual testing shows that no behaviour changes occur when sourcing an image from the camera hardware (e.g. if the user snaps a new picture).
There is 2 breaking changes when sourcing an image/video resource from the gallery.
-
Old behaviour returned a file path (not even a URI, just simply a
/path/...
without thefile://
protocol). New behaviour returns acontent://
path. -
The
content://
paths gives temporary read access to the file. Read access expires if the app activity is closes. If users previously stored the return file path, the file path will not work and will return a security exception if attempted to be read unless if the user goes through the file picker UI and selects that file again (regranting the temporary read access).
App developers who sources images or videos via the gallery may have to adapt their code. For example, if an app is using the gallery to source an image for a profile picture, the app will want to copy the file while it has the read access to an app data directory and store the app data file path to the resource instead where it will have long-term permanent access to that file.
Other Notes:
This PR does break using the picked resources in the DOM. This is because a FileEntry
using a file://
path can be resolved via .toURL()
method to a local web asset loader url and the asset can used in the DOM, using <img src="..." />
for example.
content://
paths are currently not supported. This is however isn't an issue within the camera plugin and this issue is being addressed in the file plugin: apache/cordova-plugin-file#629
The deadline set by Google for this change is Oct 31. Is there anything missing for this PR to be merged? |
This is cherry-pick and backport of a non-final implementation of PR apache#889 WR-Issue: #17891
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have any objections if this has been tested and confirmed working, but I've never used the camera plugin in an app so my vote shouldn't count for much here 😛
Does this need to be a major version bump for the plugin, since it changes the returned file paths?
Does that change affect older versions of Android as well? (I'm a bit unclear since we're actually lowering the version checks in the code rather than raising them)
It will be included in a 8.0 major release.
The READ_MEDIA_* permissions were API 33+ permissions which I think is the key point. But tbh I think this is something I want to re-test. Causing looking back now it does seem weird. |
Just to get a cordova-wide view of this issue, plugin-file has already merged Content FS support, plugin-media-capture has an open issue with a PR removing the permissions and plugin-camera is here doing the same, right? |
I haven't really kept a close eye on media-capture plugin so I don't know if it's "in-sync" with what the camera plugin is doing. I know there was previous proposals to make the media-capture plugin copy the assets from the content:// store to the app's internal temp directory to avoid permission problems or requiring the With the Content FS changes in file plugin (which is currently in the release process and I'm hoping to make a release this week if I can get enough binding votes) it will give the app developers a choice of immediate playback directly from |
@ravi-yk I think I'm going to fork your PR to extend what you've done even further. This way you're contributions are still credited in the form of a commit. The reason is I think we can go much further, I've been re-testing things and I think with some more changes we can completely remove all permissions, including the READ/WRITE external storage permission. It would simplify and cleanup a lot of the codebase. I have a working PoC testing API 24 atm. Is this OK? EDIT: Actually scratch that we have the votes already to merge, so I'll merge and do an addon PR instead of replacing your PR. Thank you for your work here! |
Platforms affected
Motivation and Context
Google recommends using the Android photo picker in apps where it's not frequent to access these files instead of the READ_MEDIA_IMAGES and READ_MEDIA_VIDEO permissions.
This should fix #866
Description
Removed the READ_MEDIA_IMAGES and READ_MEDIA_VIDEO permissions and WRITE_EXTERNAL_STORAGE storage permission maxSdkVersion is set to 30.
Testing
Tested these changes on Android 10,11,12,13 and 14 devices.
Checklist
(platform)
if this change only applies to one platform (e.g.(android)
)