Skip to content
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

Make mediaStore.saveFile return file URI (with content:// scheme) #18

Closed
Henry-Hiles opened this issue Mar 16, 2024 · 30 comments
Closed
Assignees
Labels
enhancement New feature or request waiting-for-release Task is done. Will release in next version

Comments

@Henry-Hiles
Copy link

It would be much appreciated if saveFile could return the file URI when I save the file. Thank you!

@SNNafi SNNafi self-assigned this Apr 9, 2024
@SNNafi SNNafi added the enhancement New feature or request label Apr 9, 2024
@SNNafi
Copy link
Owner

SNNafi commented Apr 11, 2024

@Henry-Hiles, Just finished this. Will release soon within 3-4 days

@SNNafi SNNafi added the waiting-for-release Task is done. Will release in next version label Apr 11, 2024
@Henry-Hiles
Copy link
Author

@Henry-Hiles, Just finished this. Will release soon within 3-4 days

Thank you so much!

@SNNafi
Copy link
Owner

SNNafi commented Apr 11, 2024

Released

@Henry-Hiles
Copy link
Author

Released

I've just realized this isn't what I want

@Henry-Hiles Henry-Hiles reopened this Apr 12, 2024
@Henry-Hiles
Copy link
Author

As you can see from the title, i said content:// scheme, not file://, also it would be better if it was a Uri not String. Thanks!

@SNNafi
Copy link
Owner

SNNafi commented Apr 12, 2024

It is content:// scheme. You can create a Uri object from the Uri String i.e. Uri.parse(uri)

Here is my console result after saving,

D/saveFile( 9771): al_aqsa_mosque.jpeg
I/flutter ( 9771): content://media/external/images/media/1000000073 <- returned by saveFile()

@SNNafi SNNafi closed this as completed Apr 12, 2024
@Henry-Hiles
Copy link
Author

It is content:// scheme. You can create a Uri object from the Uri String i.e. Uri.parse(uri)

Here is my console result after saving,

D/saveFile( 9771): al_aqsa_mosque.jpeg
I/flutter ( 9771): content://media/external/images/media/1000000073 <- returned by saveFile()

Oh huh, I just realized its returning null for me, is that normal?

@Henry-Hiles
Copy link
Author

Also this should be updated:
image

@Henry-Hiles
Copy link
Author

It is content:// scheme. You can create a Uri object from the Uri String i.e. Uri.parse(uri)
Here is my console result after saving,

D/saveFile( 9771): al_aqsa_mosque.jpeg
I/flutter ( 9771): content://media/external/images/media/1000000073 <- returned by saveFile()

Oh huh, I just realized its returning null for me, is that normal?

Ah, I guess that means it failed. Hmm. Clearing out my downloads fixed it, but not ideal.

@Henry-Hiles
Copy link
Author

Okay, it returns null, if a file with the same name in the same place was generated by a different app...

@SNNafi
Copy link
Owner

SNNafi commented Apr 12, 2024

It should ask for permission to overwrite the file. Like this,

screenshot

@Henry-Hiles
Copy link
Author

It doesn't do that for me or any testers of my app, hmm

@Henry-Hiles
Copy link
Author

If it's overwriting a file created by this app, it overrides without confirmation (that's fine), but if another app created it it returns null.

@SNNafi
Copy link
Owner

SNNafi commented Apr 12, 2024

You need to add these permission to manifest for reading respective media types,

    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

Then only the app checks for existing files and asks for overwriting. I didn't allow the permissions and it returns null.

D/DisplayName al %aqsa_mosque.jpeg(13124): null <- can't read the file as no permission is allowed.
D/saveFile(13124): al %aqsa_mosque.jpeg
I/flutter (13124): null ->  Can't save the file as __al %aqsa_mosque.jpeg__ as there's already a file exists. so returned null

But the file is saved as al %aqsa_mosque (1).jpeg. It is done by media store API by default.

@Henry-Hiles
Copy link
Author

You need to add these permission to manifest for reading respective media types,

    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

Then only the app checks for existing files and asks for overwriting. I didn't allow the permissions and it returns null.

D/DisplayName al %aqsa_mosque.jpeg(13124): null <- can't read the file as no permission is allowed.
D/saveFile(13124): al %aqsa_mosque.jpeg
I/flutter (13124): null ->  Can't save the file as __al %aqsa_mosque.jpeg__ as there's already a file exists. so returned null

But the file is saved as al %aqsa_mosque (1).jpeg. It is done by media store API by default.

Hmm, I'm saving to the downloads folder. It can be any type of file, what should I add to manifest? Altetnatively, returning the URI of the (1) file if its created would be even better!

@SNNafi
Copy link
Owner

SNNafi commented Apr 12, 2024

However, you don't need to add these permissions to read and write the files created by your app.
Again if you uninstalled your app, the files your app is created will be treated as another app creates it, the next time you install your app.

@Henry-Hiles
Copy link
Author

However, you don't need to add these permissions to read and write the files created by your app. Again if you uninstalled your app, the files your app is created will be treated as another app creates it, the next time you install your app.

Yes I see thanks

@SNNafi
Copy link
Owner

SNNafi commented Apr 12, 2024

You can ask for permission to read the Downloads/<AnyFolder> folder using

Future<DocumentTree?> requestForAccess({required String? initialRelativePath})

this method. There's an example here

@Henry-Hiles
Copy link
Author

You can ask for permission to read the Downloads/<YourAppFolder> folder using

Future<DocumentTree?> requestForAccess({required String? initialRelativePath})

this method. There's an example here

I see. And I need to have read access to overwrite the files? Would it be possible to return the uri with the (1) instead, if that's the one created? Thanks!!

@SNNafi
Copy link
Owner

SNNafi commented Apr 12, 2024

You can ask for permission to read the Downloads/<YourAppFolder> folder using

Future<DocumentTree?> requestForAccess({required String? initialRelativePath})

this method. There's an example here

I see. And I need to have read access to overwrite the files? Would it be possible to return the uri with the (1) instead, if that's the one created? Thanks!!

No, that's not ideal behavior. It can be (1), (2) or who knows? Again null can be also returned if there is an actual issue. So. this is not possible.

But you can always check by using

Future<Uri?> getFileUri({
    required String fileName,
    required DirType dirType,
    required DirName dirName,
    String? relativePath,
  })

Here the fileName would be al %aqsa_mosque (1).jpeg

But it's better to ask for access as it is the standard approach. Users don't like to add duplicated files to the devices.

@Henry-Hiles
Copy link
Author

Henry-Hiles commented Apr 12, 2024

You can ask for permission to read the Downloads/<YourAppFolder> folder using

Future<DocumentTree?> requestForAccess({required String? initialRelativePath})

this method. There's an example here

I see. And I need to have read access to overwrite the files? Would it be possible to return the uri with the (1) instead, if that's the one created? Thanks!!

No, that's not ideal behavior. It can be (1), (2) or who knows? Again null can be also returned if there is an actual issue. So. this is not possible.

But you can always check by using

Future<Uri?> getFileUri({
    required String fileName,
    required DirType dirType,
    required DirName dirName,
    String? relativePath,
  })

Here the fileName would be al %aqsa_mosque (1).jpeg

But it's better to ask for access as it is the standard approach. Users don't like to add duplicated files to the devices.

What I meant was on the library side, if it's saved with a number, could you return the uri of that instead of null?

@SNNafi
Copy link
Owner

SNNafi commented Apr 12, 2024

I want to stick with the standard way i.e. asking for request access.

@Henry-Hiles
Copy link
Author

I want to stick with the standard way i.e. asking for request access.

Well, if the file is being saved, surely the uri should be returned? Even if its under a different filename. This is how a browser would work, it'd save that way and still have an open option.

@SNNafi
Copy link
Owner

SNNafi commented Apr 13, 2024

saveFile() now returns SaveInfo. It contains the saved file name, uri and the saved status, whether the file is created, replaced or duplicated

Check here: https://github.com/SNNafi/media_store_plus/blob/main/lib/src/save_info.dart

Available from 0.1.1

@Henry-Hiles
Copy link
Author

Thank you!

@Henry-Hiles
Copy link
Author

saveFile() now returns SaveInfo. It contains the saved file name, uri and the saved status, whether the file is created, replaced or duplicated

Check here: https://github.com/SNNafi/media_store_plus/blob/main/lib/src/save_info.dart

Available from 0.1.1

With latest release it no longer duplicates the file, instead throwing a PathAccessException saying it cannot copy the file

@Henry-Hiles
Copy link
Author

And then i tried it again and it worked? Hmm.

@Henry-Hiles
Copy link
Author

Yep it seems to work now, thanks!

@Henry-Hiles
Copy link
Author

Hmm... The save info is only returned on debug, not release builds.

@SNNafi
Copy link
Owner

SNNafi commented Apr 20, 2024

Working fine. Checked on the release build. I don't know how you are testing things!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request waiting-for-release Task is done. Will release in next version
Projects
None yet
Development

No branches or pull requests

2 participants