Last days I’ve working in a phonegap/cordova project. The main purpose of the project was taking photos with the device’s camera and sending them to the server. It’s a simple apache cordova project using the camera plugin. According to the documentation we can upload pictures with the following javascript code:
navigator.camera.getPicture(onSuccess, onFail, { quality: 100, destinationType: Camera.DestinationType.DATA_URL }); function onSuccess(imageData) { // here we can upload imageData to the server } function onFail(message) { alert('Failed because: ' + message); }
As we can see we our plugin retrieves a base64 encoded version of our image and we can send it to the server, using jQuery for example
function onSuccess(imageData) { $.post( "upload.php", {data: imageData}, function(data) { alert("Image uploaded!"); }); }
Our server side is trivial. We only need to read the request variable ‘data’, perform a base64 decode and we have our binary picture ready to be saved.
I test it with an old android smartphone (with a not very good camera) and it’s works, but when I tried to use it with a better android phone (with 8mpx camera) it hangs on and it didn’t work. After property reading the documentation I realized that it isn’t the better way to upload files to the server. It only works if the image file is small. Base64 increases the size of the image and our device can have problems handling the memory. This way Is also slow as hell.
The best way (the way that works, indeed) is, instead of sending the base64 files to the server, to save them into a device’s temporary folder and send them using the file transfer plugin.
var pictureSource; // picture source var destinationType; // sets the format of returned value document.addEventListener("deviceready", onDeviceReady, false); function onDeviceReady() { pictureSource = navigator.camera.PictureSourceType; destinationType = navigator.camera.DestinationType; } function clearCache() { navigator.camera.cleanup(); } var retries = 0; function onCapturePhoto(fileURI) { var win = function (r) { clearCache(); retries = 0; alert('Done!'); } var fail = function (error) { if (retries == 0) { retries ++ setTimeout(function() { onCapturePhoto(fileURI) }, 1000) } else { retries = 0; clearCache(); alert('Ups. Something wrong happens!'); } } var options = new FileUploadOptions(); options.fileKey = "file"; options.fileName = fileURI.substr(fileURI.lastIndexOf('/') + 1); options.mimeType = "image/jpeg"; options.params = {}; // if we need to send parameters to the server request var ft = new FileTransfer(); ft.upload(fileURI, encodeURI("http://host/upload"), win, fail, options); } function capturePhoto() { navigator.camera.getPicture(onCapturePhoto, onFail, { quality: 100, destinationType: destinationType.FILE_URI }); } function onFail(message) { alert('Failed because: ' + message); }
I just realized that sometimes it fails. It looks like a bug of cordova plugin (I cannot assert it), because of that, if you read my code, you can see that if fp.upload fails I retry it (only once). With this little hack it works like a charm (and it’s also fast).
The server part is pretty straightforward. We only need to handle uploaded files. Here a minimalistic example with php
<?php move_uploaded_file($_FILES["file"]["tmp_name"], '/path/to/file');
And that’s all. We can easily upload our photos from our smartphone using phonegap/cordova.
You can read more articles about cordova here.
Very nice. Could you do an article the other way around too? Download a picture from a URL, store it in localStorage or SD card and reference to it in the app.
Can you tell how to show progress-bar while uploading multiple images to the server.
AFAIK it isn’t possible. To upload files we need to use one cordova plugin: FileTransfer (http://cordova.apache.org/docs/en/3.1.0/cordova_file_file.md.html#FileTransfer) and it does’t provide us any callback with the partial uploads. I use a “fake” progress bar to give feedback to user.
What’s with the “if (retries == 0) { retries ++” part. It looks like that would only retry once. If that’s the case, why not just “navigator.camera.getPicture(function (fileUri){ setTimeout(onCapturePhoto(fileUri))}…” to begin with?
It was a hack. I realize that sometimes the upload fails (one error in android’s log) but it works if I send it twice (something related to android’s main thread). With this hack the app works fine (it’s ugly, I know, but it works).
Finally I discover something (not documented in the oficial cordova documentation). I neet to close the connection when I upload files. So if we add this options:
options.chunkedMode = true;
options.headers = {Connection: "close"};
We don’t need this hack
Hey, i am unable to upload images with the above code.. it works fine till capturing the image. but its not sending to server
provably it’s due to versions. AFAIK new cordova versions has small changes in API. And provably that’s the problem (this code works in my installation but it’s not the last version). You must check the device’s log (adb logcat or using the IDE’s console)
You should probably pay more attention to your code. We got it working.
Check Developer options on your device and remove Do not Keep activities check box, might be the problem in this case
Hey i read your post and am trying to implement it. Is it possible to upload multiple photos to the server at a timer using this code
hey please respond ASAP thanks in advance
FileTransfer object (provided by cordova) only allows to upload one file, but you can upload all the multiple files at the same time. This example uploads the uri of the picture to the server, but you can store the uri in the client app and send them to the server
Thanks for the clarity
2014-06-16 16:43:26.325 helloworld[11449:cf07] File Transfer Finished with response code 200
Can you help me with this I follow the instructions but I get this erro!!
I don’t know where your log come from (cordova app, backend, …) but 200 means OK
which method it uses to send the image among “POST”,”PUT” etc
can we send it using “PUT” method…..
you can upload your files using a simple post request but that’s definitively slower than use FileTransfer object. AFAIK FileTransfer uses post but I’m not sure right now.
I have a web site that uses dojo toolkit and when I attempt to create a .sdk with cordova much of the functions work really well. However, my embedded videos show the ‘play icon’ but do not run and there is no sound. What’s a good way to make sure cordova recognizes dojo?
use adb logcat (with android) to check what’s the error.
Thanks Gonzalo! I will dig further into this. Some had also suggested at a very minimum, I need to install a video plugin from github.
Is there a good reference for adding a plugin for video ( I have installed plugman, as stated in the cordova lit), but not sure if it will be automatically placed in the folders.
I have been using videojs with great results. Easy to implement: http://www.videojs.com/
Testing with the real device is definitely the worse part when we develop cordova app Handle. I recommend install plugins always using the standard tools (cordova plugin add)
Thanks so much for these suggestions. I think I am all set on the Cordova side, just trying to figure out where to insert plugin code on the web-page side of things. The site was created by a software using dojo. Would including on the index.html suffice, or do I need to dig for actual calling of the video.
Thanks for this post, it was really helpful!
I want to use the filetransfer plugin to upload a picture to my server, which is based on Django (Using django rest framework token authentication). Since the picture is associated to a registered user, I’m wondering if is it possible to set the authentication token to the request header. If not, I guess I will need to find out some hacky solution for this approach.
Thanks in advance for any suggestion!
When you upload a file with FileTransfer object you create a simple http request. With this object you can pass the any parameter, including your auth token. This example uses a very simple PHP script at server side, but you can use whatever you need (It’s just a file upload)
Thanks, I managed that using the options:
options.headers = {‘Authorization’: ‘Token ‘ + localStorage.token };
I Am David, and I am looking for a pluging that carries several photos and videos multi-platform at once, it already exists?
It would be a pluging to upload many photos and videos that on my cell phone at once.
Thank you for attention
I don’t know any plugin to to it, but anyway you can perform this operation with standard File plugins
Hi there, I want to support browsing of image so I referenced your code and come up with this:
browsePicture: function (success, error) {
navigator.camera.getPicture(success, error,
{
quality: 50,
destinationType: Camera.DestinationType.DATA_URL,
sourceType: Camera.PictureSourceType.SAVEDPHOTOALBUM,
encodingType: Camera.EncodingType.PNG,
correctOrientation: true,
allowEdit: true
}
);
}
This works fine, but it always pickup the same cache image from “Android/myapp/data/cache” even if I choose different file.. Can you help me?
Oops… The above works now..
before it was estinationType: Camera.DestinationType.FILE_URI,
anyway you should avoid DATA_URL to avoid common memory problems
Hi, i’ve very problems with this.
I have not problemas with the comunications, but i don’t get anything in the server PHP in $_POST or $_FILE request.
I’ve this code:
$scope.captureImage = function () {
Camera.getPicture().then(function (imageURI) {
logService.log(1, imageURI);
var options = new FileUploadOptions();
options.fileKey = “file”;
options.fileName = imageURI.substr(imageURI.lastIndexOf(‘/’) + 1);
options.mimeType = “image/jpeg”;
options.chunkedMode = false; // Transfer picture to server
var params = {};
params.value1 = “test”;
params.value2 = “param”;
options.params = params;
var ft = new FileTransfer();
ft.upload(imageURI, encodeURI(configService.getWSBase() + ‘/api/register/uploadPhoto/format/json’), win, fail, options);
$scope.regisData.image = imageURI;
}, function (err) {
console.err(err);
});
};
And in my PHP server:
string(7) “$_FILES”
array(0) {
}
string(6) “$_POST”
array(0) {
}
Can you help me please?
Sorry for my bad english.
Ensure that you don’t have any error. Check the win and fail callbacks. Check also the device’s console (https://gonzalo123.com/2014/08/04/debugging-android-cordovaphonegap-apps-with-chrome/). Ensure also that the cordova api is correct. This post is old (+1 year old) Cordova api is a live project and sometimes it changes. Ensure also that destinationType: Camera.DestinationType.DATA_URL
Hello Gonzalo, thx for your great tutorial!
iam unable to upload pictures in the of two steps:
1. capture the picture with button A
2. upload the picture with button B
Your script uploads pictures immediantly after taking. How can i do this?
navigator.camera.getPicture with destinationType: destinationType.FILE_URI takes a picture, stores it locally and triggers onCapturePhoto callback. You can do whatever you need here.
It’s pretty straightforward to do it. You only need to store fileURI within an object (with button A) and upload all stored fileURIs with button B
I’m having difficult to get destinationType.FILE_URI working. it is set but the succesCallback always return DATA_URL, and i don’t understand why. Heres my code:
this.capturePhoto = function() {
navigator.camera.getPicture(o.onCapturePhoto, o.onFail, {
quality : 75,
destinationType : Camera.DestinationType.FILE_URI,
sourceType : Camera.PictureSourceType.CAMERA,
allowEdit : true,
encodingType: Camera.EncodingType.JPEG,
targetWidth: 100,
targetHeight: 100,
popoverOptions: CameraPopoverOptions,
saveToPhotoAlbum: false });
};
Hola,
Gracias por compartir tu código, me ha servido de mucho ahora lo estoy implantando en mi app y funciona de maravilla, en las primeras pruebas que he hecho.
Saludos
hi plz help me on how to send image to server…every time i am tried this code i get a error code “2” msg……plz upload a complete source code on github in core php (i don’t know silex)………
Hi, If i print the fileName, It displayed as “473” instead of “abc.jpg”. I need to show the selected file name in my application. Please reply
Hi Gonzalo. Thanks very much. I’ve tried following your code but my image doesn’t get to the server side, I really wonder what I could be missing. If you have uploaded this project to github, could you please send me the link.
Cool article – helped very much.
One little thing I’ve noticed – while it does transfer the file and the file does end up on the remote server – the success function (win) never seems to activate. It doesn’t call the fail, but basically once the transfer is done (apparently) it just kinda sits there.
Any idea why? lol
Check your server logs. Plugins performs a simple file upload. Create one script to upload a file (without cordova. just plain html). For example I use PHP in the backend. Normally I don’t use a web server in the developing process. I run my backend with the PHP’s built-in web server (php -S 0.0.0.0:8080 -t www). Ok this built-in server is not ready for production, and AFAIK file uploads doesn’t work. Maybe you have a similar problem
can I place a header/footer/buttons over the top of the camera image in phonegap through cordava plugin?
I am using this code but having one problem while I am selecting pic from the photolibrary my application stops working and getting alert unfortunately your application has been stop working
Is there any solution ?????
Let me know as soon possible
Thanking you !!!
with this kind of issues I recommend to upgrade everything (cordova, plugins, …). Then, with the last version of all check the logs (adb logcat). It’s looks like a plugin problem. Phonegap/cordava plugins are very “live”
hello ;
how we can do the against situation by receiving message and photo from server to the phonegap /cordova app
what possible plugin fro used with socket ? which version that support android higher than 4:4
thanks
i am able to uplaod picture from gallery n camera but don’t know sometimes when i am uploading it’s crashing my application and application restart nay idea.
I am making phonegap app for iOS. Uploading of images which is taken from camera takes around 15 seconds where as from gallery it takes around 5-6 seconds, Is there anyway to compress image before sending to the server, changing the quality didn’t work for me.
Thanks in advance.
i am trying to capture two pictures and sending to server in a specific folder. The problem is one image is uploaded to the specific folder but other image is out of the folder.
Don’t understand why but this code never worked while I tried to upload to my windows asp.net server (both production & development), while I debug it happens to step into the web method but does not contain file in HttpContext ref. http://stackoverflow.com/questions/37748110/file-upload-fails-from-android-to-asp-net-server it seems not many experienced this issue, unfortunately was struct since yesterday. Thanks for your post anyways..
I haven’t ever played with asp.net servers. The Cordova FileTransfer are almost the same as File uploads in HTML. If your backend can handle file uploads it shouldn’t have problems with Cordova FileTransfer. At least in PHP is pretty straightforward. But when I run the PHP’s built-in server (when I start my own server in development process, instead of using apache) file uploads doesn’t work
How to get image size before uploading server ?
If you’re using destinationType: destinationType.FILE_URI your picture will be in your device’s filesystem. You only need to use File plugin to handle the file. I’m not sure if File plugin’s api allows you to see the size without opening the file.
Hi, thanx for the tutorial but I wanted to ask, how can I upload a file locally, so that I can even view it even if I’m offline, just like whatsapp where you can view images even if you are online
Thanks for tutorial, I found some simple & useful article for uploading images to php server using phonegap file transfer plugin http://phonegappro.com/tutorials/upload-images-to-server-using-phonegap-file-transfer-plugin/
How to send fixed size for an image to upload?
Dear Gonzalo, thank you for your post. This is helpful. Though, I am in trouble. Could you help me? I am using some APIs (Ushahidi), and for an image upload the API call requires that data is sent with base 64 encoding. I was trying to using FormData but then I realized that for some reason, this not working with PhoneGap. As the server side requires this type of file transfer, and this step is very much needed for the next API call in my code, do you have some advice to make the two work together? Is there any trick I could use? Thank you very much for your time.
I want to take picture from cam and send it to some other folder within the application ,
but it allows only to store in the cache.but not allowing to move the captured image to the new folder created by me , can you help me move the captured image from cordova app to some other folder within the new application only .
Note : I don’t want to use the existing gallery of the phone ,
I want the image to be stored in my own application folder.