Phonegap android plugin for download files from url on sd card

[UPDATE]
You can found an updated version of my plugin on GitHub
Thanks to Phillip Neumann.
—————————————

Hi folks, today I want to share with you this very useful phonegap‘s plug-in.
As the title says this plug-in allow you to download a file (url) on the sd card in the folder of your choice.

Usage

downloader.downloadFile(fileUrl,dirName,fileName,overwrite,win,fail);

Params

fileUrl: <String> The url of the file to download
dirName: <String> The directory where you want to save the file
fileName: <String> The name of the file
overwrite: <Boolean> Overwrite the file if exist
win: <Function> Success callback function. Receive a parameter that contains the fileName if the file is wrote with success.  If the overwrite parameter is false and the file already exist the parameter will contain the string “exist”.
fail: <Function> Fail callback function. Receive a parameter that contains the error message

Source and installation

Like all phonegap android plugins is composed by tha java file and the javascript one.
For starting using this plugin first copy the java file into the java src folder of your android project, in my example  the package is called com.example.pgplugins.DownloaderPlugin.

File: Downloader.java

package com.example.pgplugins.downloaderPlugin;

/*
 @author Mauro Rocco http://www.toforge.com
*/

import org.json.JSONArray;
import org.json.JSONException;

import android.util.Log;

import com.phonegap.DroidGap;
import com.phonegap.api.Plugin;
import com.phonegap.api.PluginResult;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class Downloader extends Plugin{

 @Override
 public PluginResult execute(String action, JSONArray args, String callbackId) {
 if (action.equals("downloadFile")) {
 try {
 return this.downloadUrl(args.getString(0),args.getString(1),args.getString(2),args.getString(3));
 } catch (JSONException e) {
 return new PluginResult(PluginResult.Status.ERROR, "Param errrors");
 }
 }
 else {
 return new PluginResult(PluginResult.Status.INVALID_ACTION);
 }

 }

 private PluginResult downloadUrl(String fileUrl, String dirName, String fileName, String overwrite){
 try{
 Log.d("DownloaderPlugin", "DIRECTORY CALLED /sdcard/"+dirName+" created");
 File dir =     new File("/sdcard/"+dirName);
 if(!dir.exists()){
 Log.d("DownloaderPlugin", "directory /sdcard/"+dirName+" created");
 dir.mkdirs();
 }

 File file = new File("/sdcard/"+dirName+fileName);

 if(overwrite.equals("false") && file.exists()){
 Log.d("DownloaderPlugin", "File already exist");
 return new PluginResult(PluginResult.Status.OK, "exist");
 }

 URL url = new URL(fileUrl);
 HttpURLConnection ucon = (HttpURLConnection) url.openConnection();
 ucon.setRequestMethod("GET");
 ucon.setDoOutput(true);
 ucon.connect();

 Log.d("DownloaderPlugin", "download begining");

 Log.d("DownloaderPlugin", "download url:" + url);

 InputStream is = ucon.getInputStream();

 byte[] buffer = new byte[1024];

 int len1 = 0;

 FileOutputStream fos = new FileOutputStream(file);

 while ( (len1 = is.read(buffer)) > 0 ) {
 fos.write(buffer,0, len1);
 }

 fos.close();

 Log.d("DownloaderPlugin", "Download complete in" + fileName);

 } catch (IOException e) {

 Log.d("DownloaderPlugin", "Error: " + e);
 return new PluginResult(PluginResult.Status.ERROR, "Error: " + e);

 }

 return new PluginResult(PluginResult.Status.OK, fileName);

 }

}

Now copy the following javascript file in the assets/www folder, remember to change the name of the package or the js will never found the java file.

File: downloader.js

function Downloader() {

}

Downloader.prototype.downloadFile = function(fileUrl,dirName,fileName,overwrite,win,fail) {
 if(overwrite==false) overwrite="false";
 else overwrite="true";
 PhoneGap.exec(win, fail, "Downloader", "downloadFile", [fileUrl,dirName,fileName,overwrite]);

};

PhoneGap.addConstructor(function() {
 PhoneGap.addPlugin("downloader", new Downloader());
 PluginManager.addService("Downloader","com.example.pgplugins.downloaderPlugin.Downloader");
});

For use it you have only to include the js file in the page and call it in this way

<script type="text/javascript" charset="utf-8" src="downloader.js"></script>
 <script type="text/javascript">

 window.plugins.downloader.downloadFile("http://www.toforge.com/archive.zip","sdcard/cache/","archive.zip", false,
 function(data){
 if(data=="exist"){
 alert("File already exist");
 }
 else{
 alert("File saved on sd card")
 }
 },function(data){ alert("error: "+data); });

 </script>

If you like it please jut say me “thanks” or send me 100000 € :-D .
See you on the next post

This entry was posted in Android and tagged , , , , , . Bookmark the permalink.
  • http://www.mycfmx.com/ Robbiegod

    Thanks! What do you plan to use this for?

  • Mauro Rocco

    Personally I use it for a caching system of a media player, that download the next songs in the playlist.

  • Simon MacDonald

    Good work on the android plugin. I’ll try to point people here from the google group. At some point I have to get around to putting the download capability in the FileTransfer object.

    Simon

  • Balaji

    Thanks for your code

  • Mauro Rocco

    @Balaji

    You welcome

    @Simon MacDonald

    Yes, phonegap need a writeFileFromUrl method ;-)

  • Abdul Rahman

    I got the error of below one, Did i need to add any code in androidmanifest.xml file ??

    04-07 16:53:00.617: ERROR/AndroidRuntime(758): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.example.pgplugins.downloaderPlugin/com.example.pgplugins.downloaderPlugin.Plugin}: java.lang.ClassNotFoundException: com.example.pgplugins.downloaderPlugin.Plugin in loader dalvik.system.PathClassLoader[/data/app/com.example.pgplugins.downloaderPlugin-1.apk]

    Please help me out !!! Thanks in advance

  • Mauro Rocco

    No, you don’t need anything in the manifest, just the pointer to the phonegap main activity
    Just add the plug-in as explained in the post at your phonegap working project
    http://www.phonegap.com/start#android

    As I can see from the error seems that you are trying to instantiate the plugin as activity, but you don’t have to.

  • mxride

    I believe I followed all direction and install correctly.
    Question on how to call the action?
    here is my html trying to call the action

    window.plugins.downloader.downloadFile("http://mxride.com/android/facebook_backup/downloads/album/album-080305080411.zip","sdcard/cache/","archive.zip", false,
    function(data){
    if(data=="exist"){
    alert("File already exist");
    }
    else{
    alert("File saved on sd card")
    }
    },function(data){ alert("error: "+data); });

    Dont get any action or errors to the logcat? Any hel is greatly appreciated

  • Mauro Rocco

    @mxride
    If you don’t see anything in the log cat probably is because you didn’t include the code of the file downloader.js, this code is responsible of create the downloader js object linked to the real java class, make sure that you include it after the init of phonegap/

  • Ken

    Hi,

    Works great!

    But I’m actually looking for a way to read an XML file on webserver and parse the XML with PhoneGap. I can download with your plugin, but how do I parse or is there an easier way,

    Thanks.

  • Mauro Rocco

    Well, you can open the local file after with the readFileAsText method of PhoneGap and then parse the result string with some javascript xml parser.
    But I think that in this case the best way to do it is to load the xml with an AJAX call, self writed or with a library like JqueryMobile, after you just have to parse the string in memory without any useless IO operation.
    I hope this could help

  • mxride

    Thanks Mauro for the feedback.
    I have

    window.plugins.downloader.downloadFile("http://mydomainpath.com/downloads/album/album-082904080411.zip","sdcard/cache/","archive.zip", false,
    function data(){
    if(data=="exist"){
    alert("File already exist");
    }
    else{
    alert("File saved on sd card")
    }
    },function(data){ alert("error: "+data); });

    In the head of my phonegap project,
    and I’m trying to call it with


    data

    button click
    I also tried calling

    data

    But I still get nothing in the log cat.
    Here is my downloader.js

    function Downloader() {

    }

    Downloader.prototype.downloadFile = function(fileUrl,dirName,fileName,overwrite,win,fail) {
    if(overwrite==false) overwrite="false";
    else overwrite="true";
    PhoneGap.exec(win, fail, "Downloader", "downloadFile", [fileUrl,dirName,fileName,overwrite]);

    };

    PhoneGap.addConstructor(function() {
    PhoneGap.addPlugin("downloader", new Downloader());
    PluginManager.addService("Downloader","com.moto.fbbIV.plugins.downloaderPlugin.Downloader");
    });

    And I have my JAVA located it
    com.moto.fbbIV.plugins.DownloaderPlugin

    As you can tell I’m new to phonegap and appreciate the support you offer
    Thanks again

  • Mauro Rocco

    @mxride I deleted the additional comment ;-),

    One problem can be the class path, be sure that the classpath specified in the downloader.js is the right path of the java file, be careful with upper case and lower case.
    For let me understand better the code go to pastie.org and paste the entire code of your phone gap main page and post the link here in the comment.

  • mxride

    Thanks Mauro,

    When you refer to my phonegap main page, are you referring to my HTML page located in the www directory or the Main Android JAVA activity?

    Thanks for removing my errors :)

  • mxride

    http://pastie.org/1832699

    link to my html phonegap that I thought should call the downloader

  • Mauro Rocco

    Hi mxride,
    Was more a javascript mistake that a phonegap mistake, you was calling an inexistent function, your main page edited like this probably works. ;-)

    http://pastie.org/1834365

    As you see I add a function definition doDownload, with the calling to the downloader inside, than onClick you call doDownload. Previously you wasn’t calling any real function but just an object reference.

  • mxride

    Mauro,

    Boy dont I feel silly.Thank you so much for your help. Not only did you help me but you taught me something I shall remember for ever. Your the best and thank you again for your time. do you have a paypal account I would like to send you a little something to show my appreciation.

    mxride

  • Mauro Rocco

    Actually I’ experiencing trouble with my paypal account I’m moving it in another country. Anyway thanks for the intention I really appreciate it.

  • volvox

    Hi,

    I tried to install your plugin, but I get a TypeError:

    Result of expression ‘window.plugins.downloader’ [undefined] is not an object.

    I double-checked the path to the Java file and loaded your plugin after phonegap.

    Any advice?

    Thanks!

  • Mauro Rocco

    @volvox
    Please paste the code of your main html phonegap page on pastie.org , and post the link in the comment, is the only way to help you.

  • volvox

    I really couldn’t find a mistake. Hope you can help me.

    http://pastie.org/1856728

    Thanks.

  • Mauro Rocco

    This is again a Javascript mistake :-) like mxride.
    This can’t work because you put the javascript to execute without any ready function, when the javascript try to call the object this is not defined yet.
    You can do two things
    1) Put the call of the download in the deviceReady callback of PhoneGap
    2) Put the whole call to the downloader in a function and call it onClick

    This is an example of call onClick event
    http://pastie.org/1834365

  • volvox

    Thanks! It’s working now.

  • mxride

    Mauro,

    Any suggestions on how to unzip the downloaded zip file?
    Or how download a complete directory unzipped?

    Many thanks in advance
    mxride

  • http://winterstein.me.uk Daniel

    Thanks for making this available!

    @Simon MacDonald: Please do add support for binary file download to Phonegap itself! This would be the feature I’d most like to see. Mauro’s plugin is Android only – for many apps it’s essential to have iPhone too.

  • Mauro Rocco

    @mxride you have to do it in java, here an example code

    http://code.google.com/p/myandroidwidgets/source/browse/trunk/UnzipTest/src/com/beanie/samples/unzip/HomeActivity.java

    you can also edit the downloader and make it recognize if the downloaded file is a zip and unzip it automatically.

  • Tom Jenkins

    Hiya

    I’ve got your class and JS working brilliantly, so thank you for that. I’m using it to download and store images to cache them for offline mode. My question is once I have saved the image to my destination folder e.g. /sdcard/cache/image.jpg how do I link to that in my HTML? I’m not 100% certain of the file paths that are being used.

    Is this even possible or will I have to move the file using the phonegap File API?

    Thank you for any help you can give

    Tom J

    :)

  • colamax

    hihi!
    this code:
    Downloader.prototype.downloadFile = function(fileUrl,dirName,fileName,overwrite,win,fail) {
    if(overwrite==false) overwrite=”false”;
    else overwrite=”true”;
    PhoneGap.exec(win, fail, “Downloader”, “downloadFile”, [fileUrl,dirName,fileName,overwrite]);
    };
    Not take effect?
    Can you help me solve this problem?
    THX?

  • Mauro Rocco

    @colamax as I say to everybody if you just post me back the same code that you found in the post how can I help you ??? Use pastie.org for paste you entire index.html and than post the link please.

  • http://www.rockit.at Wolfgang Rock

    Mauro, thank you very much for this plugin!
    Is there a way to download a file (image) from the applications asset/www-folder to the sd-card? I tried file:/// android_asset/www/image.jpg as fileUrl without success.
    This way it would be possible to copy files from the app to the local filesystem…
    Many thanks in advance,
    Wolfgang

  • Mauro Rocco

    With my plugin isn’t possible is done for open remote url.
    For do that you have to code another plugin that implement a copy (cp) command that works between assets and sd card. If you will do it let me know ;-) .

  • Mathieu B

    Hi!

    First, thank you for your plugin. I have two questions :

    (I’m using nexus one)
    Is it possible to write to the internal memory? I’ve tried to edit the java plugin to change the directory to save my file on internal memory but it doesn’t work.

    Why i’m asking this question is because I wonder, if you have a phone like nexus S, which doesn’t have external memory, where the plugin will save the file? Is there an “emulated” sdcard?

    Thanks for your help

  • Vishal Rajpal

    Hello Mauro
    I am receiving an error
    Class not found…
    Can you help me??

    This is the link to my html file
    http://pastie.org/2268317

  • Vishal Rajpal

    Sorry Mauro..
    I am done
    I just renamed that package in that .js file
    /..Thanx a lot

  • Mauro Rocco

    Great :-D

  • Vishal Rajpal

    Hello Mauro..Will this work for iPad also?? I mean with phonegap ??

  • Kody

    I keep getting a class not found error and the package path is correct… What am I doing wrong??? :/

  • KillFill

    I took this downloader example and put it in here with some modifications: https://github.com/killfill/phonegap-plugins/tree/master/Android/Downloader

    Thanks!!

  • Mauro Rocco

    @Vishal Rajpal
    Is a plugin for Android only

    @Kody
    More details ?

    @KillFill
    You welcome and thanks for the reference :-)

  • http://paksoftsystems.appspot.com/ azmat

    thanks as u suggested im sending u 100000 € :-D

    in e words :)

  • Vinicius

    I’m having some errors trting to use this plugin.

    Failed to run constructor: ReferenceError: Can’t find variable: PluginManager at file:///android_asset/www/js/phonegap-1.0.0.js:204

    org.json.JSONException: Value sdcard/cache/ at 1 of type java.lang.String cannot be converted to JSONObject

    at org.json.JSON.typeMismatch(JSON.java:96)

    at org.json.JSONArray.getJSONObject(JSONArray.java:484)

    at com.phonegap.plugins.downloader.Downloader.execute(Downloader.java:31)

    at com.phonegap.api.PluginManager$1.run(PluginManager.java:119) at java.lang.Thread.run(Thread.java:1020)

    Can somebody help me ?

  • Vinicius

    Fixed the others errors, but now i’m getting those

    PhoneGapLog(1031): file:///android_asset/www/js/phonegap-1.0.0.js: Line 645 : Error in success callback: Network Status1 = TypeError: ‘undefined’ is not an object (evaluating ‘window.plugins.downloader.downloadFile’)

    Web Console(1031): Error in success callback: Network Status1 = TypeError: ‘undefined’ is not an object (evaluating ‘window.plugins.downloader.downloadFile’) at file:///android_asset/www/js/phonegap-1.0.0.js:645

  • Mauro Rocco

    Vinicius for let me help you please post on pastie.org your html code

  • http://webission.com Smit

    thanks for this super plugin

    Actually i want it to display progress in percentage
    when download proccess is running so user can know that,
    so my question is what that plugin will respond when proccess is running if its showing some details like % or memory bytes then i can create progressbar using it

  • Mauro Rocco

    Hi, this plugin don’t do that.
    The java way is just put some response or feedback inside the while while ( (len1 = is.read(buffer)) > 0 ).
    Sincerely I don’t now hot to sent callback to the javascript front end inside a plugin body.
    Anyway this is an interesting point, I will try to figure out how to do it… but no promise. ;-)

  • Mook

    Hi,

    Sorry for my poor english, I am French.

    I have an error using this script : “Class not found”. Why ?

    I put the .java file in the “src” folder, the .js in the “www” folder and I have creating to it in the “html” file.

    Can you help me please ?

    Screenshot here : http://img810.imageshack.us/img810/8046/capturelm.jpg

  • http://webission.com Smit

    i was reading in your git post and found this

    `success` and `fail` are callback functions. Success will be called when there is a progress in the download. The passed object is:

    {

    status: 0, //0 means progress, 1 means download is complete.

    progress: 46, //In percent

    total: 1000, //The total number of bytes to download.

    file: “file.ext” //Name of the file

    }

    is it respond this in JSON ?

  • http://webission.com Smit

    i was reading in your git post and found this

    `success` and `fail` are callback functions. Success will be called when there is a progress in the download. The passed object is:

    {

    status: 0, //0 means progress, 1 download finished

    progress: 46, //In percent

    total: 1000, //The total number of bytes to download.

    file: “file.ext” //Name of the file

    }

    is it respond this in JSON ?
    can i get percentage from it every 5 sec so can create progress bar

    or im dreaming a bit

  • Mauro Rocco

    Sorry I don’t know where you read it, but is not something write by me. Anyway I’m checking actually if is possible do that, as soon as I have new I will write a post.

  • Mike

    I am trying to use your plugin, but I keep getting “cannot call method ‘downloadFile’ of undefined at file… ” I have the downloadFile method inside of a button click method for my project. Would you have any idea of my problem? Can post code.