Friday, December 30, 2011

On the Sixth Day of PhoneGapping: Downloading a File

Did you know that the FileTransfer object got a new download method in PhoneGap 1.3.0? You didn't, well thanks to Alexander Heinrich for spurring it's  development and getting it checked in for Android and iOS (download is also available to you BlackBerry users). Finally PhoneGap developers have a convenient way to download binary files.

The method signature is:
download(source, destination, successCallback, errorCallback);
Where the parameters are:

source: The URL you want to download
destination: The full file path you want the file stored at
successCallback: called with a FileEntry object that represents the new file
errorCallback: called when something goes wrong

So say we want to download a PNG image and store it on the SD card. Well you'd write some code that looks like this:

16 comments:

  1. Hi,

    I've juste copy/paste your sample code, but it doesn't work

    I'm running phonegap 1.3.0

    2012-01-05 20:17:05.842 FileAssets[37881:13403] [INFO] >>> onDeviceReady
    2012-01-05 20:17:05.843 FileAssets[37881:13403] File Transfer downloading file...
    2012-01-05 20:17:06.943 FileAssets[37881:18a03] Write file /ics.png
    2012-01-05 20:17:06.945 FileAssets[37881:13403] File Transfer Error: http://developer.android.com/assets/images/home/ics-android.png
    2012-01-05 20:17:06.948 FileAssets[37881:13403] [INFO] download error source http://developer.android.com/assets/images/home/ics-android.png
    2012-01-05 20:17:06.948 FileAssets[37881:13403] [INFO] download error target /ics.png
    2012-01-05 20:17:06.949 FileAssets[37881:13403] [INFO] upload error code2

    Can you help me?

    ReplyDelete
  2. @GIACOPINO

    Do you have an SD Card? Do you have write external down as one of your permissions in your AndroidManifest.xml?

    ReplyDelete
  3. Right so if you just copy and paste my code you won't have a "/sdcard". You should remove that bit from the sample and try again.

    ReplyDelete
  4. Hi again this is what i've done is you look at the output :

    2012-01-05 20:17:06.943 FileAssets[37881:18a03] Write file /ics.png

    I've also whitelist all url by "*"

    I've tried :

    path = '/ics.png' and path='ics.png' and always the same error

    Tks for your help

    ReplyDelete
  5. I'm not really the iOS expert. You should come over to the PhoneGap Google Group and ask your question.

    ReplyDelete
  6. Done :
    http://groups.google.com/group/phonegap/browse_thread/thread/7c3674b92587c9d0

    ReplyDelete
  7. in that part of my html I paste this code?

    ReplyDelete
  8. @By_JPSP

    Yes, you just call that JavaScript code when you want to download a file.

    ReplyDelete
  9. I am getting an error dealing with fileTransfer. Its code is 1 which is "File not found error" but I don't know whether the problem is the remote file (which is a correct url as i test it in my browsers and shows the image I want to download) or the target file.

    The target file does not exists but I assume it should create it when downloading with the given name int the file path.

    I have added the following tags to my config.xml (phonegap build):




    So I allow the app to connect to any url.

    I also tried the link given by GIACOPINO but dind't don it either. My current code is:

    function downloadImg(){
    alert("downloadImg");
    /* var fileTransfer = new FileTransfer();
    fileTransfer.download(
    "http://www.mytests.es/wp-content/plugins/sitepress-multilingual-cms/res/flags/es.png",
    "/sdcard/liv-apks/es.png",
    function(theFile) {
    alert("download complete: " + theFile.toURI());
    alert(theFile.toURI());
    showLink(theFile.toURI());
    },
    function(error) {
    alert("download error source " + error.source);
    alert("download error target " + error.target);
    alert("upload error code: " + error.code);
    },
    true
    );*/
    try{
    window.requestFileSystem(LocalFileSystem.PERSISTENT, 0,
    function(fileSystem){
    var rootPath = fileSystem.root.fullPath;
    alert(">>>rootPath = "+rootPath);
    var fileTransfer = new FileTransfer();
    fileTransfer.download(
    "http://www.mytests.es/wp-content/plugins/sitepress-multilingual-cms/res/flags/es.png",
    rootPath+'/es.png',
    function(entry) {
    alert("download complete: " + entry.fullPath);
    },
    function(error) {
    alert("download error source " + error.source);
    alert("download error target " + error.target);
    alert("upload error code" + error.code);
    }
    );
    }, null);
    }catch(err){
    alert(err.message);
    }
    }

    Anyone can give a hand?

    Thanks!!!

    ReplyDelete
  10. @lamakun

    Make it "file:///sdcard/liv-apks/es.png" and make sure the directory /sdcard/liv-apks exists.

    ReplyDelete
  11. Thank you very much Simon. I found out what the problem was and it was related to the permissions I had given the app in config.xml. I had been playing with them to check how it works and apparently I was avoiding the app to download contents (still haven't checked out which is the permission that controls it, I am on it right now).


    Thank you very much!!

    ReplyDelete
  12. @lamakun

    You were probably missing WRITE_EXTERNAL_STORAGE.

    ReplyDelete
  13. Hi again Simon,

    all of a sudden I find myself in a new problem that is keeping me stuck for hours. I have the following code:

    function wait(){
    $(document).ready(
    function() {
    document.addEventListener("deviceready", init(), true);
    }
    );
    }

    Where "wait" is a javscript function called from the onload event. I use the onload event, as well as $(document).ready and "deviceready" event to make sure every single thing is loaded when i start coding.

    The "init()" method does a few things and then calls the following method:

    function download_img(imgToDownload){
    var url = remote_url+imgToDownload;
    try{
    window.requestFileSystem(LocalFileSystem.PERSISTENT, 0,
    function (fs) {
    var imagePath = fs.root.fullPath +"/"+ imgToDownload; // full file path
    var fileTransfer = new FileTransfer();
    fileTransfer.download(url, imagePath,
    function (entry) {
    alert("OK: " + entry.fullPath); // entry is fileEntry object
    },
    function (error) {
    alert("download error source " + error.source);
    alert("download error target " + error.target);
    alert("upload error code" + error.code);
    alert("http_status"+error.http_status);
    }
    );
    }
    );
    }catch(err){ alert(err.message); } }

    Where I get the error message: "LocalFileSystem is not defined".

    My config.xml is:




    PhoneGap Build Application

    A simple PhoneGap Build application.


    Your Name








    In case I might add any permission, even though I think right now I have them all. It is happening to me in Android 2.3.3, and I don't know whether it might work fine in some other devices, but anyhow I need it to work in all Android/iOS devices. Do you have any idea why I am getting this error?

    Thanks Simon!!

    ReplyDelete
  14. @lamakun

    It isn't:

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

    it should be:

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

    having the () after init calls that function immediately before the deviceready event is fired.

    ReplyDelete
  15. Thanks Simon, we can keep on in stackoverflow so it might help more people ok?

    Thank you very much!!!

    ReplyDelete