Tuesday, February 21, 2012

PhoneGap Android Plugin to Extract ZipFile.

Hello Folks,

Its about after 2 months I thought of writing a post. So here is it. I was thinking to extract a .zip file from PhoneGap on android and I ended up implementing a plugin for it.

Include the below .java file with the same package mentioned.

/*
     Author: Vishal Rajpal
     Filename: ExtractZipFilePlugin.java
     Date: 21-02-2012
*/

package com.phonegap.plugin.ExtractZipFile;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import org.json.JSONArray;
import org.json.JSONException;
import com.phonegap.api.Plugin;
import com.phonegap.api.PluginResult;

public class ExtractZipFilePlugin extends Plugin {

    @Override
    public PluginResult execute(String arg0, JSONArray args, String arg2) {
        PluginResult.Status status = PluginResult.Status.OK;
        JSONArray result = new JSONArray();
        try {
            String filename = args.getString(0);
            File file = new File(filename);
            String[] dirToSplit=filename.split("/");
            String dirToInsert="";
            for(int i=0;i<dirToSplit.length-1;i++)
            {
                dirToInsert+=dirToSplit[i]+"/";
            }
            BufferedOutputStream dest = null;
            BufferedInputStream is = null;
            ZipEntry entry;
            ZipFile zipfile;
            try {
                zipfile = new ZipFile(file);
                Enumeration e = zipfile.entries();
                while (e.hasMoreElements())
                  {
                      entry = (ZipEntry) e.nextElement();
                      is = new BufferedInputStream(zipfile.getInputStream(entry));
                      int count;
                      byte data[] = new byte[102222];
                      String fileName = dirToInsert + entry.getName();
                      File outFile = new File(fileName);
                      if (entry.isDirectory())
                      {
                          outFile.mkdirs();
                      }
                      else
                      {
                          FileOutputStream fos = new FileOutputStream(outFile);
                          dest = new BufferedOutputStream(fos, 102222);
                          while ((count = is.read(data, 0, 102222)) != -1)
                          {
                              dest.write(data, 0, count);
                          }
                          dest.flush();
                          dest.close();
                          is.close();
                      }
                  }
            } catch (ZipException e1) {
                // TODO Auto-generated catch block
                return new PluginResult(PluginResult.Status.MALFORMED_URL_EXCEPTION);
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                return new PluginResult(PluginResult.Status.IO_EXCEPTION);
            }
           
        } catch (JSONException e) {
            // TODO Auto-generated catch block
            return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
        }
        return new PluginResult(status);
    }

}


Include the below .js file in your phonegap project.

/*
     Author: Vishal Rajpal
     Filename: ZipPlugin.js
     Date: 21-02-2012
*/

var ExtractZipFilePlugin=function(){
};

PhoneGap.addConstructor(function()
{
    PhoneGap.addPlugin('ExtractZipFilePlugin', new ZipPlugin());
});

ExtractZipFilePlugin.prototype.extractFile = function(file, successCallback, errorCallback)
{
    alert(file);
    return PhoneGap.exec(successCallback, errorCallback, "ZipPlugin", "extract", [file]);
};



Lastly include this plugin in the plugins.xml of your project.


<plugin name="ZipPlugin" value="com.phonegap.plugin.ExtractZipFile.ExtractZipFilePlugin" />

Usage i.e. .html file

<!--
     Author: Vishal Rajpal
     Filename: index.html
     Date: 21-02-2012
-->

<html>
<head>
<script type="text/javascript" src="phonegap-1.3.0.js"></script>
<script type="text/javascript" src="ZipPlugin.js"></script>

<script type="text/javascript">

document.addEventListener("deviceready",onDeviceReady);

function onDeviceReady()
{
}

function extractFile(fileName)
{
    alert(fileName);
    var ZipClient = new ExtractZipFilePlugin();
    ZipClient.extractFile('sdcard/'+fileName,win,fail,'ExtractZipFilePlugin');
}
function win(status)
{
   alert('Success'+status);
}
 
function fail(error)
{
    alert(error);
}
</script>
</head>
<body>
<input type="button" value="Extract Zip File" onClick="extractFile('SampleDir/AnotherDir/SampleFile.zip');"/>
</body>

</html>

The default location for the file has to be sdcard then it can be as many directories or no directory i.e.
extractFile('SampleFile.zip');

The plugin will work both ways.

Thanks. Any suggestions or comments will be helpful.

37 comments:

  1. Thanks. And I will test it. I need it.

    ReplyDelete
  2. I tested it. And it work ok. Thanks.

    ReplyDelete
  3. i tried it but it gives me this error
    Default buffer size used in BufferedInputStream constructor. It would be better to be explicit if an 8k buffer is required.
    please what does that mean or what did i get wrong?

    ReplyDelete
    Replies
    1. Hi Kamal

      Try

      new BufferedInputStream(zipfile.getInputStream(entry), 8192);

      instead of
      new BufferedInputStream(zipfile.getInputStream(entry));

      Delete
  4. Hi Vishal, I am having a bit of trouble implementing this code in phonegap 1.9.0 I am using it to unzip an epub file and it gets as far as FileOutputStream fos = new FileOutputStream(outFile); but then throws the FileNotFoundException any ideas ? It can definately read the file ok as I can see it loop through all the contents.

    ReplyDelete
    Replies
    1. Just in case someone else has the same issue, I had to add the following two lines File destinationParent = outFile.getParentFile();
      destinationParent.mkdirs();

      above:
      if (entry.isDirectory())
      {
      outFile.mkdirs();
      }

      Delete
    2. That's great Sam, I will make the changes and commit it to the phonegap directory.

      Delete
  5. hi i am using your plugin but is given the error " Uncaught TypeError: Object [object Object] has no method 'extractFile'" i am using cordova-2.0.0.js

    ReplyDelete
    Replies
    1. Hi Kapil,
      Here is a link to the plugin
      https://github.com/vishalrajpal/phonegap-plugins/tree/master/Android/ExtractZipFile

      Though I have added a pull request to PhoneGap repository they haven't updated it yet.

      Delete
    2. Please, I have same problem in cordova 2.0.0
      " Uncaught TypeError: Object [object Object] has no method 'extractFile'"

      How can I fix this.

      Thank you

      Delete
    3. Hi Rafa,

      Did you downloaded the plugin from the below github link?

      https://github.com/vishalrajpal/phonegap-plugins/tree/master/Android/ExtractZipFile

      Delete
  6. I have implement this plugin its work fine for 2.0 but how can I get destination directory or location.

    ReplyDelete
    Replies
    1. Hi Im...
      The destination directory is where the .zip file is located.

      Delete
    2. Thx vishal
      but can we get extract content(listing of extracted zip file ) in success call back or using anything else ?

      Delete
    3. Success callback is when the zip file is extracted...

      Delete
    4. ok I am agree with you but I need listing of extracted zip file

      Delete
    5. after the extraction use PhoneGap DirectoryReader....
      isn't that simple??

      Delete
    6. this plugin is not working for me in 2.3.0 can someone help me implement it?

      Delete
    7. Hi Neels

      Refer to the below repo as there are some changes in 2.3.0

      https://github.com/vishalrajpal/PhoneGap-ZipFile-Plugin-2.3.0

      Thanks

      Delete
    8. Thank you for your help.

      When adding the plugin i get "The import java.io.Console cannot be resolved" .

      what am i doing wrong and is this needed to perform the unzip?

      thanks again.

      Delete
    9. Neels that was just for debugging. You may remove it.

      Delete
    10. thank you. got it running but now i get "class not found" on fail. what can be the problem?

      Delete
    11. changed the ZipPlugin.js to:
      return cordova.exec(successCallback, errorCallback, "ZipPlugin", "extract", [file]);

      now it seems to get the class

      but now i get IO_exception and invalid action?

      just cant make this work...... :(

      Delete
    12. Hi Neels,

      I provided you the link above for the updated plugin. Refer that one. You seem to have using the Old one.

      Delete
    13. Thank you again for your help.

      I did install the new version again and i still get the class not found

      Delete
    14. what should be in the config.xml?

      Delete
  7. Hello Vishal, i am using codova-2.5.0, do i need to make any changes ?
    i am not able to make it work i am getting many errors in ExtracZipFilePlugin.java

    Best Regards

    ReplyDelete
  8. Hi Yama,
    I hope you have downloaded the latest plugin..I will also check this with 2.5.0
    Below is the link for recent plugin..

    https://github.com/vishalrajpal/phonegap-plugins/tree/master/Android/ExtractZipFile

    ReplyDelete
    Replies
    1. Hello Vishal,

      I'm using Cordova 2.5.0 too and your latest version (22-01-2013), I get a "Class not found" error :(

      What should I change ?

      Kind regards

      Delete
    2. Hi,

      Sorry but I will have to look into it, will revert back to you soon

      Delete
    3. Hello,

      This worked for me:
      replace this:
      <plugin name="ZipPlugin" value="com.phonegap.plugin.ExtractZipFile.ExtractZipFilePlugin" />
      with this:
      <plugin name="ExtractZipFilePlugin" value="com.phonegap.plugin.ExtractZipFile.ExtractZipFilePlugin" />

      Not "Class not found" anymore but IO_EXCEPTION instead. But this error is produced by the plugin itself, while "Class not found" is Cordova. I am not sure if it's correct, but that's how I understand that.

      Delete
    4. Solved IO_Exception. It doesn't create directory prior writing the file. Fortunately my project doesn't require folder structure in data. But I hope it helps you finding errors.

      Cheers

      Delete
    5. Hey Vit, thank you i can solved the "Class not found".. but as you said, i got "IO_Exception" but i dont understand how you solved, could you please guide me a little? Thanks!

      Delete
  9. I can't import com.phonegap.api.Plugin; My project does not contain it. Please help me!

    ReplyDelete
    Replies
    1. Hi Nguyen,

      Use the latest one from the below link
      https://github.com/vishalrajpal/PhoneGap-ZipFile-Plugin-2.3.0

      Delete
  10. I need to use your plugin with Phonegap 2.8.0.
    The configuration used in the documentation doesn't work!
    I had to change the ZipFile.js file and the plugin xml node like that:

    var ExtractZipFilePlugin=function(){
    };

    /*cordova.addConstructor(function()
    {
    cordova.addPlugin('ExtractZipFilePlugin', new ExtractZipFilePlugin());
    });*/

    if(!window.plugins) {
    window.plugins = {};
    }
    if (!window.plugins.extractZipFilePlugin) {
    window.plugins.extractZipFilePlugin = new ExtractZipFilePlugin();
    }

    ExtractZipFilePlugin.prototype.extractFile = function(file, successCallback, errorCallback)
    {
    return cordova.exec(successCallback, errorCallback, "ExtractZipFilePlugin", "extract", [file]);
    };





    When I try to unzip a file now I get the error "invalid action"! What should I do? I download a zip file in the sdcard root then I try to unzip it. Can I set the unzip destination folder?

    I need your help as soon as possible.
    Thanks

    ReplyDelete
  11. Hi,
    I also have a problem with your plugin (I'm using phonegap 2.7.0).
    According to this article: http://ambrusmartin.wordpress.com/2012/09/17/cordova-2-0-broken-vs-resolved/ this part:

    cordova.addConstructor(function()
    {
    cordova.addPlugin('ExtractZipFilePlugin', new ExtractZipFilePlugin());
    });

    ExtractZipFilePlugin.prototype.extractFile = function(file, successCallback, errorCallback)
    {
    return cordova.exec(successCallback, errorCallback, "ExtractZipFilePlugin", "extract", [file]);
    };

    should be changed to something like:

    var ExtractZipFilePlugin = {
    extractFile: function(file, successCallback, errorCallback){
    cordova.exec(successCallback, errorCallback, "ExtractZipFilePlugin", "extract", [file]);
    }
    }

    But it still doesn't work for me (Error: object is not a function).

    Thanks in advance for any help.

    ReplyDelete