Today I'd like to talk about using the FileTransfer.download() command with PhoneGap. In PhoneGap 1.5.0 we introduced common JavaScript. This is a sub project which has each platform that PhoneGap supports pulling it's JS from a common source. One of the changes introduced because of this is that all FileEntry.fullPath's would start with the "file://" protocol.
Unfortunately the native FileTransfer.download() code was not updated to take care of the new input. I've raised CB-539: FileTransfer.download fails when target starts with "file://" to track this issue. I've already got a fix for this checked into the source repository and it'll be in the 1.7.0 release of PhoneGap.
In the meantime you'll need to strip the "file://' from the target path you pass into FileTransfer.download(). Something like this:
var localPath = fileEntry.fullPath;Here is a full example and don't forget to whitelist "http://i3.kym-cdn.com":
if (device.platform === "Android" &&
localPath.indexOf("file://") === 0) {
localPath = localPath.substring(7);
}
Thanks Simon! Very usefull!
ReplyDeleteI try your code but i have one mistake .
ReplyDeleteWhen i click on "Download and display image" the browser says me :
<< Uncaught TypeError: string is not a function >>
in the body html
@Père
ReplyDeleteWhat line does the error come from?
Hi Simon,
ReplyDeleteThanks for the article, it's really helpful. I'm seeing an issue, though. According to my console, all the files are downloading correctly, but when I try to set the source of an image to the entry.fullPath, I just get a broken image?
I'm testing with a 4s and the path I'm getting from entry.fullPath looks like this:
/var/mobile/Applications/94B5774C-F4B4-4295-B0F2-9C779CDB048E/Documents/138.png
Ideas?
@Joe
ReplyDeleteI will ask Becky, my iOS counterpart.
Thanks!
ReplyDeleteFWIW, I also tried to use .toURL() and I got the URL as:
ReplyDeletehttp://localhost/var/mobile/Applications/94B5774C-F4B4-4295-B0F2-9C779CDB048E/Documents/138.png
BUT, it still displays a broken image.
Joe
Also of note is that I'm using 1.5, not 1.6.1. Do you think there was something in there that changed?
ReplyDeleteThanks for this Simon, been struggling with the download method for a while (html & php are my game, js not so much), looks like I'm finally making some headway thanks to you!
ReplyDeleteTo add to @Joe's issue, I'm writing for iPad and struck the same problem. I'm not sure why this works, but I was having no joy pulling data from my db into the app a while back, turned out to be the syntax in the whitelisting.
Did the same thing with your example and it's all good - whitelist '*.i3.kym-cdn.com' rather than 'http://i3.kym-cdn.com'.
If anyone far more knowledgable than I (i.e. most everyone) can shed any light on why this works it would be appreciated!
Found the problem - our backend is serving up the image as a stream and the FileTransfer.download is expecting a file, so I was getting images that were size 0. I'm writing out the image to a physical file now and downloading it and everything's working.
ReplyDeleteHi,
ReplyDeleteFirst of all thanks for the HUGE job you are dooing.. It is highly appriciated..
I am building a App (On Android at the moment) that should download all the images locally..
I am struggeling with a Connect error and it looks like the whitelisnting problem..
Could you give me a quic explaination of implementing this or a link to a doc.. I have been googling for some time and I might have gone blind...
Thanks in advance
Kim
Awsome.. did mug a littel around with it but now it work..
ReplyDeleteTHANSK
Hi,
ReplyDeleteI am using FileTranfer.download to download images from both Android and Iphone .But i am getting FileTransferError.INVALID_URL_ERR on Iphone .On Android its works fine for that urls.I am using Phonegap 1.4.1 version. Please help .
i am working on android 2.3 sdk and when i run this code it says 06-08 13:23:21.873: E/Web Console(352): TypeError: Result of expression 'window.requestFileSystem' [undefined] is not a function. at file:///android_asset/www/libs/modules/contacts/contacts.js:180
ReplyDelete@megha rathore
ReplyDeleteIt sounds like the PhoneGap/Cordova library is not being loaded properly. Are you seeing the "Thunderbirds are go!" log in your console? If not then PG is not loaded.
@joe , hi joe where u r writing the image to a physical file. whether in client side or server side. i am using the java as a backend file. doing exactly as u r doing like sending image as stream and in client side its downloading as empty file. what to do. please help me joe. hi simon pl post this comment. its very urgent.
ReplyDeletehi dear, great article you write.
ReplyDeleteAt first, sorry my poor english.
Man, i´ve tryed download a file with FileTransfer in iOS 5.1 but a try/catch in "var ft = FileTransfer();"
Showed me a error like this: "ReferenceError: Can´t findi variable: FileTransfer"
So, my app don´t work.
I´ve checked my permissions on my plist file of my project in xCode.
But, the little sample don´t work.
In my project, the another functions of cordova/phonegap are working fine. Only FileTransfer return me this error.
Do you have any info about this error? In google, and cordova site, i don´t found any info about that.
My best regards,
@kimbavng
ReplyDeleteSorry man, what version of Cordova are you using?
Hi,
ReplyDeleteI have tried to download the image into my device and display it. I have tried your code but i am not able to download the image i have been getting the following issue could you please help on this
Source URL is not in white list: 'http://i3.kym-cdn.com/entries/icons/original/000/000/080/doubt.jpg'
Could you explain me how to white list the url.
Thank in advance..
@jagadesh
ReplyDeleteHere is the white list guide:
http://docs.phonegap.com/en/2.0.0/guide_whitelist_index.md.html#Domain%20Whitelist%20Guide
This is very useful, however, I haven't been able to get my download to work. I have been successful with the upload command, but not download. Here is my code:
ReplyDeletevar fileTransfer = new FileTransfer(),
uri = encodeURI('myURI');
fileTransfer.download(uri, LocalFileSystem.PERSISTENT,
function(entry) {
console.log("download complete: " + entry.fullPath);
},
function(error) {
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("upload error code" + error.code);
}
);
What do you think I am doing wrong?
@Spencer Quistberg
ReplyDeleteWell LocalFileSystem.PERSISTENT is a constant and not a file path. You'd need to pass in something like "/sdcard" to get this to work.
thanks you it is working now
ReplyDeleteHi,
ReplyDeleteI was successfully in downloading the single image to the sdcard by following the code instruction mentioned above. But when i am trying to download the multiple images i have been getting the images but with the same image
here i will mention the code could you help me in this issue
function onDeviceReady()
{
console.log("on the ondevice ready function");
// do your thing!
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem) {
for(var i=0;i"+additems[i]);
var remoteFile = "http://www.raymondcamden.com/demos/2012/jan/17/"+additems[i];
console.log("remoteFile------------>"+remoteFile);
var localFileName = remoteFile.substring(remoteFile.lastIndexOf('/')+1);
fileSystem.root.getFile(localFileName, {create: true, exclusive: false}, function(fileEntry) {
var localPath = fileEntry.fullPath;
if (device.platform === "Android" && localPath.indexOf("file://") === 0) {
localPath = localPath.substring(7);
console.log("localPath------------>"+localPath);
}
var ft = new FileTransfer();
console.log("in the file transfer ");
ft.download(remoteFile,
localPath, function(entry) {
console.log("in the file download method");
}, fail);
}, fail);
}
}, fail);
}
@jagadesh
ReplyDeleteThis line:
for(var i=0;i"+additems[i]);
is not valid JavaScript.
I was successful in downloading my file to file:///mnt/sdcard/myfile.jpg. How can I download the file to my downloads on my phone? would it be something like file:///mnt/sdcard/downloads or is there a constant for this as well?
ReplyDelete@Spencer Quistberg
ReplyDeleteWell in the download method you just need to specify you want it to go in the downloads directory. Modify the getFile input to be:
fileSystem.root.getFile("downloads/" + localFileName, {create: true, exclusive: false}, ...);
Thanks. I successfully downloaded the file to file:///mnt/sdcard/Download/file.jpg, but I can find it in my "Downloads" on my phone. Basically, I would like this to work the way an attchment download in an email works on your phone. When you download the email attachment, your phone notifies you that you have an attachment and then you can go to your "Downloads" from there. Does phonegap has this capability?
ReplyDeleteI really dont know if you can help. I am using this code to download multiple PDF documents. How do I wait for the first PDF to complete it's download then move onto the second then third etc.
ReplyDeleteI was using $.each but this may be the wrong way round.
var local2User = JSON.parse( localStorage["locallessons"] ) ;
$.each(local2User, function(key) {
var remoteFile = optionsJSON + local2User[key].idcountries + '/' + local2User[key].idcurriculum + '/' + local2User[key].idoptions + '/pdf/' + local2User[key].pdfname;
var localFileName = remoteFile.substring(remoteFile.lastIndexOf('/')+1);
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem) {
fileSystem.root.getFile(localFileName, {create: true, exclusive: false}, function(fileEntry) {
var localPath = fileEntry.fullPath;
if (device.platform === "Android" && localPath.indexOf("file://") === 0) {
localPath = localPath.substring(7);
}
var ft = new FileTransfer();
ft.download(remoteFile,
localPath, function(entry) {
//var dwnldImg = document.getElementById("dwnldImg");
//dwnldImg.src = entry.fullPath;
//dwnldImg.style.visibility = "visible";
//dwnldImg.style.display = "block";
}, fail);
}, fail);
}, fail);
});
I just seem to be stuck and no matter what I try just cant get it right.
@Donovan
ReplyDeleteDon't use a "each" loop. Push all the files you want to download into an array. Start the download as normal but in your success callback you pop the next file off the array and call file transfer download again. Repeat until no files are left in the array.
@Spencer Quistberg
ReplyDeleteOnce the file is downloaded you could fire off a local notification use a plugin:
https://github.com/phonegap/phonegap-plugins/tree/master/Android/StatusBarNotification
Hi Simon thanks for the response. I have always used each loops. Could you give me a quick example of what you were sugesting for array and call back. A bit confussed at the moment. Thanks again for the advise.
ReplyDeleteWhen i try your code, I am getting an error of error code 12. what may be fault..
ReplyDelete@Donovan
ReplyDeleteI have a cold today but here is some pseudo code that should get you going:
https://gist.github.com/3835045
@MuthuKumar
ReplyDeleteThat is a PATH_EXISTS_ERR so you are trying to create a file that already exists.
Hi Simon, I want to download a couple of files in a folder stored in my server, is there a way to download the folder itself, or how can I download all the files in that folder.
ReplyDeleteI was also considering ziping the folder, so the app downloads the zipped file and unzips it within the device filesystem.
What do you think can solve this challenge, thanks, I appreciate your great work.
@Dalton Whyte
ReplyDeleteYou can't download a folder but you can zip up the contents of the folder download it and unzip it on your device using this plugin:
ExtractZipFile Plugin
Thanks Simon I was able to implement your code on https://gist.github.com/3835045.
ReplyDeleteReally appreciate the help.
I am able to download single pdf file by directly giving that url. suppose if i want to downlaod all pdf files(dont know the no.) from the folder, how to do that simon..,,, pls guide in doing this
ReplyDelete@MuthuKumar
ReplyDeleteI just covered that in my comments to @Donovan. If you read back a bit you'll see the 2 options.
I downloaded the list of pdf files from my server using file download, and able to view in my device during online mode. But I want to view the file during offline and also need to synchronize the files. Is there a way to do file synchronisation from the server using file download
ReplyDelete@MuthuKumar
ReplyDeleteThe way I would do it is to have a service that I could query to get the last updated times of your PDF files. If it is different than what you have stored from the last request you made to the service. If the files are newer then use the FileTransfer.download method.
In the phonegap filestorage, i want to insert data in my localdatabase, when data is already not there. byt when I tried to do by using select query, if exists i am updating it, if not i am inserting the data. but i am getting error. how to procede in this...
ReplyDelete@MuthuKumar
ReplyDeleteYou need to show some code, errors, logs, etc. Bring this discussion over to my FormSpring page or PhoneGap Google Group.
I am struggling to Save the downloaded Image from server to Save it to Device Photo ALbum ,Please guide me.
ReplyDelete@Satish Kumar
ReplyDeleteSo you are able to download the file but it is not showing up in the Photo Album?
Just popped in to say thanks for explaining this. It works fine for me with a simple image and my next step will be to download multiple pdf files, images and videos.
ReplyDeleteI cam here trying to figure out how to get the local folder because I could not find a clear explanation on phonegap's website.
@Nick
ReplyDeleteThe success callback for FileTransfer.download is called with a FileEntry object that you can use to manipulate the file. If you call FileEntry.getParent it's success callback will be called with a DirectoryEntry which is the parent of the file you just downloaded.
@Simon ,
ReplyDeleteYes , I am able to download the file . But unable to save or move to the Photo Album.
I tried with downloading the file to the Application's/ Document folder , Wrote a plugin to move this File to the Photo Album , It was not successful .
My intention is to achieve two things ,
1) Save the Downloaded Image to Photo Album of the device.
2) Save the Downloaded Image to a specific Album in the Device .
Please let me know if this is possible.
Thanks,
satish
@Satish Kumar
ReplyDeleteSorry, is this Android or iOS?
Simon ,
ReplyDeleteIt is for both Android & IOS.
Thanks,
Satish
@Satish Kumar
ReplyDeleteIt is certainly possible on Android. If you download the file to the "Pictures" directory the media scanner process should recognize this and add the picture to the "Gallery" app. Not 100% sure on iOS.
Just wanted to say thanks for the gist!
ReplyDeleteHi
ReplyDeleteI am using cordova for iPhone. I was able to download videos using this code to the Documents directory. Can you please guide "How to move the video from Documents directory to the photo album" ?.
@Arjun
ReplyDeleteSorry, I don't know how to do that.
Hi Simon,
ReplyDeleteI am having a problem when downloading a batch of files (potentially hundreds).
At the beginning I was using the most basic code to download, but there was always a few (random) files which could not be downloaded. When using alerts to keep track of the execution they all downloaded properly so I assumed it might be a sync problem, I mean, some files did not have enought time to be downloaded (so when using alerts they had enough time).
I don't know if this idea makes sense, but I tried a code with flags to make sure the code did not continue until each file was downloaded.
The code is as follows:
function download_img(imgToDownload, imgToRemove){
var url = remote_url+imgToDownload; // image url
root_path = get_root_path();
var flag = "working";
var flag_delete = false;
var imageToDownloadPath = root_path + "/" + imgToDownload; // full file path
var imageToRemovePath = root_path + "/" + imgToRemove; // full file path
try{
var fileTransfer = new FileTransfer();
fileTransfer.download(url, imageToDownloadPath,
function () {
if(imgToRemove != "" && imgToRemove != null){
var entry = new FileEntry("foo", imageToRemovePath);
entry.remove(function (){alert("fine");flag_delete = true;}, function (){alert("marron");flag_delete = true;});
}
else{
flag_delete = true;
}
flag = "done";
},
function (error) {
flag = "done";
flag_delete = true;
}
);
}catch(error){
alert("Error capturado: "+error.message);
}
while(flag=="working" && !flag_delete){
try{
setTimeout(
function() {
/* Código */
},
300
);
}
catch(error){
alert("Error en el bucle: " + error.message);
}
}
}
The result is:
* Only the first file is downloaded.
* However, neither succes function nor error function is executed.
* The loop keeps on as flags are never changed.
I really need a stable method to download remote files. Would you have any advice on this? Should I use a different approach or there is an error here to be solved.
Manny thanks!!!
@lamakun
ReplyDeleteMost probably the reason why things work when you use an alert is that an alert is a blocking call. It'll give time for the file to be downloaded.
What you want to do is to keep a list of files you want to download and on the success callback of each download you need to look at the list to see if there are more files to be downloaded so you can do them all in sequence.
Check out this gist for example:
https://gist.github.com/3835045
i want to download the images in the specific folder. how to do that.
ReplyDelete@Billy
ReplyDeleteJust provide the full path in the second parameter to download.
Hi simon Thanks for the article.
ReplyDeleteActually, i have tried this code for downloading a file from local server, but i m getting JSCallbackError : Request Failed at Line 3723 in Cordova.android.js file.
Thanks Ranjeet
@Ranjeet Kumar
ReplyDeleteIt is exactly what is sounds like. There is a coding error in your error callback to FileTransfer. You'll need to fix that first.
Thanks simon i fixed it now. But how to display all types of file in android emulator. i m able to display only image files, other files like text,doc... are not display..
ReplyDelete@Ranjeet Kumar
ReplyDeleteI'm not even sure what you are trying to do. Can you provide more info?
Hi Simon, Thanks for response. Actually i m trying to open Text, Doc. etc files.in android emulator. but i think these files required corresponding software to open in emulator and one more thing i want to ask that i m trying to make one vertical sliding page for my mobile app. using phonegap, like curtain type with our touch it should go up-down. but i didn't get any clue anywhere. plz help me..
ReplyDelete@Ranjeet Kumar
ReplyDeleteIf you want to open a file set its file path to document.location. That should cause the default file type viewer to start.
Regarding a curtain then you'd need to do some CSS to do it. Check out this link for instance:
http://www.thecssninja.com/css/reveal-effect
Thanks Simon, It's really good working fine with android emulator..
ReplyDeleteHi Simon!
ReplyDeleteGreat! I can download multiple images but how can I save them into my phonegap directory www/img?
@James
ReplyDeleteYou can't save into the www directory of your app. That would break the checksum of your app causing all sorts of security issues. You can reference the downloaded images via their file:// URL.
Excelente Simon MacDonald..funca maximo
ReplyDeleteDoes the download only work with physical files or can I stream the file from my server in byte array or even base64 string?
ReplyDelete@Thabo Letsoalo
ReplyDeletePhysical files only, no streaming.
will it works for android
ReplyDelete@bijay kanshi
ReplyDeleteYes