Downloading files to a PhoneGap application - Part 2

This post is more than 2 years old.

Yesterday I blogged my experiment with downloading files to a PhoneGap application. Today I decided to take my code and try it out on iOS. Along the way I discovered a little bug, and encountered the White List issue with iOS PhoneGap apps. As with the previous entry, please note that this could possibly be done better.

Before we even get started, I wanted to correct a small issue in the previous code base. The code that handles file downloads looked like so:

var dlPath = DATADIR.fullPath + "/" + res[i]; console.log("downloading crap to " + dlPath); ft.download("http://www.raymondcamden.com/demos/2012/jan/17/" + escape(res[i]), dlPath, function(){ renderPicture(dlPath); console.log("Successful download"); }, onError);

I noticed, however, that my images were all the same URL, but only when the app was run for the first time and the images had to be downloaded. Why? I was using dlPath inside my closure and it wasn't using the right value. Classic JavaScript scoping issue and one I can't believe I made.

Luckily, the FileTransfer event includes all the data I need. Here's the new version:

var dlPath = DATADIR.fullPath + "/" + res[i]; console.log("downloading crap to " + dlPath); ft.download("http://www.raymondcamden.com/demos/2012/jan/17/" + escape(res[i]), dlPath, function(e){ renderPicture(e.fullPath); console.log("Successful download of "+e.fullPath); }, onError);

Nice and obvious once you see it. Ok, so what about iOS? I had struggled a bit last week to get my first iOS/PhoneGap running, but most of that struggle was due to the fact I had never run XCode before. It's a strange beast! Plus I'm using it over VNC, which works ok for the most part but is a bit tricky at times.

Once I got past getting my application certificate crap running (thank you, Apple, for protecting me from my own hardware, lord forbid you allow me to just install anything without asking for permission first... oh crap, I'm going off on a sermon again) everything was mostly kosher. And rants aside - the iOS Simulator makes the Android Simulator look like a TRS-80. (And yes, I know the Android thing is doing more. Guess what - I don't care. It's a pain in the ass and slower than waiting for a picture to download over 14.4 baud modem.)

With my code in place, I immediately ran into an issue with my remote URL. Remember I'm hitting raymondcamden.com to get a list of images. XCode actually fleshed this error out quite obviously in the debugger. It's also something "everyone" knows so I wasn't too surprised. You simply need to go into PhoneGap.plist and add your domain:

The next change I made was one that would probably work fine in Android too. Instead of switching to an Android based directory:

fileSystem.root.getDirectory("Android/data/com.camden.imagedownloaddemo",{create:true},gotDir,onError);

I did this instead:

fileSystem.root.getDirectory("com.camden.imagedownloaddemo",{create:true},gotDir,onError);

My gut tells me this same path would be fine on both - but in my third entry, where I talk about using integrating the iOS/Android version, I'll use this as one of the things I do differently on each platform. Anyway, it runs!

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 AMet posted on 7/18/2012 at 11:57 AM

Uhmm your third entry?
Is it just me that can't find this or did I misunderstand something?

Comment 2 by Raymond Camden posted on 7/18/2012 at 7:37 PM
Comment 3 by Ristef posted on 10/25/2012 at 5:22 PM

I found my new god. Really thanks Raymond for this example. It works nice :)

Comment 4 by Raymond Camden posted on 10/25/2012 at 6:02 PM

Heh, careful now, someone may get offended. ;)

Comment 5 by Ristef posted on 10/25/2012 at 6:40 PM

Haha :)
Juste a little question about your imagelister. How do you generate it.
I tried with a json_encode($var) with $var, the name of my .jpeg on my list.php for the $.get but the synthax is not the same.

I don't have "[]" at the beginning and at the end, and also don't have the "," between each name.

Ps: I'm french and sorry my english is not well :)

Comment 6 by Ristef posted on 10/25/2012 at 7:16 PM

-But all it's doing is returning a JSON-encoded array of images-

I didn't see it was an array, i got the same synthax now. :stupid:

Sorry for double comments!

Comment 7 by Raymond Camden posted on 10/25/2012 at 8:03 PM

No worries - just glad you got it.

Comment 8 by Ristef posted on 10/30/2012 at 7:36 PM

Hey Raymond is still me.
Did you have any idea to create several directories using the sampe principe. Return a JSON with the name of the directory and create it to download into them the images.

Thank you in advance

Comment 9 by Raymond Camden posted on 10/30/2012 at 7:57 PM

I can describe it in abstract. Pretend for a minute that we wanted to organize pictures by subject. You could return data like so:

[
{ img:"foo.jpg", subject:"sports"},
{ img:"foo2.jpg", subject:"music"},
{ img:"foo3.jpg", subject:"sports"}
]

Your code would treat subject like a subdirectory and use the FileSystem API to create the folder if it needs to be created.

Then it uses that directory when storing the file.

Comment 10 by Ristef posted on 10/30/2012 at 8:10 PM

Yes, i see how do, i will try to do this.
Thank you for your fast answer, and thanks a lot for everything. :)

Comment 11 by Ristef posted on 11/13/2012 at 2:34 PM

Hey Raymond, I have one last question. :)
All works nice in my app but, is it possible to copy/paste or direct donwload images in a directory in www ?

Comment 12 by Raymond Camden posted on 11/13/2012 at 5:21 PM

I don't believe so. You want to use the system storage instead.

Comment 13 by Ristef posted on 11/13/2012 at 6:13 PM

Arf, ok, thanks anyway again.

Comment 14 by Jhonnatan posted on 8/29/2013 at 9:49 PM

I do not get it work :( help me please
http://pastebin.com/gq9wwCa3

Comment 15 by Raymond Camden posted on 9/3/2013 at 3:47 PM

You need to figure out _where_ it isn't working. Just saying the whole thing isn't working is enough. Describe what part fails.

Comment 16 by Jhonnatan posted on 9/3/2013 at 7:53 PM

This shows no errors. this does not show images

Comment 17 by Raymond Camden posted on 9/3/2013 at 7:56 PM

So your next step would be to try adding console.log messages, or even alerts, to see if you can figure out where it breaks. FOr example, I'd consider deviceready is firing with a simple alert message.

Comment 18 by Jhonnatan posted on 9/3/2013 at 9:19 PM

I'm trying to adapt your example to my code, and I wondered if in your url the number 17 is the folder where the images is?, I do not know how to access the imagens from php, I already create the list with the names of all pictures.

Comment 19 by jhonnatan posted on 9/3/2013 at 9:20 PM

Can you show me the php code?

Comment 20 by Raymond Camden posted on 9/3/2013 at 9:43 PM

1) Yes, 17 was just part of the folder name. Nothing special.
2) What PHP code? My example was built in CF. But it would be done in PHP.

Comment 21 by Richard posted on 9/30/2013 at 5:44 PM

Hi Raymond!
Any possibility to see the code demo??
Richard

Comment 22 by Raymond Camden posted on 9/30/2013 at 7:23 PM

Sorry I don't have a direct link for this, but if you get the code from P1 and just do the fix I mentioned in the entry, that is it.

Comment 23 by Richard posted on 9/30/2013 at 7:51 PM

Thanks Ray For you quick answer!
Richard

Comment 24 by Anneleen posted on 11/6/2013 at 2:22 AM

Does this also work for Phonegap Build? Cause I tried it, in combination with Phonegap 2.9 and it's not working.

Comment 25 by Raymond Camden posted on 11/6/2013 at 2:26 AM

How is it not working? Don't forget to use config.xml to specify raymondcamden.com in your access block. Or another server if you set up your own service.

Comment 26 by Anneleen posted on 11/6/2013 at 3:28 AM

Strange, that actually did do the trick, even though I put * in the access block. Now to find out why it isn't working in my adaptation! Thanks!

Comment 27 by reda posted on 12/10/2013 at 10:53 PM

@Anneleen

The * should work. Make sure you are setting this in the good config.xml as you can have multiple config.xml in a phonegap project and this can be very confusing.

@Raymon, I have an app with lot of images organized in chapters and the total app size is 300mo while max app size is 60mo (OTA), and I want to use your file-download-example to download the additional chapters right after first launch, and keep initial app size small. Do you have any best practice to do this while making sure the app get accepted by Apple validation team? Is your technique suitable for my need?

Thanks

Comment 28 by Raymond Camden posted on 12/11/2013 at 1:18 AM

A few thoughts.

1) Create a placeholder image in case the user somehow clicks into something that would use one of the images. That way they see something.

2) Just fire off a process in the background to handle getting the images. You want to ensure you remember where you left off in case you don't complete them all.

Comment 29 by SAMTJ posted on 6/15/2014 at 9:38 AM

Hello friend, you would not have to provide the link with the code?

Comment 30 by SAMTJ posted on 6/15/2014 at 1:19 PM

Hello, updated their code to the cord => 3.0, if you want to then do an update of your post, and if possible post the code to download

Comment 31 by Raymond Camden posted on 6/15/2014 at 11:27 PM

Are you asking for a copy of the code? I can't really tell. As for an update, what I have *should* still work in 3.X.

Comment 32 by SAMTJ posted on 6/16/2014 at 11:20 AM

Wanted a copy, but I've run, the way you did not work in version => 3 needs some tweaking if you want it updated to post here pass me your email I will send you

Comment 33 by Raymond Camden posted on 6/16/2014 at 3:01 PM

Can you post a zip publicly and share the URL here?

Comment 34 by Raymond Camden posted on 6/17/2014 at 8:44 AM

@Samtj: I just deleted your comment. Please do not post your files in the comment block. Post a Gist URL instead.

Comment 35 by Nehul Agrawal posted on 9/10/2014 at 11:47 PM

Hello, it is a great tutorial.

But i want to know. When i want to check. IF the file already exists with the same name then do not download the file again.

How can i do that?

I try to put a FOR loop to check this. But didnt work out it starts to give some error like IO exception. Any way you can suggest?

Thank you!

Comment 36 by Raymond Camden posted on 9/10/2014 at 11:48 PM