We have some old issues with similar words, but most of them are about converting one or the other.
What I'm looking here is the "Right" behaviour of URI usage with the new changes. Let me give some context:
Before when we get an image URI this would return file://...
format.
But since the new OS permissions changes, where we should not use WRITE_EXTERNAL_STORAGE
anymore we should use getUriForFile(..)
that return content://...
path.(Scope Storage usage Android 11 Storage FAQ)
This can be spot on some Android guides, like: taken photos guide
The "problem" is that many users got used to use the URI of a crop image (for example) to create a file of it and save it.
Now, with this changes come the question:
How should we use the URI?
content
of file
) and if someone wanna save it would need to create it own file pathObs: Asking this, because of a Android Image Crop open source project handover, where we need to upgrade the permissions for Android 10/11 but now we have this content/file issue. More here
Edit: As pointed on the comments
Code returning file://
(not valid anymore since the changes)
Uri outputFileUri = null;
outputFileUri = Uri.fromFile(
new File(context.getExternalCacheDir().getPath(),
"pickImageResult.jpeg")
);
Code returning content://
outputFileUri = FileProvider.getUriForFile(
context,
context.getPackageName() + CommonValues.authority,
File.createTempFile("pickImageResult", ".jpeg", getImage)
);
The "problem" is that many users got used to use the URI of a crop image (for example) to create a file of it and save it.
In the end, this is your library, and you need to document what any Uri
that you return is suitable for. After all, a Uri
could point to:
file
)https
, or possibly http
)android.resource
)file://android_asset
)content
)Your library is for image cropping. While I have not examined the implementation, I assume that it all works inside the app itself. If so, there is nothing wrong with returning a file
Uri
, if you want to do so. Your code is writing a file somewhere (e.g., getCacheDir()
on Context
). The app using your library must have access to that file, or else you would have crashed trying to write it. A Uri
created via Uri.fromFile()
, for that file, is perfectly fine... in that app.
Where Uri.fromFile()
becomes a problem is in passing the Uri
to another app. However, your library is for cropping images, not sharing content with other apps. Your job, IMHO, is to give a cropped image back to the app. What the app does with it is up to that app, subject to whatever limitations there are in the Uri
that you hand over.
The two options that you seem to be considering have different issues:
Uri Source |
Advantages | Disadvantages |
---|---|---|
Uri.fromFile() |
Cheap, easy | Can only be used within the app itself; cannot be passed to other apps |
FileProvider |
Uri can be passed to other apps |
Requires a library and manifest configuration; cannot readily get to the underlying file |
Since IMHO an image cropper is not an image sharing solution, Uri.fromFile()
seems reasonable. If the app using your library wants to turn around and share the cropped image, they would set up FileProvider
themselves and use FileProvider.getUriForFile()
. The only catch is that either you need to document where the file will be written or give them an option to tell you what directory to use — that information will be needed to set up the FileProvider
metadata.
Someday, if you elect to change the API, you might consider returning an ordinary File
instead of a Uri
. That way, there is no confusion about what it represents.
But, in the end, this is all your decision. If you want to use FileProvider
, or you want to upload images to your own Web server and use https
, that is all up to you. However, you should document what you are doing and what the Uri
represents.