Comments (8)
@breautek - final update on this one. On Android, I got everything working on compiledSDK/targetSDK 33.
- Download file to custom
/MyApp/sub-folder1/
path in the users standard/Download
folder - IE:/Download/MyApp/sub-folder1/thisFile.pdf
- Got around issue if user manually deleted file from
/Download/MyApp/sub-folder1/
by triggering off of native Android error ofEEXIST
. If that error is detected, then redownload the same file and save to target with a different name (add a character1
) to the end of the filename. This gets around the Android scoping issue without having to get into complex user permissions or related issues. - Finally, using
cordova-plugin-file-opener2
, I can display anopen file
button in my app that will auto-launch a app picker for the user to select which app to use to open the file with. In THOSE apps, they ask for permission access to files downloaded by my app. The user needs to authorize my access to my app files and all is good. The same process happens if the user navigates their devicesFile Manager
to my app folders and tries to open a file - they select the app, and if permissions not yet granted those apps will walk user through granting access.
An update, this worked with only the following permissions set in my config.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application android:requestLegacyExternalStorage="true" />
Now...just need to validate all this on iOS.
from cordova-plugin-file-transfer.
I figured out what is going on. If your app downloads the file and then the user manually deletes the file you cannot save the file with the same name again; this is related to some Android caching of some sort. I found this reference here:
itinance/react-native-fs#1078
https://learn.microsoft.com/en-us/answers/questions/932579/after-manually-delete-a-file-and-use-fileoutputstr
Apparently this started in Android 11+. The proper solutions offered haven't worked for me. But the hack solution does work.
If the user manually deleted the file then use the error to "EEXIST" to determine that, then redownload the file again and save it with a slightly different name...add a random character to the end of the name and it will save.
from cordova-plugin-file-transfer.
Whats crazy about this issue is after manually deleting the file with the phones File Manager, my app reads the directory and doesn't see the file. But when writing the file, with the same previous file name, it can't do it because Android says the file is still there. So why is one saying its not there and the other is?
from cordova-plugin-file-transfer.
It sounds like you're experiencing scoped storage rules, which is effective since API 29. I wrote a blip in a PR for the file plugin but the same would apply here.
Basically scoped storage applies to all external storage partitions (/storage/emulated/0/
is considered an external storage partition, which is used to emulate external storage when a physical medium is not available).
With scoped storage, applications do not require permission to read or write files, however it can only read and write files that the application itself has written to. So for example, if another app (Say the chrome browser) downloads a file and stores it at: /storage/emulated/0/Download/MyApp/BYG/REIA_Check_List.doc
, that file will not be read or writeable by your app since the file is not owned by your app.
Listing directories will not show files that your app doesn't have access to. However attempting to write to a filename that already exists will be blocked.
There is limited capability of reading files owned by other apps with READ_EXTERNAL_STORAGE
permission on pre-API 33 devices, and READ_MEDIA_AUDIO
, READ_MEDIA_VIDEO
, and READ_MEDIA_IMAGES
for API 33+ devices. If you're observant you'll notice that there are only permissions for multimedia assets, but not nothing for document files. This is because scoped storage only allows reading media files. So reading your .doc file is not possible via a file API. Additionally, there are no write permissions for writing to files owned by other apps. You cannot modify a file owned by another app via the file api.
The file transfer plugin uses the file plugin behind the scenes, which naturally uses the file apis.
So how do work with non-media files?
Well the native way is to use a non-file API, and use something called a MediaStore. Apache doesn't have a plugin that interfaces with this MediaStore outside of context specific plugins (like the camera plugin which deals with images/video). But there are third-party plugins available that interfaces with the media store with a generic API: https://www.npmjs.com/search?q=ecosystem%3Acordova%20storage%20access%20framework
If placing these files in external storage is a requirement, then you'll probably need to use the file transfer plugin to download into your internal cache directory (cordova.file.cacheDirectory
), then use a media store plugin to transfer from the internal cache directory to media store.
Lastly if you support API 29, then using MediaStore APIs is a requirement because Android lacks a filesystem API into scoped storage, which was only introduced in API 30. So accessing any external storage mechanism on API 29 is blocked.
If you think any of this sounds bizarre, then you're not alone. You can read learn more about scoped storage in the android docs
from cordova-plugin-file-transfer.
@breautek - As always Norman, you give very thorough explanations and I REALLY appreciate your responses and the time you put into your responses. Android needs to hire you to rewrite their docs because they suck.
Based on what you wrote above about reading scoped files I have an additional question. If using this file-transfer
plugin I am able to download the files. My app doesn't need to modify/edit change the docs, just download so the user can reference/read them. If my app downloads thisFile.pdf
to my own MyApp/Sub-Folder/thisFile.pdf
location, can my app open that file into another app PDF viewer - it should still work yes? And if the user navigates to the file via their phones File Manager
they should be able to open it in what ever app they choose correct?
So long as users can download files from my app and open them other apps without issue I am going to continue to use this plugin. It keeps it simple and clean. All I have to do now add code to download the file again, changing the name slightly, if the FileTransfer gets the error with EEXIST
in it.
from cordova-plugin-file-transfer.
If my app downloads thisFile.pdf to my own MyApp/Sub-Folder/thisFile.pdf location, can my app open that file into another app PDF viewer - it should still work yes?
This part I'm not 100% sure, but I don't think it will work out of the box. The part that makes it more difficult is the fact that your file are document files, not a media file. (Media as in an image, video or audio).
Normally if you had a image file owned by App A. App B could read it without explicit permission from App A if App B has READ_EXTERNAL_STORAGE
or READ_MEDIA_IMAGE
permission granted.
However because you're working with document files, that convenience escape hatch is not available. In order to share document files with other apps, App A needs to implement something called a ContentProvider
which can accept and grant read (or write) permission to App B.
I could be completely wrong here.... but I believe the typical flow in that kind of use case is that:
- App B uses a file picker intent to open up a document tree where they may pick your App A's
thisFile.pdf
. - This will will trigger a ContentProvider request implemented by App A where
- App A can decide to grant temporary permission to App B.
- App B can then read the document file to use.
Cordova doesn't implement any content providers which is why I don't think it will just work. And I think implementing one will be difficult since the details of a content provider will be largely app-specific.
I don't have a complete understanding on the content provider concepts in Android, it's not something I have actually dabbled with. But it is the mechanism for sharing content between apps, from what I can understand.
from cordova-plugin-file-transfer.
@breautek - well....good news. Changing the name allows for redownload of file. And after downloading, navigating to folder with phones general file manager allowed me to open the file with another app. However, the other app did require permissions to access the file; it opens dialog "Go To Settings", which then opens to "All Files Access" forcing the user to allow access for the app they choose to view the file with. Tried it on several different app types and it was the same for all of them.
The equally good news is that the other app asks for the permissions, so I don't have to code in my app giving permissions. I don't want the user viewing files in my app anyway...too many issues rendering different file formats in my app - just easier to let native apps do it.
function priFileDL(fInfo){
startStatus(fInfo.cfID,"black","Starting download...") ;
var fileTransfer = new FileTransfer();
var folderPath=fInfo.dir+fInfo.cfSave ;
var onSuccess= function(e){
fileDone(fInfo,e) ;
if (ionic.Platform.isIOS()) {
fileMove(folderPath) ;
}
};
var onError=function(e) {
// this handle issue if user had downloaded file before
// and then manually deleted it from a file manager
// this appends the name, making it a unique download
if (e.exception.includes("EEXIST")) {
var n = fInfo.cfSave.split(".") ;
n[0] += "1" ;
fInfo.cfSave = n.join(".") ;
priFileDL(fInfo) ;
} else {
fileError(1,e,fInfo) ;
}
};
fileTransfer.onprogress = function(pe) {
fileProgress(pe,fInfo) ;
}
fileTransfer.download(fInfo.url,folderPath,onSuccess,onError);
}
from cordova-plugin-file-transfer.
@breautek - btw...all of this was on Android. I haven't tested iOS yet. The other issue now is how a user, from within my app, can click a button that then opens the file in another app using some kind of app picker. Trying cordova-plugin-file-opener2
as a first stab at it, but so far no luck.
from cordova-plugin-file-transfer.
Related Issues (20)
- Server issue: Cordova flie-transfer-plugin working on UAT server but not on Production server
- cordova-plugin-file-transfer is not working with cordova 11 HOT 2
- cordova plugin add cordova-plugin-file-transfer Not working HOT 2
- Compatibility with cordova-plugin-file@7 Android URLs HOT 14
- This plugin seems to be no longer supported HOT 1
- Cordova 11 > Android incompatible HOT 15
- With iOS, I think -file-transfer needs to be updated to work with -plugin-file v7 HOT 3
- how do i install 2.0.0-dev? HOT 1
- EPERM (Operation not permitted) HOT 1
- cordova-plugin-file-transfer is not working with ios HOT 2
- Longer downloads fail silently when app is backgrounded on iOS HOT 1
- Kindly advise if there is an alternative to FileTransfer / FileUpload for use with Capacitor 4. Thanks HOT 3
- Upload was not working in API level 32 in Android HOT 2
- Can't resolve 'cordova-plugin-file-transfer' HOT 1
- Undeprecate this plugin HOT 4
- The plugin 2.0.0-dev will not load on Android 6.0 and below. HOT 2
- `download` method failing on cordova / android platform with `java.lang.NullPointerException` exception HOT 6
- open failed: ENOENT (No such file or directory) HOT 2
- There is any way to download image from POST API
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from cordova-plugin-file-transfer.