breautek commented on issue #603:
URL:
https://github.com/apache/cordova-plugin-file/issues/603#issuecomment-1709254803
My apologies, there's a couple of important detail I forgot, but yes the
situation with Android is messy. I'd still recommend using a MediaStore plugin.
I foresee support for the external file system being completely dropped in the
future.
For context here is a sample file write to the external download directory:
```javascript
function onDeviceReady() {
// Cordova is now initialized. Have fun!
console.log('Running cordova-' + cordova.platformId + '@' +
cordova.version);
document.getElementById('deviceready').classList.add('ready');
window.resolveLocalFileSystemURL(cordova.file.externalRootDirectory +
'Download', (directoryEntry) => {
directoryEntry.getFile('myFile.txt', {create: true, exclusive:
false}, (entry) => {
entry.createWriter((writer) => {
writer.onwriteend = () => {
console.log('write success');
};
writer.onerror = (e) => {
console.error('write error', e);
};
let blob = new Blob(['test123'], { type: 'text/plain' });
writer.write(blob);
}, (e) => {
console.error('writer init error', e);
});
}, (e) => {
console.error('creation error', e);
});
}, (e) => {
console.error('resolve error', e);
});
}
```
Whether this works will depend on several factors, and depending on the API
level of the device running this code.
## API 24-28 Devices (Android 7-9)
On API 28 (and earlier) devices, scoped storage rules do not apply.
`WRITE_EXTERNAL_STORAGE` is required. However the plugin as of v8 no longer
manages the permission automatically. You'll need a hook script or use
`config-file` if something isn't already adding this permission. See the
[release
blog](https://cordova.apache.org/news/2023/07/11/file-plugin-8.0.0.html) for
more details on this. This is the first important detail I forgot to mention
earlier.
## API 29 Devices (Android 10)
On API 29, **EXTERNAL STORAGE** will not work whatsoever. API 29 is when
Google first introduced Scoped Storage and disabled file system access to
external storage. This is why using the Mediastore is nearly a requirement,
unless if you intend to support API 30+ in your app. This is the second
important detail I forgot to mention earlier.
You can read more on this issue on the [Android
Docs](https://source.android.com/docs/core/storage/scoped#using-scoped-storage-with-fuse)
> Android 10 enforced scoped storage rules on file accesses by
MediaProvider, but not for direct file path access (for example, using File API
and NDK APIs) due to the effort required in intercepting kernel calls. As a
result, apps in scoped storage couldn't access files using a direct file path.
This restriction impacted app developers' ability to adapt as it required
substantial code changes to rewrite File API access to the MediaProvider API.
## API 30-32 (Android 11-12)
Starting with API 30, Google introduced a way to allow access to external
storage via File APIs once again. Using the same android doc link above...
> Android 11 or higher supports Filesystem in Userspace (FUSE), which
enables the MediaProvider module to examine file operations in user space and
to gate access to files based on the policy to allow, deny, or redact access.
Apps in scoped storage that use FUSE get the privacy features of scoped storage
and the ability to access files using a direct file path (keeping File APIs
working in apps).
As a result, this plugin will begin working again, under the restrictions of
Scoped file storage rules.
Those limitations are noted
[here](https://github.com/apache/cordova-plugin-file#androids-external-storage-quirks)
which I've mentioned previously earlier today.
Starting with API 30, the above JS code will work assuming that you're not
writing to a file that your app doesn't own.
I've also tested the above code with API 32 (Android 12) device.
Note that while scoped storage doesn't require permission to write, the
plugin still requests the `READ_EXTERNAL_STORAGE` permission, so on your
creation/write call it will prompt for a permission grant.
## API 33 (and beyond?) / Android 13
I've also explicitly tested this. In your use case the changes in API 33
doesn't matter. But effectively READ_EXTERNAL_STORAGE now doesn't grant you any
special permissions, and they added 3 new READ permissions, one for video,
audio, and images. As a result you won't see any permission requests anymore
since there is an explicit API 33 or greater check. Changes in API 33 doesn't
limit or increase your access to scoped storage anymore than what was
previously accessible.
So with this information, to answer your questions
> Would I really need mediastore for such a simple task?
If you intend to support API 29 devices, then yes, because there is no
direct file support on API 29 devices. If you intend to support API 30+, then
you _could_ potentially get away with using file plugin, but I'd still
recommend using a MediaStore plugin.
> Is there any updated documentation showing how to save an image to the
download folder since Android 33?
If you're referring documentation in regards to using the MediaStore plugin,
Apache has no official plugin that interfaces with the MediaStore, so no we
don't have any documentation. Our file plugin hasn't changed, but Android has
changed significantly in very awkward ways.
For example, the MediaStore API doesn't fit well with a "Filesystem" API
model. It would be very difficult to maintain the API as we have now, but use
the MediaStore APIs instead. This is why I foresee Apache dropping support, but
there has been no formal vote to move forward with that path at this time of
writing. The file plugin itself still works completely intended for internal
app data files. The issues is exclusively with Android's external file system.
Alternatively, if these files belong to your app as "app data", then perhaps
you should use `cordova.file.dataDirectory` instead. But I assume that if you
were writing to to the `Download` directory, then you must intend on having the
files potentially shared with other apps.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]