Closed HarelM closed 2 years ago
Or is there a way to use this plugin on the 'Files' android app so the user can save the file on his device ?
I recommend my users to simply install this simple and light add-on, I'd say it's not even an app, it simply allows you to share to file system. But any file system app allows you to do that.
@jfoclpf Will this work on Android 11 sdk 30+ ?
@jfoclpf Will this work on Android 11 sdk 30+ ?
Yes, so far the feedback from the users is that it works
I am using ionic 4 and I faced the same issue so I tried the ionic 4 version of resolveDirectoryUrl(cordova.file.externalRootDirectory, function (dirEntry) {)) and on success function I used dirEntry.getDirectory ('Download'... and I can create folders and save files to the Download folders on android 11 without adding android:requestLegacyExternalStorage="true". Here is the code for ionic 4. I have also tried to convert it to the normal web version.
createDirectory(rootDir) {
return new Promise((res, rej) => {
this.file.resolveDirectoryUrl(rootDir).then((rootDirEntry)=>{
rootDirEntry.getDirectory('Download', { create: false, exclusive:false}, (dirEntry) =>{
dirEntry.getDirectory('updates', { create: true, exclusive:false}, (subDirEntry) =>{
this.updateDir = subDirEntry;
this.appDir = dirEntry;
res(this.updateDir)
}, (err)=> {
this.onErrorGetDir(rootDir+'Download/','updates');
rej(err)
})
}, (err)=> {
this.onErrorGetDir(rootDir,'Download')
rej(err)
})
})
})
}
and the normal web version. Note that I have only tested the ionic 4 version of this code.
function createDirectory(rootDir /*cordova.file.externalRootDirectory*/) {
window.resolveDirectoryURL(rootDir, function (rootDirEntry) {
dirEntry.getDirectory('Download', { create: false, exclusive:false}, function (dirEntry) {
dirEntry.getDirectory('updates', { create: true, exclusive:false}, function (subDirEntry) {
/* delete a file or donwload a file using cordova-plugin-advanced-http.
I tested mine using cordova-plugin-advanced-http to download a file to this folder */
createFile(subDirEntry, "fileInNewSubDir.txt");
}, onErrorGetDir);
}, onErrorGetDir);
})
}
This doesn't allow you to write or read from the root directory but works with the download directory and probably other sub directories in the root directory. You will need READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE permissions.
@joshuaokpako that's strange, normally you shouldn't be able to write to cordova.file.externalRootDirectory + 'Download/'
without the android:requestLegacyExternalStorage
to true (check the answer from @breautek ) after API 29. Are you using the dev version of this file plugin (i.e. fetched from github)?
@jfoclpf I am using ionic 4 and the ionic cordova plugin is built on this file plugin. I have attached the link to the ionic 4 website that references this plugin https://ionicframework.com/docs/native/file
@joshuaokpako ah, now I see, you are using the npm version (npm install cordova-plugin-file
) and not the dev version and in the npm version android:requestLegacyExternalStorage
is not set to true
. Thus it works (in theory just up to Android 10).
I am using ionic 4 and I faced the same issue so I tried the ionic 4 version of resolveDirectoryUrl(cordova.file.externalRootDirectory, function (dirEntry) {)) and on success function I used dirEntry.getDirectory ('Download'... and I can create folders and save files to the Download folders on android 11 without adding android:requestLegacyExternalStorage="true". Here is the code for ionic 4. I have also tried to convert it to the normal web version.
createDirectory(rootDir) { return new Promise((res, rej) => { this.file.resolveDirectoryUrl(rootDir).then((rootDirEntry)=>{ rootDirEntry.getDirectory('Download', { create: false, exclusive:false}, (dirEntry) =>{ dirEntry.getDirectory('updates', { create: true, exclusive:false}, (subDirEntry) =>{ this.updateDir = subDirEntry; this.appDir = dirEntry; res(this.updateDir) }, (err)=> { this.onErrorGetDir(rootDir+'Download/','updates'); rej(err) }) }, (err)=> { this.onErrorGetDir(rootDir,'Download') rej(err) }) }) }) }
and the normal web version. Note that I have only tested the ionic 4 version of this code.
function createDirectory(rootDir /*cordova.file.externalRootDirectory*/) { window.resolveDirectoryURL(rootDir, function (rootDirEntry) { dirEntry.getDirectory('Download', { create: false, exclusive:false}, function (dirEntry) { dirEntry.getDirectory('updates', { create: true, exclusive:false}, function (subDirEntry) { /* delete a file or donwload a file using cordova-plugin-advanced-http. I tested mine using cordova-plugin-advanced-http to download a file to this folder */ createFile(subDirEntry, "fileInNewSubDir.txt"); }, onErrorGetDir); }, onErrorGetDir); }) }
This doesn't allow you to write or read from the root directory but works with the download directory and probably other sub directories in the root directory. You will need READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE permissions.
This only work for CREATE files.
i can't delete/update a file inside 'Download' folder without flag 'requestLegacyExternalStorage'
Android 11 sdk 30+
@victorvhpg I believe the new android 11 update will only allow you delete files that are created by your app in the Download folder. I haven't tested deleting any other file but I have used the code on ionic 4 to delete files I created in the Download folder.
delelteFile(dir:DirectoryEntry,name) {
return new Promise((res, rej) => {
dir.getFile(name, {create: false}, function (fileEntry) {
fileEntry.remove( () =>{
res("deleted")
}, function (error) {
rej(error)
});
}, function () {
res("ok")
});
})
}
I believe this is the reason why the code above will work on android 11 https://developer.android.com/about/versions/11/privacy/storage#media-direct-file-native
I would like to invite people to try out my fork and give it a test: https://github.com/breautek/cordova-plugin-file/tree/feat/api30
My fork removes the requestLegacyExternalFlag
which means it should work on both API 29 and API 30+. It ensures that it prompts for the proper permission in read/write external storage.
Here are some highlight changes:
It's possible that you've already granted or denied external storage permissions, in which case it may just work or it may not work. If you're getting a file not found kind of errors, or file listings are simply empty when you expect there to be content, that probably means you're lacking permissions. Android does not tell us that a file exists but you lack permissions to view; it just gives a file not found error. I assume this is for privacy reasons.
You can use adb shell pm reset-permissions
to reset your permissions on all apps back to a state of "not requested", so that you can test as if the user is running your app for the first time.
externalRootDirectory
is readable, but not writable. You cannot create directories or files inside this directory anymore.
I used https://github.com/breautek/cordova-file-api30-test-app as a test app. If something is not working right for you on my fork, feel free to make a pull request and add a test case.
I've seen Google is cracking down, requiring external use via READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE
; in order to use these permissions (and this plugin for accessing external storage) you will need to give justification. You'll going to have to evaluate if your app needs external storage access, and if not, then start migrating to internal storage. As a result of this, I'm planning on making this plugin add the external storage permissions as a configurable option.
This plugin is currently not compatible with cordova-android@10/nightly
. So please only test using cordova-android@9.1
@breautek thanks for the proposed solution.
Does this also fix Writing to external Files like ( /Download ) on SDK 30 ?
@breautek thanks for the proposed solution.
Does this also fix Writing to external Files like ( /Download ) on SDK 30 ?
It should. I didn't test writing to the Downloads
directory explicitly, but feel free to augment my test app https://github.com/breautek/cordova-file-api30-test-app/blob/86b1c9135f1e68e62ddc2d874fd82cd933cb9392/www/js/index.js#L173
@breautek thanks for the proposed solution. Does this also fix Writing to external Files like ( /Download ) on SDK 30 ?
It should. I didn't test writing to the
Downloads
directory explicitly, but feel free to augment my test app https://github.com/breautek/cordova-file-api30-test-app/blob/86b1c9135f1e68e62ddc2d874fd82cd933cb9392/www/js/index.js#L173thanks for the proposed solution.
My fork is not intended to be a solution, I just want to make sure that my changes are covering API 30 properly in wide range of use cases before I prepare a PR.
@breautek In your test you write to file to externalApplicationStorageDirectory
, I tested it . That works fine.
I intend to save the file to Download
folder inside externalRootDirectory
.
externalRootDirectory is readable, but not writable. You cannot create directories or files inside this directory anymore.
I read your previous comment , but Is there any workaround or other plugin/method to save files to the public android Download
directory ?
@interstellerS I know the thread is long, but we have already discussed that previously.
The current workaround is to use the npm version of this plugin and not the dev version, just run to be sure you're using the npm version
cordova plugin rm cordova-plugin-file
cordova plugin add cordova-plugin-file
The npm version does not use requestLegacyExternalFlag
on which Google complains, on and after Android 11.
Then install the plugin cordova-plugin-x-socialsharing
and use the options.files
Array property. This let the users save the file wherever they want, instead of you trying to find the correct path. If you want to be sure your users are able to share to the file system, you can suggest them to install this simple APP, which is indeed just an addon (it will not create any new icon and it's not openable, it simply allows users to share a file to the file system).
I would like to invite people to try out my fork and give it a test: https://github.com/breautek/cordova-plugin-file/tree/feat/api30
My fork removes the
requestLegacyExternalFlag
which means it should work on both API 29 and API 30+. It ensures that it prompts for the proper permission in read/write external storage.Here are some highlight changes:
- It's possible that you've already granted or denied external storage permissions, in which case it may just work or it may not work. If you're getting a file not found kind of errors, or file listings are simply empty when you expect there to be content, that probably means you're lacking permissions. Android does not tell us that a file exists but you lack permissions to view; it just gives a file not found error. I assume this is for privacy reasons.
- You can use
adb shell pm reset-permissions
to reset your permissions on all apps back to a state of "not requested", so that you can test as if the user is running your app for the first time.externalRootDirectory
is readable, but not writable. You cannot create directories or files inside this directory anymore.- I used https://github.com/breautek/cordova-file-api30-test-app as a test app. If something is not working right for you on my fork, feel free to make a pull request and add a test case.
- I've seen Google is cracking down, requiring external use via
READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE
; in order to use these permissions (and this plugin for accessing external storage) you will need to give justification. You'll going to have to evaluate if your app needs external storage access, and if not, then start migrating to internal storage. As a result of this, I'm planning on making this plugin add the external storage permissions as a configurable option.- This plugin is currently not compatible with
cordova-android@10/nightly
. So please only test usingcordova-android@9.1
Im having a use case of reading the files from shared storage which is failing in android 11 currently. I had tried your solution. It asks for the permissions required and requestLegacyExternalFlag is removed. But still unable to read the files.
As the new apps would need to target SDK 30, any workaround for this issue? Any way to read files from shared storage(Downloads/images..).
Thanks
Hello, I confirm that it works with sdk 29.0.3. I am writing an application that saves files that come either from a web server (downloaded) or created by my application. I'm using sdk 30 and it works for downloaded files with "cordova-plugin-file-transfer" but not locally with "cordova-plugin-file" Can someone explain me the difference between the two? Thanks
I store a created file inside files folder in the internal storage and i want the user to be able to send it via email using cordova-plugin-x-socialshearing. But when the Gmail app or Google Drive opens it says that the file couldn't be attached. I don't understand where the problem is, where this file must be stored...
Check the file size. File larger than 25 mb won't be attached. I have no issues with the plugin and gmail, I use it for reporting an issue in my app to attach log files.
Chooser
@Vatsov file chooser (this.chooser.getFile()) also returns base64 data, you can convert that into blob, then use the this.file.writeFile() method to save the file into your app directory
Hello, I was facing a similar problem, when I needed to read a file from the storage of an Android device, the plugin returns null in the contents of the file.
The reason for this is the "partial" permission implemented in Android 11, although the user gives the storage permission this always stays in "only multimedia content".
So what I did was send the user to the settings section of the app and tell them to change the storage permission to "allow access to all files". And with that change I was already able to read the files in any directory on the device on Android 11.
Note:
You need to implement this in your config.xml for the storage permission to work well on Android 11
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
I hope and this will help you.
Tell the user to allow the app to access all files is not a good practice, it poses potential security problems and it is exactly that which Google was trying to avoid with the new policies on Android 11.
A sábado, 5/06/2021, 16:41, Joshua Eduardo González Ruíz < @.***> escreveu:
Hello, I was facing a similar problem, when I needed to read a file from the storage of an Android device, the plugin returns null in the contents of the file.
The reason for this is the "partial" permission implemented in Android 11, although the user gives the storage permission this always stays in "only multimedia content".
So what I did was send the user to the settings section of the app and tell them to change the storage permission to "allow access to all files". And with that change I was already able to read the files in any directory on the device on Android 11.
Note: You need to implement this in your config.xml for the storage permission to work well on Android 11
I hope and this will help you.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/apache/cordova-plugin-file/issues/426#issuecomment-855249720, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6M4DLMZZOLJK7STKAVVOLTRIZR7ANCNFSM4SAAWWGQ .
Tell the user to allow the app to access all files is not a good practice, it poses potential security problems and it is exactly that which Google was trying to avoid with the new policies on Android 11. A sábado, 5/06/2021, 16:41, Joshua Eduardo González Ruíz < @.***> escreveu: …
I know, but that was the only way I could get the process going. If I find any other way, I will gladly share it around here until there is an official form.
Hello, i found plugin for save image base64 in public directory, using api Media Store. Work in android 10 and 11. I hope and this will help someone.
https://github.com/Heartade/cordova-plugin-android-mediastore
Hello, I was facing a similar problem, when I needed to read a file from the storage of an Android device, the plugin returns null in the contents of the file.
The reason for this is the "partial" permission implemented in Android 11, although the user gives the storage permission this always stays in "only multimedia content".
So what I did was send the user to the settings section of the app and tell them to change the storage permission to "allow access to all files". And with that change I was already able to read the files in any directory on the device on Android 11.
Note: You need to implement this in your config.xml for the storage permission to work well on Android 11
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
I hope and this will help you.
Unfortunately this is not working for me!
I try to write a file from a html input tag. This is working with eg files from the Downloads-Folder. But it is not working with files from google drive. Setting the permission to access all files ("android.permission.MANAGE_EXTERNAL_STORAGE") does not change this behaviour. I get this error message:
DOMException: The requested file could not be read, typically due to permission problems that have occurred after a reference to a file was acquired.
Hello, i found plugin for save image base64 in public directory, using api Media Store. Work in android 10 and 11. I hope and this will help someone.
https://github.com/Heartade/cordova-plugin-android-mediastore
@HarelM @breautek Maybe the solution is mediaStore
For android 10 and 11 that's probably true, but if you need to support 9 in one plugin it's hard...
- This plugin is currently not compatible with
cordova-android@10/nightly
. So please only test usingcordova-android@9.1
Is it compatible with cordova-android@10 now? I tested it and it works for me so far.
@breautek please highlight your comment about the test fork you created, because people are not reading it since the thread is becoming too long.
Newcomers: test the following fork because it was made to overcome all the problems related with storage on Android 11 and beyond
cordova plugin add https://github.com/breautek/cordova-plugin-file/tree/feat/api30
and downgrade to cordova 9.1 if necessary (latest is 10)
npm i -g cordova-android@9.1
More info here: https://github.com/apache/cordova-plugin-file/issues/426#issuecomment-830841544
@breautek any update?
@breautek please highlight your comment about the test fork you created, because people are not reading it since the thread is becoming too long.
Newcomers: test the following fork because it was made to overcome all the problems related with storage on Android 11 and beyond
cordova plugin add https://github.com/breautek/cordova-plugin-file/tree/feat/api30
and downgrade to cordova 9.1 if necessary (latest is 10)
npm i -g cordova-android@9.1
More info here: #426 (comment)
but google not allowed android api 29 anymore we must have to update api level 30 which is only possible by cordova 10.0.0 so we must solved this issue to upload new apk in playstore.
I've read through this entire thread (trying to follow as much as I can), the Google docs on scoped storage, and other issues and stackoverflow posts and I'm still not 100% sure that this issue applies to me, so if anyone can tell me I'd really appreciate it...
For a feature I'm working on (involving opening a video, overlaying text on it with canvas, and capturing the output) I need the video and page to be same origin. So I've tried to use API30 and cordova-android@10.0.1 for the WebViewAssetLoader functionality to serve my app from https://localhost.
The problem I have is that after updating (from API29 / cordova-android@9.1), when I select a video from the photo library, using previously working code like this:
navigator.camera.getPicture(
file => {
file = file.indexOf('file://') === 0 ? file : 'file://' + file
window.resolveLocalFileSystemURL(file, (fileEntry) => {
this.video = fileEntry.toInternalURL() // Vue.js data property that populates video src
})
},
() => {},
{
destinationType: Camera.DestinationType.FILE_URI,
sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
mediaType: Camera.MediaType.VIDEO
}
)
}
... I get an error like this in the console:
GET cdvfile://localhost/sdcard/DCIM/Camera/VID_20210802_200106.mp4 net::ERR_UNKNOWN_URL_SCHEME
If I go back to API29 / cordova-android@9.1 it works fine again.
Where I'm not sure if this is the same issue is from comments like this one by @HarelM https://github.com/apache/cordova-plugin-file/issues/426#issuecomment-751977160 :
@Vatsov Are you reading a file a user selects? If so I don't think there's an issue that is related to Android 11, or at least I hope not as you open the file picker and this should be OK even in Android 11 as far as I know.
...and things that I read in google's docs that seem to suggest that reading the users photo/video library is treated differently to accessing other types of file.
Regardless, I've still tried adding the MANAGE_EXTERNAL_STORAGE permission, but that hasn't seemed to have any effect.
So can anyone tell me if this is the same issue? Or is it a different one caused by the upgrade to API30 and/or cordova-android@10.0.1 ?
To be honest I'm feeling a little out of my depth here and would very much like to get back to my cosy javascript safe place! :)
Thanks in advance for any help or suggestions!
@skmbr on my side the latest working versions of android and camera plugins are: "cordova-android": "^9.1.0", "cordova-plugin-camera": "^5.0.2",
I dont think that your issue is related with this. Its look like native Java code error from incompatible versions of cordova-android and cordova-plugin-camera. Try to check Java stacktrace in Android Studio logging.
@skmbr on my side the latest working versions of android and camera plugins are: "cordova-android": "^9.1.0", "cordova-plugin-camera": "^5.0.2",
I dont think that your issue is related with this. Its look like native Java code error from incompatible versions of cordova-android and cordova-plugin-camera. Try to check Java stacktrace in Android Studio logging.
Thanks @sytolk
The console error I posted is from the javascript console in chrome devtools after building my app in debug mode.
I assumed it wasn't anything to do with the camera plugin as that's returning the correct internal file path. I thought cordova-plugin-file was responsible for resolveLocalFileSystemURL and cdvfile:// links?
Will I need to wait for cordova-android@10 support in cordova-plugin-camera ?
I've read through this entire thread (trying to follow as much as I can), the Google docs on scoped storage, and other issues and stackoverflow posts and I'm still not 100% sure that this issue applies to me, so if anyone can tell me I'd really appreciate it...
For a feature I'm working on (involving opening a video, overlaying text on it with canvas, and capturing the output) I need the video and page to be same origin. So I've tried to use API30 and cordova-android@10.0.1 for the WebViewAssetLoader functionality to serve my app from https://localhost.
The problem I have is that after updating (from API29 / cordova-android@9.1), when I select a video from the photo library, using previously working code like this:
navigator.camera.getPicture( file => { file = file.indexOf('file://') === 0 ? file : 'file://' + file window.resolveLocalFileSystemURL(file, (fileEntry) => { this.video = fileEntry.toInternalURL() // Vue.js data property that populates video src }) }, () => {}, { destinationType: Camera.DestinationType.FILE_URI, sourceType: Camera.PictureSourceType.PHOTOLIBRARY, mediaType: Camera.MediaType.VIDEO } ) }
... I get an error like this in the console:
GET cdvfile://localhost/sdcard/DCIM/Camera/VID_20210802_200106.mp4 net::ERR_UNKNOWN_URL_SCHEME
If I go back to API29 / cordova-android@9.1 it works fine again.
Where I'm not sure if this is the same issue is from comments like this one by @HarelM #426 (comment) :
@Vatsov Are you reading a file a user selects? If so I don't think there's an issue that is related to Android 11, or at least I hope not as you open the file picker and this should be OK even in Android 11 as far as I know.
...and things that I read in google's docs that seem to suggest that reading the users photo/video library is treated differently to accessing other types of file.
Regardless, I've still tried adding the MANAGE_EXTERNAL_STORAGE permission, but that hasn't seemed to have any effect.
So can anyone tell me if this is the same issue? Or is it a different one caused by the upgrade to API30 and/or cordova-android@10.0.1 ?
To be honest I'm feeling a little out of my depth here and would very much like to get back to my cosy javascript safe place! :)
Thanks in advance for any help or suggestions! I dont try this but i think you can solve your issue using this as suggest here
<preference name="AndroidInsecureFileModeEnabled" value="true" />
@krunalsk007
I dont try this but i think you can solve your issue using this as suggest here
<preference name="AndroidInsecureFileModeEnabled" value="true" />
No, that puts everything back to using file://
I need https://localhost and WebViewAssetLoader to solve my origin issues.
Actually i have the same problem while i upgraded to API 30. I got error code 9 also. As google upgraded its android protocol set for storage we have to use "scoped storage".
In my application i have to capture image, then i have to compress using Javascript image compressors (usually gives better quality than the "cordova-plugin-camera
" compressors and have more flexibility) and have to write compressed files using "cordova-plugin-file
" to storage.
Previously i am using "LocalFileSystem.PERSISTENT
" and with API 30 i couldn't access that region of my file system due to restrictions imposed.
Example:-
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) { console.log('file system open: ' + fs.name);fs.root.getFile("newPersistentFile.txt", { create: true, exclusive: false }, function (fileEntry) {console.log("fileEntry is file?" + fileEntry.isFile.toString()); // fileEntry.name == 'someFile.txt' // fileEntry.fullPath == '/someFile.txt' writeFile(fileEntry, null);}, onErrorCreateFile); }, onErrorLoadFs);
LocalFileSystem.PERSISTENT
" with "cordova.file.dataDirectory
" and it worked. Its also logically correct as per the restrictions imposed now a days. Example :-
window.resolveLocalFileSystemURL(cordova.file.dataDirectory, function (dirEntry) { console.log('file system open: ' + dirEntry.name); var isAppend = true; createFile(dirEntry, "fileToAppend.txt", isAppend); }, onErrorLoadFs);
This example can also be used to create new files, if you provide unique file name each time. Like below.
Example :-
window.resolveLocalFileSystemURL(cordova.file.dataDirectory, function(fs) { createFile(fs, outputfilename); function createFile(dirEntry, fileName, isAppend) { // Creates a new file or returns the file if it already exists (use unique file name each time) . dirEntry.getFile(fileName, { create: true, exclusive: false }, function(fileEntry) {writeFile(fileEntry, result); }, function(err) { console.log(err); });}function writeFile(fileEntry, dataObj) { // Create a FileWriter object for our FileEntry (log.txt). fileEntry.createWriter(function(fileWriter) {fileWriter.onwriteend = function() {console.log("File written successfully...");console.log(fileEntry); };fileWriter.onerror = function(e) { console.log("Failed to write file: " + e.toString()); };// If data object is not passed in, // create a new Blob instead. if (!dataObj) { dataObj = new Blob(['some file data'], { type: 'text/plain' }); }fileWriter.write(dataObj); }); } }, function(error) { console.log(error); });
Correct me if something i missed. Thank you all.
I've read through this entire thread (trying to follow as much as I can), the Google docs on scoped storage, and other issues and stackoverflow posts and I'm still not 100% sure that this issue applies to me, so if anyone can tell me I'd really appreciate it... For a feature I'm working on (involving opening a video, overlaying text on it with canvas, and capturing the output) I need the video and page to be same origin. So I've tried to use API30 and cordova-android@10.0.1 for the WebViewAssetLoader functionality to serve my app from https://localhost. The problem I have is that after updating (from API29 / cordova-android@9.1), when I select a video from the photo library, using previously working code like this:
navigator.camera.getPicture( file => { file = file.indexOf('file://') === 0 ? file : 'file://' + file window.resolveLocalFileSystemURL(file, (fileEntry) => { this.video = fileEntry.toInternalURL() // Vue.js data property that populates video src }) }, () => {}, { destinationType: Camera.DestinationType.FILE_URI, sourceType: Camera.PictureSourceType.PHOTOLIBRARY, mediaType: Camera.MediaType.VIDEO } ) }
... I get an error like this in the console:
GET cdvfile://localhost/sdcard/DCIM/Camera/VID_20210802_200106.mp4 net::ERR_UNKNOWN_URL_SCHEME
If I go back to API29 / cordova-android@9.1 it works fine again. Where I'm not sure if this is the same issue is from comments like this one by @HarelM #426 (comment) :@Vatsov Are you reading a file a user selects? If so I don't think there's an issue that is related to Android 11, or at least I hope not as you open the file picker and this should be OK even in Android 11 as far as I know.
...and things that I read in google's docs that seem to suggest that reading the users photo/video library is treated differently to accessing other types of file. Regardless, I've still tried adding the MANAGE_EXTERNAL_STORAGE permission, but that hasn't seemed to have any effect. So can anyone tell me if this is the same issue? Or is it a different one caused by the upgrade to API30 and/or cordova-android@10.0.1 ? To be honest I'm feeling a little out of my depth here and would very much like to get back to my cosy javascript safe place! :) Thanks in advance for any help or suggestions! I dont try this but i think you can solve your issue using this as suggest here
<preference name="AndroidInsecureFileModeEnabled" value="true" />
Is your Application has File permissions enabled ? Check Android Manifest for these three
`
if not add these in your AndroidManifest.xml
. Try to build with these. if problem exists reply me under same thread.
I work on an application that allows users to create directories in externalRootDirectory
and save various files into these directories (QR codes, log files, csv files, etc). Users expect to be able to copy files off of the tablet when using a Windows computer to explore the tablet file system.
After spending a bunch of time trying to migrate this functionality to allow files to be saved to externalApplicationStorageDirectory
, I discovered a potentially much simpler solution. From my testing so far, applications using this plugin and opting in to Scoped Storage can still create directories and write files to the Documents
folder in externalRootDirectory
.
I tested this on API 29 with Scoped Storage enabled on an Android 11 tablet by going to Developer Options -> App Compatibility Changes -> FORCE_ENABLED_SCOPED_STORAGE
and
all of the "Enabled for targetSdkVersion > 29 features" except for NATIVE_HEAP_POINTER_TAGGING
. I have no idea why this flag prevents files from being created, but luckily it is not (currently) required for apps targeting API 30.
I then targeted API 30 and added the following to config.xml
:
<edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application">
<application android:allowNativeHeapPointerTagging="false"/>
</edit-config>
My application seems to function as it did without scoped storage as long as I prefix my paths with Documents/
when targeting API 29 and API 30. We will need to train our users to expect files to be in this location, but (so far) this seems much simpler than trying to use app-specific storage.
I hope this helps someone else, or hope someone tells me why I'm wrong!
@anshuman61 : MANAGE_EXTERNAL_STORAGE
is not a long-term solution. Once the Play Store requires applications to target API 30 later this year, Google is also cracking down on this permission and will not allow you to upload apps to the Play Store that use this permission unless the central purpose is file-system manipulation (a backup app, for example). Even in that case, you have to submit an application to attain this permission including a demonstration of why your app requires MANAGE_EXTERNAL_STORAGE
.
This is quite a thread. I was looking at it trying to figure out why I couldn't read a file after the user selects it from a system file picker. My issue is specifically for targeting API level 30, and my application was attempting to resolve a given URL to a path on the phone, then use a FileInputStream to read the file and write it into a my applications data. The solution to this problem is to call something like context.getContentResolver().openInputStream(uri) to read the file instead. I'm still working out how to connect everything, because right now cordova-android@10, cordova-plugin-filechooser, cordova-plugin-filepath, and cordova-plugin-file are all in use. Just putting this out there, even though it won't help anyone trying to figure out why they can't write files with scoped storage.
Hello, i found plugin for save image base64 in public directory, using api Media Store. Work in android 10 and 11. I hope and this will help someone.
https://github.com/Heartade/cordova-plugin-android-mediastore
Thanks! This seems to work for us. In our ionic cordova app we want users to be able to download photos and videos stored in our protected app space to their media directory.
We have extended the repo downloading video files:
https://github.com/konnectappdev/cordova-plugin-android-mediastore
Hello, I just want to share a solution I found to my problem as it's related to this thread.
Problem with SDK 30 : Our team used the path externalApplicationStorageDirectory to store some assets of the application, wich are downloaded the first time the user connect to the application. But we weren't able to access those files, and got an ACCESS_DENIED error.
Solution : I made a little modification in CordovaActivity.java in init() function
protected void init() {
appView = makeWebView();
createViews();
if (!appView.isInitialized()) {
appView.init(cordovaInterface, pluginEntries, preferences);
}
/********** MODIFICATION SDK 30 **********/
WebView webView = (SystemWebView)(appView.getEngine().getView());
WebSettings webSettings = webView.getSettings();
webSettings.setAllowFileAccess(true);
/**********************************/
cordovaInterface.onCordovaInit(appView.getPluginManager());
// Wire the hardware volume controls to control media if desired.
String volumePref = preferences.getString("DefaultVolumeStream", "");
if ("media".equals(volumePref.toLowerCase(Locale.ENGLISH))) {
setVolumeControlStream(AudioManager.STREAM_MUSIC);
}
}
you also need to add these import :
import android.webkit.WebView;
import android.webkit.WebSettings;
import org.apache.cordova.engine.SystemWebView;
Hope this can help some of you :)
Hello, I just want to share a solution I found to my problem as it's related to this thread.
Problem with SDK 30 : Out team used the path externalApplicationStorageDirectory to store some assets of the application, wich are downloaded the first time the user connect to the application. But we weren't able to access those files, and got an ACCESS_DENIED error.
Solution : I made a little modification in CordovaActivity.java in init() function
protected void init() { appView = makeWebView(); createViews(); if (!appView.isInitialized()) { appView.init(cordovaInterface, pluginEntries, preferences); } /********** MODIFICATION SDK 30 **********/ WebView webView = (SystemWebView)(appView.getEngine().getView()); WebSettings webSettings = webView.getSettings(); webSettings.setAllowFileAccess(true); /**********************************/ cordovaInterface.onCordovaInit(appView.getPluginManager()); // Wire the hardware volume controls to control media if desired. String volumePref = preferences.getString("DefaultVolumeStream", ""); if ("media".equals(volumePref.toLowerCase(Locale.ENGLISH))) { setVolumeControlStream(AudioManager.STREAM_MUSIC); } }
you also need to add these import :
import android.webkit.WebView; import android.webkit.WebSettings; import org.apache.cordova.engine.SystemWebView;
Hope this can help some of you :)
I also want to include what Google says about setting setAllowFileAccess
to true
, for informational purposes:
setAllowFileAccess
Enables or disables file access within WebView. Note that this enables or disables file system access only. Assets and resources are still accessible using
file:///android_asset
andfile:///android_res
.Note: Apps should not open file:// URLs from any external source in WebView, don't enable this if your app accepts arbitrary URLs from external sources. It's recommended to always use androidx.webkit.WebViewAssetLoader to access files including assets and resources over http(s):// schemes, instead of file:// URLs. To prevent possible security issues targeting Build.VERSION_CODES.Q and earlier, you should explicitly set this value to false.
I changed the android version in which the application is focused adding this tag in the config.xml:
<preference name="android-targetSdkVersion" value="28" />
And this change allows to save files into the device using on Android 8, Android 9, Android 10 and Android 11.
I did tests on Android emulator and physical devices working correctly.
The Android documentation recommends to change the API Level version to avoid the scoped storage feature on Android 10.
You get more information about scoped storage feature here: https://developer.android.com/training/data-storage/use-cases#opt-out-scoped-storage
I hope this information will be helpful.
I changed the android version in which the application is focused adding this tag in the config.xml:
<preference name="android-targetSdkVersion" value="28" />
And this change allows to save files into the device using on Android 8, Android 9, Android 10 and Android 11. I did tests on Android emulator and physical devices working correctly.The Android documentation recommends to change the API Level version to avoid the scoped storage feature on Android 10.
You get more information about scoped storage feature here: https://developer.android.com/training/data-storage/use-cases#opt-out-scoped-storage
I hope this information will be helpful.
This isn't a solution to anybody who wants to publish to the Google Play store as they require the target SDK to be set to >= 30.
I changed the android version in which the application is focused adding this tag in the config.xml:
<preference name="android-targetSdkVersion" value="28" />
And this change allows to save files into the device using on Android 8, Android 9, Android 10 and Android 11. I did tests on Android emulator and physical devices working correctly. The Android documentation recommends to change the API Level version to avoid the scoped storage feature on Android 10. You get more information about scoped storage feature here: https://developer.android.com/training/data-storage/use-cases#opt-out-scoped-storage I hope this information will be helpful.This isn't a solution to anybody who wants to publish to the Google Play store as they require the target SDK to be set to >= 30.
You're right, it is necessary set API Level to 30 for Play Store but I forced the API Level to 30 testing again in Android 8, 9, 10 and 11 and everything worked fine.
This is the preference tag:
<preference name="android-targetSdkVersion" value="30" />
Also, I tested that an application with this tag could be uploaded to Play Store Console and the file was accepted.
You're right, it is necessary set API Level to 30 for Play Store but I forced the API Level to 30 testing again in Android 8, 9, 10 and 11 and everything worked fine.
When running your tests, did you uninstall the app and its data from your device first? Should test the clean install use case, where a user has never had the app installed before.
You're right, it is necessary set API Level to 30 for Play Store but I forced the API Level to 30 testing again in Android 8, 9, 10 and 11 and everything worked fine.
When running your tests, did you uninstall the app and its data from your device first? Should test the clean install use case, where a user has never had the app installed before.
Sure, I cleaned the data and uninstall the application before test in each Android version.
Feature Request
Support the android 11 new file system based policy.
Motivation Behind Feature
Support the changes that are planned for android 11 (API level 30)
Feature Description
I'm not sure how to fully describe this, but basically support what's documented here: https://developer.android.com/about/versions/11/privacy/storage
Alternatives or Workarounds
Not targeting API level 30 until this is supported?