Cordova Sample: Check for a file and download if it isn't there

This post is more than 2 years old.

I've begun work on trying to answer the questions I gathered concerning Cordova's FileSystem support. As I work through the questions I'm trying to build "real" samples to go along with the text. My first sample is a simple one, but I think it is pretty relevant for the types of things folks may do with Cordova and the file system - checking to see if a file exists locally and if not - fetching it.

I'll begin by sharing the code and then explaining the parts. Here is the entire JavaScript file for the application. (Earlier today, Andrew Grieve shared a way my code could be simplified by a good 1/3rd. The code below reflects his update and has been changed since my original writing of the blog post.)

document.addEventListener("deviceready", init, false);

//The directory to store data
var store;

//Used for status updates
var $status;

//URL of our asset
var assetURL = "https://raw.githubusercontent.com/cfjedimaster/Cordova-Examples/master/readme.md";

//File name of our important data file we didn't ship with the app
var fileName = "mydatafile.txt";

function init() {
	
	$status = document.querySelector("#status");

	$status.innerHTML = "Checking for data file.";

	store = cordova.file.dataDirectory;

	//Check for the file. 
	window.resolveLocalFileSystemURL(store + fileName, appStart, downloadAsset);

}

function downloadAsset() {
	var fileTransfer = new FileTransfer();
	console.log("About to start transfer");
	fileTransfer.download(assetURL, store + fileName, 
		function(entry) {
			console.log("Success!");
			appStart();
		}, 
		function(err) {
			console.log("Error");
			console.dir(err);
		});
}

//I'm only called when the file exists or has been downloaded.
function appStart() {
	$status.innerHTML = "App ready!";
}

Ok, let's break it down. The first step is to check to see if our file exists already. The question is - where should we store the file? If you look at the docs for the FileSystem, you will see that the latest version of the plugin adds some useful aliases for common folders. Unfortunately, the docs are not exactly clear about how some of these aliases work. I asked for help (both on the PhoneGap Google group and the Cordova development list) and got some good responses from Kerri Shotts and Julio Sanchez.

The directory that I thought made sense, cordova.file.applicationStorageDirectory, is incorrectly documented as being writeable in iOS. A pull request has already been filed to fix this mistake. For my application, the most appropriate directory is the next one, cordova.file.dataDirectory. Once I have my directory alias, I can make use of resolveLocalFileSystem on the directory plus desired file name to see if it exists. The third argument, downloadAsset, will only be run on an error, in this case a file not existing.

If the file does not exist, we then have to download it. For this we use a second plugin, FileTransfer. This is where one more point of confusion comes in. We need to convert that earlier DirectoryEntry object, the one we used to get an API for files and directories, back to a URL so we can give a path to the Download API.

So to recap - we've got a few moving parts here. We've got a directory alias, built into the plugin for easily finding common folders for our application. Again, the docs here are currently a bit wrong but they should be corrected soon. From that we can quickly see if our desired file exists, and if not, use the FileTransfer plugin to download it.

Simple... but even a simple application caused me a bit of trouble, so hopefully this helps others. You can get the full source code here: https://github.com/cfjedimaster/Cordova-Examples/tree/master/checkanddownload

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Krishna posted on 7/2/2014 at 6:28 AM

I tried _cordova.file.dataDirectory_ as a way to store files in a cross platform way and it seems to be undefined. I installed the file and file-transfer plugins. From what version is this available in the file plugin?

Comment 2 by Raymond Camden posted on 7/2/2014 at 6:34 AM

1.2 and higher. Did you wait for deviceready to fire?

Comment 3 by Krishna posted on 7/2/2014 at 6:56 AM

Yes the call was inside deviceready. The reason it probably didn't work was because I used Phonegap Build. I can now see in the plugins page (https://build.phonegap.com/... that the latest version is 1.0.1.

Will I get version 1.2 of the file plugin if I use cordova CLI?

Comment 4 by Raymond Camden posted on 7/2/2014 at 7:46 AM

Yep.

Comment 5 by ManuelPaulo posted on 7/2/2014 at 9:04 AM

Thanks for this. I am testing your code to update a file regularly.
Using Network Link Conditioner, I simulated a 100% loss network.
Now the problem is, when the file transfer fails, the stored local life gets deleted. Any idea on how to prevent fileTransfer from deleting it?

Comment 6 by Raymond Camden posted on 7/2/2014 at 5:13 PM

Oh now that is interesting. I guess it would be expected as it needs to stream the data to the system and if the stream fails, it wipes the file, but I can see how this may be a surprise to people.

So I see two things:
a) We should document it in the FileTransfer download method.
b) For your specific use case, the logic should be modified to download to *another* location and on success, copy to the proper location.

Comment 7 by Raymond Camden posted on 7/3/2014 at 7:47 AM

Note - code updated.

Comment 8 by ManuelPaulo posted on 7/3/2014 at 10:06 AM

Thanks for your reply.

I think FileTransfer should have a cache mechanism like the OS's. Start downloading to .tmp file; if successful move it to the final file name, if not, delete the .tmp.

Yes, I will have to implement this. Will use fileEntry.copyTo. When not update your code to do this also? :)

Comment 9 by Raymond Camden posted on 7/3/2014 at 6:13 PM

I'd suggest filing a request for this on the issue tracker: https://issues.apache.org/j...

Comment 10 by Néstor RP posted on 7/14/2014 at 5:08 PM

Hi Raymond

Nice post, this is exactly what I was trying to do. However, I have a question about it: You don't seem to call _requestFileSystem()_ anywhere.
In every documentation or tutorial I've seen so far, _requestFileSystem()_ must be called in order to access any file in the file system. I presume that _resolveLocalFileSystemURL()_ has been introduced in version 1.2 and it's intended to be used when the full path for the file bein accessed is already known, while _requestFileSystem()_ allows navigating through the file system and look for it, but since I can't find any reason on the net why _resolveLocalFileSystemURL()_ was introduced, I'm not sure. Could you please confirm or refuse it?

Thanks!

Comment 11 by Raymond Camden posted on 7/14/2014 at 5:46 PM

My understanding is that requestFileSystem is mainly giving you an alias to the root of either the persistent or temp directory. The new aliases in the latest FS plugin makes this unnecessary (assuming you want to use one of those aliases of course).

Comment 12 by Jason U posted on 7/16/2014 at 9:36 PM

This post was great and helped me to download a file to my app. How do I set the download location to be in my \www\data directory that I have in my app?

Thanks

Comment 13 by Raymond Camden posted on 7/17/2014 at 12:06 AM

I *believe* that may be read only. I think the docs say as much here:

cordova.file.applicationDirectory - Read-only directory where the application is installed. (iOS, Android)

Comment 14 by Jason U posted on 7/17/2014 at 12:11 AM

Here's the actual goal. I ship a json file with my app. It is stored in the \www\data directory. I would like to be able to replace that file from time to time with new data. If that directory is read only then where can I store the file during development? I don't see any of the app storage directories when developing in cordova.

Thanks for all of the help, it is greatly appreciated.

Comment 15 by Raymond Camden posted on 7/17/2014 at 12:12 AM

I'd just store the new version in localStorage. Then your logic can be:

if I have it in localstorage, see if too old, and if so, update
otherwise if not too old, use it
otherwise if not there, default to one I ship with the app in file storage

Comment 16 by David Blanchard posted on 7/28/2014 at 1:14 AM

This code worked great for Android devices. But when I ran the same code on a wp8 device, the cordova.file namespace appears to be undefined as I receive an error of 'unable to get property 'dataDirectory' of undefined or null reference'. When I reference the cordova-plugin-file at git://git.apache.org/cordov..., it seems the plugin is supported by wp8, but that is the only reference to it. None of the cordova.file.* have wp8 listed.

Do you know what I should be using instead for wp8? And where I can reference the 'where to store files' table for wp8 that is an excellent summary for each other platform?

Comment 17 by Raymond Camden posted on 7/28/2014 at 6:16 AM

The docs mention that dataDirectory is not supported in WP8.

Since these are just aliases to help simplify your code, in theory, it shouldn't stop you per se, you would just need to figure out the right folder by hand. I'd google around and see what the typical directory would be for that platform.

Comment 18 by AJ Davidson posted on 8/7/2014 at 8:07 PM

First thanks. This post helped me get up to speed quickly.
On IOS I can download and open the file in Adobe smoothly. But it never finds the downloaded file. It always downloads another copy(#). I have tried Documents, Library, Temp directories.
My console logs show the right directory all the way through.
Adobe will open those very files offline, but my code doesn't find it or at least cant open it.
resolveLocalFileSystemURL is never true, but it should be.
Is adobe moving my files?
Do i need to requestFileSystem before opening a file that doesn't need to be downloaded?

I will appreciate any help and regardless thank you again for your time. I am certainly downloading and opening files in the sandbox when I wasn't before and that is useful.

Comment 19 by Raymond Camden posted on 8/7/2014 at 10:03 PM

First off... what do you mean by Adobe? Adobe what?

Comment 20 by AJ Davidson posted on 8/7/2014 at 10:26 PM

I can download the file and open it in Adobe Reader. I use a different plugin to just read PDF offline no prob.
But Forms PDFs we need to open in reader so client can email print etc the form. Console shows adobe "copying" the file. Which is actually great for us.
And it seems to still show the file in the application sandbox listing in xcode.
But it always downloads another copy it never finds the file that is there and makes the copy.

Comment 21 by Raymond Camden posted on 8/7/2014 at 10:27 PM

I honestly can't tell what you are saying here. It sounds like you modified my code to work with PDFs, and you are trying to open the PDF, is that so? If so, it does not apply to this blog post, does it?

Comment 22 by AJ Davidson posted on 8/7/2014 at 11:42 PM

the pdf opens with the fileopener plugin just fine.
it is just one call line added to your code to open the file. I could have used inAppBrower too. Its not top of mind relevant because
resolveLocalFileSystemURL is never true with or without even trying to open the file, except if I am still connected to the mac and hit run again then

your code does work great to download and open pdf in adobe reader btw, when used with the fileopener plugin.

I just cant open the downloaded file online or offline.
resolveLocalFileSystemURL cant find it or it isnt still there.

Comment 23 by Raymond Camden posted on 8/8/2014 at 12:26 AM

I'm still not quite I understand you. That being said - I'm currently investigating a bug with this on Android. Please see: https://github.com/cfjedima...

Comment 24 by AJ Davidson posted on 8/8/2014 at 12:59 AM

ty already watching that. I am teamdenver

Comment 25 by AJ Davidson posted on 8/8/2014 at 9:50 PM

I have a bit more info. I watched my apps sandboxed directory from the xcode organiser window.
I can see the file in the Documents folder after successful transfer code.
Then console says it is "copy" file to Adobe Reader Sandbox.
But as soon as I choose "Open With" Adobe Reader, and refresh organiser window, it is gone.
It is a "move" not a "copy".
resolveLocalFileSystemURL isnt true because the file is no longer there.

Comment 26 by Dave posted on 9/10/2014 at 3:38 PM

Great article! Helped me a lot. Do you also know how to delete a file? Will I have to loop through the entire dir to get the filehandle, or is it possible to delete a file straight away if you know the filename? Thank you

Comment 27 by Dave posted on 9/10/2014 at 4:16 PM

Figured that out, the success routine will have the filehandle.

Comment 28 by Nehul Agrawal posted on 9/11/2014 at 1:11 AM

Hello,

I want to use your this file checking method in loop.

I have write this something like below.

window.resolveLocalFileSystemURL(DATADIR.toURL() +"/"+ filename, appStart, function(){
ft.download(uri, dlPath, function(e){
//renderPicture(e.toURL());
alert("Successful download of "+e.toURL());
}, onError, true);

});

But it seems like i am doing some mistake here. Can you please tell me the right way?

Comment 29 by Raymond Camden posted on 9/11/2014 at 2:03 AM

Remember that these calls are async, so if you have it in a loop, there is no guarantee for which order they will finish.

Comment 30 by Nehul Agrawal posted on 9/11/2014 at 10:20 AM

Hello, thank you for your reply.
No problem with the order. But the same image is keep downloading. And even though it dont download the file. It just shows that, it has been downloaded successfully.

I generated one query here at http://stackoverflow.com/qu....

Please if there is anyway i can resolve this problem let?

Comment 31 by Raymond Camden posted on 9/12/2014 at 5:55 AM

Posted an answer there.

Comment 32 by Nehul Agrawal posted on 9/12/2014 at 1:36 PM

Thank you, you are a life saver....This one worked perfectly fine.

But i dont understand. What the problem from my method?

Thank you! Thank you so much!

Comment 33 by Raymond Camden posted on 9/12/2014 at 2:55 PM

I explained - kinda - on SO. It has to do with the nature of callbacks. If it is any consolation, I make the same mistake myself all the time.

Comment 34 by Mohammed posted on 9/25/2014 at 6:47 PM

Your effort really appreciated Raymond. Everybody loves Raymond :)

Comment 35 by rajesh rs posted on 11/26/2014 at 10:19 AM

Hi Raymond, thanks for the post.

i was trying the upload plugin for uploading a "zip" file to the server.

the zip file successfully uploads to the server but the web service does some operation based on the uploaded zip file before returning success. But on the device side i get an cordova error as below:

"File Transfer Error: The request timed out." code : 3

please let me know how to handle this or is there a way to increase the timeout for this plugin ?

Comment 36 (In reply to #35) by Raymond Camden posted on 11/26/2014 at 7:58 PM

I'm not seeing an option for that. I'd file a bug report.

Comment 37 by Prashant posted on 12/21/2014 at 2:38 PM

@Raymond.
In my case, i will be download file depending on productid. So i dont know what will be the file name and its extension. So how can i download this file.?
For eg:
http://127.0.0.1/Download.php?id=10
Will give ABC.doc
http://127.0.0.1/Download.php?id=6
Will give Five.pdf
http://127.0.0.1/Download.php?id=3
Will give Five.xls
So how can i specify my filename?

Comment 38 (In reply to #37) by Raymond Camden posted on 12/22/2014 at 1:06 PM

You would need to modify your API to return the name. For example, I'd have an API that returns the file name and the "download.php" url. You would then make a second request to get the binary data.

Comment 39 by Дадыкин Павел posted on 2/19/2015 at 10:43 AM

Hello! Thanks for your post.
But I have a question. How to delete files?
In my app I have to download zip file to cordova.file.dataDirectory, and extract it to cordova.file.dataDirectory/folder.
But when file updates on the server, I need to download new zip file and delete old zip file and all files stored in cordova.file.dataDirectory/folder.

Please, tell me, how to delete these files.
Thank you!

Comment 40 (In reply to #39) by Raymond Camden posted on 2/19/2015 at 1:02 PM

It is discussed here, http://www.html5rocks.com/e...

Comment 41 by Alessandro Belli posted on 8/4/2015 at 3:25 PM

is it possibile to make a loop for check more files?

Comment 42 (In reply to #41) by Raymond Camden posted on 8/4/2015 at 7:25 PM

Sure.

Comment 43 by Jay J. Das posted on 8/19/2015 at 10:59 AM

Hello! Raymond

Can we download the file to the downloads folder?
What should be the path for store, instead of

cordova.file.dataDirectory;

Thanks,
J

Comment 44 (In reply to #43) by Raymond Camden posted on 8/19/2015 at 11:03 AM

I don't know. I checked the File plugin (https://www.npmjs.com/packa... and there is no alias for it, but obviously if you know the full path to the downloads folder, and it is writeable by your app, then it is a simple matter.

Comment 45 (In reply to #44) by Karthikeya Mishra posted on 8/21/2015 at 11:46 AM

I have used cordova.file.externalRootDirectory to create a folder. And I downloaded the photos in that folder. But now my problem is I want to check whether the file I am downloading already exist in that folder but I am unable to get the path of that folder.

I am using Ionic framewrok. To download the image in folder I used -

$scope.downloaad= function(photoUrl, photoId, folder){
var url = photoUrl;
var targetPath = cordova.file.externalRootDirectory+"/"+folder+"/"+options.photoId+".jpg";

var trustHosts = true;
var str = {};

$cordovaFileTransfer.download(url, targetPath, str, trustHosts)
.then(function(result) {
console.log("result->" + result);
}, function(err) {
console.log("error->" + err);
});

}

Comment 46 (In reply to #45) by Raymond Camden posted on 8/21/2015 at 4:59 PM

Are you saying you want to resolve the path to a DirectoryEntry object you can work with?

Comment 47 by mralj posted on 9/1/2015 at 12:56 PM

Hey, thanks for the great article. I've tried to implement your code in my app, which has to do this: check if video exists, if it does play it, else download it and play it. But it doesn't work, problem is both every time success and fail functions get called. So if video exists app plays it, but it also downloads it again. Here is relevant part of my code:

var store = cordova.file.dataDirectory;
var filePath = store + "videoTest.mp4";

//Check for the file.
window.resolveLocalFileSystemURL(filePath, playVideo(filePath, true), transferFile(uri, filePath));

Also here is my SO question with a bit different code, but same problem: http://stackoverflow.com/qu...

Please, if it is not too much trouble, could you tell me what am I doing wrong ?

Thanks in advance !

Comment 48 (In reply to #47) by Raymond Camden posted on 9/1/2015 at 1:18 PM

I posted an answer there.

Comment 49 (In reply to #48) by mralj posted on 9/1/2015 at 2:15 PM

Hey, thanks for the fast response :)

Comment 50 by tomiwaadefokun posted on 9/16/2015 at 1:50 PM

Thanks for the great post. But how do I open the file via a link?

Comment 51 (In reply to #50) by Raymond Camden posted on 9/16/2015 at 4:26 PM

Just link to it? :)

Comment 52 by tomiwaadefokun posted on 9/16/2015 at 4:42 PM

Many thanks. Using url = entry.toURL() gives me file:///path/to/file and it doesn't open in browser and not even in inAppBrowser. Both window.open(url, '_system') and window.open(url, '_blank') did not work.

Comment 53 (In reply to #52) by Raymond Camden posted on 9/16/2015 at 4:46 PM

What happens though? You said it didn't work- did it throw an error? What did remote debugging show you?

Comment 54 (In reply to #53) by tomiwaadefokun posted on 9/16/2015 at 5:10 PM

I get "Options expected to be an object", from inAppBrowser. I have no idea what that means...

Comment 55 (In reply to #54) by Raymond Camden posted on 9/16/2015 at 5:14 PM

Double check to ensure you are running this plugin - https://github.com/apache/c...

Comment 56 (In reply to #55) by tomiwaadefokun posted on 9/16/2015 at 5:51 PM

The problem is ngCordova's InAppBrowser implementation actually requires the options to be passed as object. Now the file opens with a PDF reader but it says "Document path is not valid." Please what can be the issue? Many thanks for your time.

Comment 57 (In reply to #56) by Raymond Camden posted on 9/16/2015 at 6:36 PM

Was the file downloaded to a temporary location?

Comment 58 (In reply to #57) by tomiwaadefokun posted on 9/16/2015 at 6:50 PM

The file was downloaded to cordova.file.dataDirectory directly, I am suspecting it may be that it is private. Could that be the case?

Comment 59 (In reply to #58) by tomiwaadefokun posted on 9/16/2015 at 7:16 PM

I changed the path to cordova.file.externalApplicationStorageDirectory and it worked well. How reliable is this path?

Comment 60 (In reply to #59) by Raymond Camden posted on 9/16/2015 at 7:30 PM

I'd check what the FIle plugin doc has to say about it.

Comment 61 (In reply to #60) by tomiwaadefokun posted on 9/16/2015 at 7:38 PM

Many thanks Raymond, I really appreciate.

Comment 62 (In reply to #16) by Vinicius posted on 11/19/2015 at 5:12 PM

Hello, I'm with the same problem.
Do you find some workaround for this issue?

Comment 63 by Realtebo posted on 12/7/2015 at 9:01 AM

Great tutorial !

resolveLocalFileSystemURL error fallback passes an argument of type FileError object. Here you can find the meaning of FileError.code: https://developer.mozilla.o...

Comment 64 by Naitik Patel posted on 3/7/2016 at 10:32 AM

Can we add file on external sdcard, if sdcard is inserted? i done code put file in internal storage in specific folder. But need to put in external sdcard. Is there any way to do it? Thank you in advance.

Comment 65 (In reply to #64) by Raymond Camden posted on 3/7/2016 at 11:50 AM

Check out externalDataDirectory, and the other external aliases in the docs here: https://www.npmjs.com/packa...

Comment 66 (In reply to #65) by Naitik Patel posted on 3/7/2016 at 12:02 PM

thank for you quick reply, But it didn't help me. It still showing internal storage path for app. I need external sdcard access.

Comment 67 (In reply to #66) by Raymond Camden posted on 3/7/2016 at 12:18 PM

You say, "it still showing internal storage path" - what is? If you mean my code, obviously you need to change it.

Comment 68 (In reply to #67) by Naitik Patel posted on 3/7/2016 at 12:23 PM

yes it showing me path "file:///storage/emulated/0/" but i need get path of "/sdcard/myfolder" here sdcard is what normally inserted in android phone externally.

Comment 69 (In reply to #68) by Raymond Camden posted on 3/7/2016 at 12:26 PM

yes what? If you are using my code, then you need to change it. If you've changed my code to use the external sd card, show (via a Gist) how you did it.

Comment 70 (In reply to #69) by Naitik Patel posted on 3/7/2016 at 12:28 PM

i used your code. But i didn't change it till now. i need your help for save my file on "external sdcard"

Comment 71 (In reply to #70) by Raymond Camden posted on 3/7/2016 at 12:42 PM

And I did help. :) Look at the docs on the File plugin and pay special attention to the external aliases.

Comment 72 by Jacob posted on 3/8/2016 at 9:24 AM

Hi, thanks for a great tutorial! I've got a question for you, in case this has already been asked and answered before I beg your pardon.. hope you're up for it :)
Anyway, here we go:

I am downloading images to the device on the fly and my intention is to save them locally in my application. The app will then look for the images when they're requested and see if they're stored locally and then use them with the local path otherwise it will download them and save them for future use.

In many other examples I've seen the following:
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, onFileSystemSuccess, fail);

But in yours I don't. In your example, are the images saved until they're removed or are they just saved temporarily? If they're saved temporarily, what would I change to make them stick around forever?

When I try to add window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, onFileSystemSuccess, fail); to my application it will just stop. No callbacks are thrown at all.

Comment 73 (In reply to #72) by Raymond Camden posted on 3/8/2016 at 11:04 AM

requestFileSystem will give you a handle to the root of the file system. This would let me start digging into the file system from, basically, /. I don't need that as I'm checking to see if a specific file exists. Does that make sense?

Comment 74 (In reply to #73) by Jacob posted on 3/8/2016 at 11:52 AM

Thank you so much for your reply. That makes sense. Just to clarify, when I use fileTransfer.download will the file then be saved permanently? My main worry here is that I want to make sure that images that are downloaded from a remote host can be used in offline mode days/weeks later.

When I connect, say my Android to my Mac and open up a program called "Android File Transfer" I was expecting to see the saved files within my adobe.phonegap folder. But it seems to be empty. Is this normal behaviour? I am using your exact example.

I really appriciate your time.

Comment 75 (In reply to #74) by Raymond Camden posted on 3/24/2016 at 1:23 PM

1) Check the docs on that. There are locations that are temp/perm.

2) Note the docs on dataDirectory: "Persistent and private data storage" - notice how it says 'private'? I'm guessing thats why you can't see it.

Comment 76 (In reply to #74) by Raymond Camden posted on 3/24/2016 at 1:24 PM

Holy smokes - sorry it took 16 days to reply.

Comment 77 (In reply to #75) by Jacob posted on 4/13/2016 at 1:09 PM

Hi Raymond, woah! Took me another 20 days to reply! Sorry about that. Thank you so much for your help. Much appriciated. Great articles!

Comment 78 by JA C posted on 5/18/2016 at 6:25 AM

Thanks for the great article!!!! But I am not sure why this file downloads everytime i run the script even though the file exists it downloads again. how can i overcome this?

Comment 79 (In reply to #78) by JA C posted on 5/18/2016 at 7:00 AM

I fixed the issue you need to change the following line :

window.resolveLocalFileSystemURL('file:///'+store+fileName, appStart, downloadAsset);

below article was helpful to solve it :

http://ourcodeworld.com/art...

Thanks Again.

Comment 80 (In reply to #79) by Raymond Camden posted on 5/18/2016 at 11:51 AM

Looks to be a known bug - hopefully corrected soon. Thanks for sharing this.

Comment 81 (In reply to #80) by JA C posted on 5/18/2016 at 2:22 PM

How abt this code working on iOS. i mean what will be the path of cordova.file.dataDirectory

Comment 82 (In reply to #81) by Raymond Camden posted on 5/18/2016 at 2:42 PM

See the FileSystem plugin docs. It explains what that alias means for each supported platform.

Comment 83 by Omar Al Arab posted on 6/2/2016 at 3:25 AM

Hello is there a way to download a mp3 FIle and then use it as a localNotification

I have already downloaded the file successfully but i am not being able to use it as a local notification

Comment 84 (In reply to #83) by Raymond Camden posted on 6/2/2016 at 12:56 PM

If you mean something that is used with a Push notification, then I'm not sure. I know when you send a Push, you can specify a audio file to play, and if you can specify a folder that matches where you save the file, then yes. So I'd look into that first.

If you mean just a random noise, then sure, you can use the Media plugin to play it.

Comment 85 by David Graf posted on 6/24/2016 at 3:19 PM

Hi, could we download pdf file on ios device?
if then, how can we browse that downloaded pdf file?
I tried below code from https://github.com/apache/c....
I got "download complete", but can't find that pdf and no way to find out on my device.

var fileTransfer = new FileTransfer();
var uri = encodeURI("http://some.server.com/down...");

fileTransfer.download(
uri,
fileURL,
function(entry) {
console.log("download complete: " + entry.toURL());
},
function(error) {
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("download error code" + error.code);
},
false,
{
headers: {
"Authorization": "Basic dGVzdHVzZXJuYW1lOnRlc3RwYXNzd29yZA=="
}
}
);

Comment 86 (In reply to #85) by Raymond Camden posted on 6/24/2016 at 3:29 PM

So first off - yes - you can download a PDF, or any file within reason. You know you can because you yourself said you saw the download complete message, right?

So - as for viewing it - theres a few options here. Let me get back to you on that. You may be able to simply window.location.href = entry.toURL().

Comment 87 by Alwyn Malan posted on 7/1/2016 at 8:21 AM

Howsit Raymond, I'm trying to download a video file on the click of a button on both Android and iOS. I can get it to work fine on Android but not on iOS. As far as I can see it is the target directory that is the problem here.

After a lot of research I just can't seem to get the target path right and using the other solutions i.e. cordova.file.applicationDirectory, cordova.file.dataDirectory doesn't seem to work. Please help if you can, here is my code:

if (devicePlatform === 'Android') {
baseUrl = '/storage/emulated/0/Download/';
}
else if (devicePlatform === 'iOS') {
baseUrl = 'var/mobile/Applications/<application uuid="">/Documents/Download/';
}

It is this baseURL that is the problem. I don't know how to get that path dynamically?

$('#download6').on('click', function (e) {

e.preventDefault();
var fileTransfer = new FileTransfer();
var uri = encodeURI("URLOFVIDEO");
var fileURL = baseUrl + 'FILENAME';

$('#videoContainer6').html('<img alt="" src="images/loading.gif"/>
Downloading');

fileTransfer.download(
uri,
fileURL,
function (entry) {
alert('Your video has finished downloading to: Device Storage > Download > FILENAME');
console.log("download complete: " + entry.toURL());
$('#videoContainer6').html('Video Downloaded.');
},
function (error) {
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("download error code" + error.code);
},
false,
{
headers: {
"Authorization": "Basic dGVzdHVzZXJuYW1lOnRlc3RwYXNzd29yZA=="
}
}
);
return false;
});

Comment 88 (In reply to #87) by Raymond Camden posted on 7/1/2016 at 1:13 PM

So when you tried cordova.file.dataDirectory, how did it fail?

Comment 89 (In reply to #88) by Alwyn Malan posted on 7/1/2016 at 1:16 PM

It succeeds, but when I go to that folder there is no file. Tried the cache directory as well, get the succeed message from the File Transfer function but no actual file in directory...very strange.

Comment 90 (In reply to #89) by Raymond Camden posted on 7/1/2016 at 1:19 PM

How are you "going to the folder"? Are you using the File system APIs to get a directory listing?

Comment 91 (In reply to #90) by Alwyn Malan posted on 7/1/2016 at 1:23 PM

Just using "My Files" on Android and when going to Android->Storage->Data->App->Files/Cache there is nothing there.

Comment 92 (In reply to #91) by Raymond Camden posted on 7/1/2016 at 1:24 PM

Well keep in mind - some of these folders are private to the app itself. Ie, only the *app* can see it - so that may be your issue. If you use the File API to get a file listing, see if *that* shows up.

Comment 93 (In reply to #92) by Alwyn Malan posted on 7/1/2016 at 1:25 PM

Cool will have a look thank you

Comment 94 by caiczcz posted on 7/26/2016 at 11:09 AM

Hi Raymond,
I have tried your method with some modification, but I met with some issues.
Every time I tried to download something, whether there exists the file, the file will be created but not any data is downloaded, so the file is 0 byte. Every time, "already exists" prints. Do you have any idea?

window.resolveLocalFileSystemURL(dirname.nativeURL+"/"+path.dir+"/"+path.name, function(){
console.log("already exists");
}, function(){

var p = fe.toURL();

console.log("p====>"+p);
fe.remove();
ft = new FileTransfer();
ft.download(
encodeURI(url),
p,
function(entry) {
console.log("entry===>"+entry);
// $scope.imgFile = entry.toURL();
deferred.resolve();
},
function(error) {
deferred.reject();
},
false,
null
);
});

Comment 95 (In reply to #94) by Raymond Camden posted on 7/26/2016 at 2:43 PM

If you log the error in the error handler for download, what do you see?

Comment 96 (In reply to #95) by caiczcz posted on 7/27/2016 at 2:10 AM

Hi Raymond,
You mean the second parameter of window.resolveLocalFileSystemURL() is error handler for download??

window.requestFileSystem(LocalFileSystem.PERSISTENT, 1024*1024*100, function(fs) {

fs.root.getDirectory(
"EvnetsTiles",
{
create: true,
},
function(dirname) {

dirname.getDirectory(path.dir,
{
create: true,
},
function(dirEntry){

dirEntry.getFile(
path.name,
{
create: true,
exclusive: false
},
function gotFileEntry(fe) {

window.resolveLocalFileSystemURL(dirname.nativeURL+"/"+path.dir+"/"+path.name,
function(){
console.log("already exists");
}, function(){

var p = fe.toURL();

console.log("p====>"+p);
fe.remove();
ft = new FileTransfer();
ft.download(
encodeURI(url),
p,
function(entry) {
console.log("entry===>"+entry);

deferred.resolve();
},
function(error) {
deferred.reject();
}

);
});

},
function() {
deferred.reject();
}
);
});
}
);
});

Comment 97 (In reply to #96) by Raymond Camden posted on 7/27/2016 at 12:47 PM

You posted the code again - that's not what I want. When you do deferred.reject(), can console.log(error) to see what the error is?

Comment 98 by Mauricio posted on 8/2/2016 at 6:24 PM

Hi Raymond,

I am working with an ipad, but I have the issue that after the image is downloaded it don't show in the img tag, the thing is it works with cache folder :

var targetPath = cordova.file.cacheDirectory + "folio/assets/images/testImage0.jpg"; //work

var targetPath = cordova.file.dataDirectory + "testImage.jpg"; // don't work

"folio/assets/images" I take this path from other image that I don't download it is part of the content.

sorry for bad English, not native speaker.

Comment 99 (In reply to #98) by Raymond Camden posted on 8/4/2016 at 5:05 PM

Do you get a 404 error in the console - for the image I mean.

Comment 100 (In reply to #99) by Mauricio posted on 8/4/2016 at 5:25 PM

Not i don't get any error, it seems to be something with path, I can download image wherever I want : cordova.file.cacheDirectory, cordova.file.dataDirectory, cordova.file.documentsDirectory but I only can show the ones saved in cordova.file.cacheDirectory, I have trying with adiccional folder but i get same result :

cordova.file.dataDirectory + "/image/someimage.jpg"
cordova.file.dataDirectory + "/content/image/someimage.jpg" etc.

it only work with "cordova.file.cacheDirectory" my fear is that this directory can be cleared whenever the OS desires, that is why i want to use cordova.file.cacheDirectory or cordova.file.documentsDirectory

Comment 101 (In reply to #100) by Raymond Camden posted on 8/4/2016 at 5:37 PM

If the image didn't load, *something* went wrong. What do you see when you remote debug?

Comment 102 (In reply to #101) by Mauricio posted on 8/4/2016 at 5:48 PM

I am not doing remote debugging, I will do it and tell you what i get.

Comment 103 by Jim posted on 9/1/2016 at 7:04 PM

Hi Raymond,

I'm wondering how to specify a specific file to download as part of the download() call. So when we call upload(), can can include params that allow our server to make additional determinations regarding what to do with the uploaded file. When I call download (to download a picture for a person's profile for instance), the server needs to do which specific picture to download - I don't see how to tell it that as part of the download() call since there is no ability to add params onto the call. Any advice?

Comment 104 (In reply to #103) by Raymond Camden posted on 9/2/2016 at 5:43 PM

"So when we call upload(), can can include params "
Yes, look at the API docs for the plugin, this is supported.

"I don't see how to tell it that as part of the download() call since there is no ability to add params onto the call"
Since you are passing a URL, you can use URL params. Ie,

myserver.com/image.php?id=X

Comment 105 (In reply to #101) by Kyle Roach posted on 9/22/2016 at 12:31 PM

Hey i encountered the same problem. The error given in the console is 'Failed to load resource: The operation couldn’t be completed. Operation not permitted'. I used 'cordova.file.documentsDirectory'

Comment 106 (In reply to #105) by Raymond Camden posted on 9/22/2016 at 3:27 PM

It may be that you can read and write to the directory but can't use it as an image source. You should maybe consider another path.

Comment 107 (In reply to #106) by Kyle Roach posted on 9/22/2016 at 5:53 PM

I also was to mention that it works in the simulator but not on device

Comment 108 (In reply to #107) by Raymond Camden posted on 9/22/2016 at 5:58 PM

Not sure what else to suggest off the top of my head. At this point I'd need to get your code, run it, etc, which would be a paid engagement.

Comment 109 by Mohammed Azhar posted on 2/13/2017 at 7:06 AM

Hi Raymond,

I'm trying to download a file but the file using this plugin. On the success callback, I am triggering the FileOpener2 plugin. However, the fileOpener2 plugin throws an error that the file is not found. When I go check in the file directory on an android phone through the file manager, the file does not exist. I have posted the question with some code on SO, link is: http://stackoverflow.com/qu...

Please check this out.

Comment 110 (In reply to #109) by Raymond Camden posted on 2/14/2017 at 2:24 AM

I'm not using the fileOpener2 plugin in this blog post.

Comment 111 (In reply to #110) by Mohammed Azhar posted on 2/14/2017 at 7:48 AM

I am using the fileOpener2 plugin just to open the downloaded file. My concern is not with the fileOpener2 plugin but it is about downloading of the file itself. The file is not getting downloaded.

I found the issue to be with the new permissions in Android 6.0 and above. I've posted the answer on my question in SO and if anyone here has come across a similar issue, you can check my answer.
Cheers! :)

Comment 112 by Nisha Ramesh posted on 10/19/2017 at 9:15 AM

I am using the fileOpener2 plugin just to open the downloaded file in my cordova hybrid app(android version) .It works only once after logging.If we again click on the pdf image ,it's not working and didn't get any error.If we logout and login again it will work for the first time.

Comment 113 (In reply to #112) by Raymond Camden posted on 10/19/2017 at 12:48 PM

You say no error, so I assume you checked developer tools. Outside of that - no idea. I'd post a report on the GitHub repo for the plugin.

Comment 114 by CitizenKane posted on 10/31/2017 at 2:39 PM

Where can files added be to an Android and iOS cordova project so files are preloaded into the dataDirectory?

For the longest time I have been using applicationDirectory which is read-only. In the project, add the files to be preloaded into (android) /platforms/android/assets and (iOS) simply add the files to the root of project in Xcode (I still don't know where it places the files in the Xcode project though, but it works.)

But now I need to write to these preloaded files which means I need to change the folder to a read-write folder...based on my reading, I think the best location for this is the dataDirectory (based on the assumption that both OS's do not clear this folder/data - please correct me if I am wrong). I need the data files to be persistent so long as the app is installed.

But for the life of me I can't find any documentation on what directory path to add these files to the project so they get properly preloaded into the dataDirectory during app install

Any other insights would be appreciated too.

Comment 115 (In reply to #106) by CitizenKane posted on 10/31/2017 at 2:44 PM

My understanding is that files in this path are not a part of the www/dom resource structure. Thus an image placed in it is not accessible from a www page. The only other way would be to read the file and write the file on the fly to the page being rendered

Comment 116 (In reply to #114) by Raymond Camden posted on 11/4/2017 at 10:20 PM

Sorry you got me there. Obviously you could do a one time copy - that may be your only solution.

Comment 117 (In reply to #71) by Naitik Patel posted on 12/13/2017 at 7:56 AM

Glad again i found this. We had conversation before 2 years. But again stuck on this. SO for more clarification my question is:

i have some files at removable SdCard in location /storage/450-283/test

i need to grab from those files and copy inside internal storage of device.

But i can't able to fetch files from removable SdCard in location /storage/450-283/test.

Please more clarification i need to READ/WRITE file from external sdcard ( removable sdcard ).

Thanks again man.

Comment 118 (In reply to #117) by Raymond Camden posted on 12/13/2017 at 1:28 PM

I'd check the FIle plugin documentation and see what it says about external storage. The docs say what you have R/W access to.

Comment 119 (In reply to #118) by Naitik Patel posted on 12/13/2017 at 7:19 PM

Hi Raymond,

Thank you. But got working now.

below is my code for your reference:

function getExternalSdLocation(done){
cordova.plugins.diagnostic.getExternalSdCardDetails(function(details){
details.forEach(function(detail){
if(detail.type == "application"){
cordova.file.externalSdCardApplicationDirectory = detail.filePath;
}else if(detail.type == "root"){
cordova.file.externalSdCardRootDirectory = detail.filePath;
}
});
done();
}, function(error){
console.error(error);
done();
});
}

function requestExternalSdPermission(done){
cordova.plugins.diagnostic.requestRuntimePermission(function(status){
switch(status){
case cordova.plugins.diagnostic.permissionStatus.GRANTED:
console.log("Permission granted");
getExternalSdLocation(done);
break;
case cordova.plugins.diagnostic.permissionStatus.DENIED:
console.log("Permission denied");
askAgain(done);
break;
case cordova.plugins.diagnostic.permissionStatus.DENIED_ALWAYS:
console.log("Permission permanently denied");
reportError(done);
break;
}
}, function(error){
console.error("The following error occurred: "+error);
reportError(done);
}, cordova.plugins.diagnostic.permission.WRITE_EXTERNAL_STORAGE);
}

requestExternalSdPermission(function(res){
console.log("Permission done " , res);
})

function checkIfFileExists(path){
window.resolveLocalFileSystemURL(path,
function(fileSystem){
console.log("File System " ,fileSystem )
fileSystem.getFile('1.jpg', { create: false }, function(fileEntry){
console.log("File " + fileEntry.fullPath + " exists!");
}, function(){
console.log("file does not exist");
});
},function(){
console.log("Error Grab file system" );
}) //of requestFileSystem
}

setTimeout(function(){
checkIfFileExists(cordova.file.externalSdCardRootDirectory + '/test')
},5000);

That will check in removable sdcard and inside it "test" folder and search for file "1.jpg" and it's working great.

Thank you for your valuable time man.

Comment 120 by Parrish Fam posted on 1/25/2019 at 9:35 PM

Does ANYONE have a demo Phonegap or Cordova file download app template that works. I am trying to build an app that is able to download files to Android device. I am not sure how to download or include the plugin the the config.xml file and need a working guide. Please share if you have something. Thanks !