Skip to content
This repository has been archived by the owner on Apr 29, 2021. It is now read-only.

Commit

Permalink
Add FileUploader plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
Matt Kane committed Nov 5, 2010
1 parent ae67c7d commit 3cc7031
Show file tree
Hide file tree
Showing 3 changed files with 383 additions and 0 deletions.
245 changes: 245 additions & 0 deletions Android/FileUploader/FileUploader.java
@@ -0,0 +1,245 @@
/**
*
*/
package com.beetight;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import android.net.Uri;
import java.net.URL;
import java.util.Iterator;

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

import android.util.Log;
import android.webkit.CookieManager;

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

/**
* @author matt
*
*/
public class FileUploader extends Plugin {

/* (non-Javadoc)
* @see com.phonegap.api.Plugin#execute(java.lang.String, org.json.JSONArray, java.lang.String)
*/
@Override
public PluginResult execute(String action, JSONArray args, String callbackId) {

try {
String server = args.getString(0);
String file = args.getString(1);
JSONObject params = args.getJSONObject(2);

String fileKey = "file";
String fileName = "image.jpg";
String mimeType = "image/jpeg";
if(args.length() > 3) {
fileKey = args.getString(3);
}
if(args.length() > 4) {
fileName = args.getString(4);
}
if(args.length() > 5) {
mimeType = args.getString(5);
}

if (action.equals("upload")) {
upload(file, server, params, fileKey, fileName, mimeType, callbackId);
} else if (action.equals("uploadByUri")) {
Uri uri = Uri.parse(file);
upload(uri, server, params, fileKey, fileName, mimeType, callbackId);
} else {
return new PluginResult(PluginResult.Status.INVALID_ACTION);
}
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
r.setKeepCallback(true);
return r;
} catch (JSONException e) {
e.printStackTrace();
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
}

}

public void upload(Uri uri, String server, JSONObject params, final String fileKey, final String fileName, final String mimeType, String callbackId) {
try {
InputStream fileInputStream=this.ctx.getContentResolver().openInputStream(uri);
upload(fileInputStream, server, params, fileKey, fileName, mimeType, callbackId);
} catch (FileNotFoundException e) {
Log.e("PhoneGapLog", "error: " + e.getMessage(), e);
}
}

public void upload(String filename, String server, JSONObject params, final String fileKey, final String fileName, final String mimeType, String callbackId) {
File uploadFile = new File(filename);
try {
FileInputStream fileInputStream = new FileInputStream(uploadFile);
upload(fileInputStream, server, params, fileKey, fileName, mimeType, callbackId);
} catch (FileNotFoundException e) {
Log.e("PhoneGapLog", "error: " + e.getMessage(), e);
}

}


public void upload(InputStream fileInputStream, String server, JSONObject params, final String fileKey, final String fileName, final String mimeType, final String callbackId) {
try {

String lineEnd = "\r\n";
String td = "--";
String boundary = "*****com.beetight.formBoundary";

URL url = new URL(server);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();

// Get cookies that have been set in our webview
CookieManager cm = CookieManager.getInstance();
String cookie = cm.getCookie(server);

// allow inputs
conn.setDoInput(true);
// allow outputs
conn.setDoOutput(true);
// don't use a cached copy
conn.setUseCaches(false);
// use a post method
conn.setRequestMethod("POST");
// set post headers
conn.setRequestProperty("Connection","Keep-Alive");
conn.setRequestProperty("Content-Type","multipart/form-data;boundary="+boundary);
conn.setRequestProperty("Cookie", cookie);
// open data output stream
DataOutputStream dos = new DataOutputStream(conn.getOutputStream());

try {
for (Iterator iter = params.keys(); iter.hasNext();) {
Object key = iter.next();
dos.writeBytes(td + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"" + key + "\"); ");
dos.writeBytes(lineEnd + lineEnd);
dos.writeBytes(params.getString(key.toString()));
dos.writeBytes(lineEnd);
}
} catch (JSONException e) {
Log.e("PhoneGapLog", "error: " + e.getMessage(), e);
}


dos.writeBytes(td + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"" + fileKey + "\";filename=\"" + fileName + "\"" + lineEnd);
dos.writeBytes("Content-Type: " + mimeType + lineEnd);

dos.writeBytes(lineEnd);
// create a buffer of maximum size
int bytesAvailable = fileInputStream.available();
final int total = bytesAvailable;
Log.e("PhoneGapLog", "available: " + bytesAvailable);

int maxBufferSize = 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[] buffer = new byte[bufferSize];
// read file and write it into form...
int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
int progress = bytesRead;
int send = 0;
while (bytesRead > 0)
{
dos.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
progress += bytesRead;
final int prog = progress;
Log.e("PhoneGapLog", "read " + progress + " of " + total);

// Sending every progress event is overkill
if (send++ % 20 == 0) {
ctx.runOnUiThread(new Runnable () {
public void run() {
try {
JSONObject result = new JSONObject();
result.put("status", FileUploader.Status.PROGRESS);
result.put("progress", prog);
result.put("total", total);
PluginResult progressResult = new PluginResult(PluginResult.Status.OK, result);
progressResult.setKeepCallback(true);
success(progressResult, callbackId);
} catch (JSONException e) {
Log.e("PhoneGapLog", "error: " + e.getMessage(), e);
}
}
});
// Give a chance for the progress to be sent to javascript
Thread.sleep(100);
}
}
// send multipart form data necessary after file data...
dos.writeBytes(lineEnd);
dos.writeBytes(td + boundary + td + lineEnd);

// close streams
fileInputStream.close();
dos.flush();
InputStream is = conn.getInputStream();
int ch;
StringBuffer b =new StringBuffer();
while( ( ch = is.read() ) != -1 ) {
b.append( (char)ch );
}
String s=b.toString();
dos.close();
JSONObject result = new JSONObject();
result.put("status", FileUploader.Status.COMPLETE);

result.put("progress", progress);
result.put("total", total);
result.put("result", s);
PluginResult progressResult = new PluginResult(PluginResult.Status.OK, result);
progressResult.setKeepCallback(true);
success(progressResult, callbackId);

}
catch (MalformedURLException e) {
Log.e("PhoneGapLog", "error: " + e.getMessage(), e);
PluginResult result = new PluginResult(PluginResult.Status.MALFORMED_URL_EXCEPTION, e.getMessage());
error(result, callbackId);
}
catch (FileNotFoundException e) {
Log.e("PhoneGapLog", "error: " + e.getMessage(), e);
PluginResult result = new PluginResult(PluginResult.Status.ERROR, e.getMessage());
error(result, callbackId);
}
catch (IOException e) {
Log.e("PhoneGapLog", "error: " + e.getMessage(), e);
PluginResult result = new PluginResult(PluginResult.Status.IO_EXCEPTION, e.getMessage());
error(result, callbackId);
} catch (InterruptedException e) {
Log.e("PhoneGapLog", "error: " + e.getMessage(), e);
PluginResult result = new PluginResult(PluginResult.Status.ERROR, e.getMessage());
error(result, callbackId);
} catch (JSONException e) {
Log.e("PhoneGapLog", "error: " + e.getMessage(), e);
PluginResult result = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
error(result, callbackId);
}
}

public enum Status {
PROGRESS,
COMPLETE
}


}
70 changes: 70 additions & 0 deletions Android/FileUploader/README.md
@@ -0,0 +1,70 @@
# File Uploader plugin for Phonegap #
By Matt Kane

## Adding the Plugin to your project ##

1. To install the plugin, move fileuploader.js to your project's www folder and include a reference to it
in your html files.
2. Create a folder called "beetight" within your project's src/com/ folder and move the java file into it.

## Using the plugin ##
The plugin creates the object `window.plugins.fileUploader` with two methods, `upload` and `uploadByUri`.
These are identical except for the format of the reference to the file to upload. `upload` takes an
absolute path, e.g. `/sdcard/media/images/image.jpg`, while `uploadByUri` takes a content:// Uri,
e.g. `content://media/external/images/media/5`.
The full params are as follows:

* server URL of the server that will receive the file
* file Path or uri of the file to upload
* fileKey Object with key: value params to send to the server
* params Parameter name of the file
* fileName Filename to send to the server. Defaults to image.jpg
* mimeType Mimetype of the uploaded file. Defaults to image/jpeg
* callback Success callback. Also receives progress messages during upload.
* fail Error callback

Note that the success callback isn't just called when the upload is complete, but also gets progress
events while the file is uploaded. It's passed an object of the form:

{
status: 'PROGRESS', //Either FileUploader.Status.PROGRESS or FileUploader.Status.COMPLETE,
progress: 0, //The number of bytes uploaded so far.
total: 1000, //The total number of bytes to upload.
result: "OK" //The string returned from the server. Only sent when status = complete.
}

This is under development, and the API is likely to change.


## BUGS AND CONTRIBUTIONS ##
The latest bleeding-edge version is available [on GitHub](http://github.com/ascorbic/phonegap-plugins/tree/master/Android/)
If you have a patch, fork my repo baby and send me a pull request. Submit bug reports on GitHub, please.

## Licence ##

The MIT License

Copyright (c) 2010 Matt Kane

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.





68 changes: 68 additions & 0 deletions Android/FileUploader/fileuploader.js
@@ -0,0 +1,68 @@
/**
* Phonegap File Upload plugin
* Copyright (c) Matt Kane 2010
*
*/
var FileUploader = function() {

}


/**
* Given a content:// uri, uploads the file to the server as a multipart/mime request
*
* @param server URL of the server that will receive the file
* @param file content:// uri of the file to upload
* @param fileKey Object with key: value params to send to the server
* @param params Parameter name of the file
* @param fileName Filename to send to the server. Defaults to image.jpg
* @param mimeType Mimetype of the uploaded file. Defaults to image/jpeg
* @param callback Success callback. Also receives progress messages during upload.
* @param fail Error callback
*/
FileUploader.prototype.uploadByUri = function(server, file, params, fileKey, fileName, mimeType, callback, fail) {

return PhoneGap.exec(function(args) {
callback(args);
}, function(args) {
if(typeof fail == 'function') {
fail(args);
}
}, 'FileUploader', 'uploadByUri', [server, file, params, fileKey, fileName, mimeType]);
};

/**
* Given absolute path, uploads the file to the server as a multipart/mime request
*
* @param server URL of the server that will receive the file
* @param file Absolute path of the file to upload
* @param fileKey Object with key: value params to send to the server
* @param params Parameter name of the file
* @param fileName Filename to send to the server. Defaults to image.jpg
* @param mimeType Mimetype of the uploaded file. Defaults to image/jpeg
* @param callback Success callback. Also receives progress messages during upload.
* @param fail Error callback
*/
FileUploader.prototype.upload = function(server, file, params, fileKey, fileName, mimeType, callback, fail) {

return PhoneGap.exec(function(args) {
if(typeof callback == 'function') {
callback(args);
}
}, function(args) {
if(typeof fail == 'function') {
fail(args);
}
}, 'FileUploader', 'upload', [server, file, params, fileKey, fileName, mimeType]);
};


FileUploader.Status = {
PROGRESS: "PROGRESS",
COMPLETE: "COMPLETE"
}

PhoneGap.addConstructor(function() {
PhoneGap.addPlugin('fileUploader', new FileUploader());
PluginManager.addService("FileUploader","com.beetight.FileUploader");
});

0 comments on commit 3cc7031

Please sign in to comment.