Can Meteor create iOS app that takes pictures and uploads them to a server?


#1

I’m kinda stuck.
I love meteor and have been using it for a few weeks now.
it is truly amazing and the great work of all the contributors.
but, i’ve spent the entire weekend trying to create an iOS app that simply use the camera to take a picture and then upload it to a server.
I could not imagine i will get stuck with such a simple task, but after searching and searching no solution seem to work.
if someone direct me to a working minimal example of this action it will be so great.
right now I’m really considering going to other directions, which is a bummer after the last few weeks of hard work.


#2

Yes, you’re absolutely right, it’s a shame that Meteor does not support such a standard feature as a simple file upload to the server in its standard feature set. But there are community-driven packages that support this.

The most well-known is probably the CollectionFS set of packages, but I cannot really recommend it for mobile apps, as it’s still under development, has some bugs and did not work very well for me.

I ended up with using edgee:slingshot in combination with an AWS S3 bucket as a backend. This solution has the advantage that the data is directly uploaded to S3 from the device, so there is no load on your Meteor application server.

If you prefer to upload the files to your server instead, there’s also the Meteor Uploads packages collection: https://github.com/tomitrescak/meteor-uploads

I haven’t tried this myself, but it looks promising and also supports Cordova.


#3

Thanks @waldgeist, I’ll have a deeper look in it.
I actually decided to give Meteor another 10 days and log the development activity categorising working hours as “coding” and “platform fighting”.
after the analysis I might take hard decisions such as abandoning Meteor for this specific project.
I must flash out again that I absolutely love Meteor, it is an amazing reactive, modern and active platform, but it’s important to know what one should use it for and what not.


#4

I used collectionFS, and used own iOS App to accomplish file upload/download(include take pictures).

You can use Cordova to get same results.

On collectionFS git site, they have samples for file download/upload, pls take a look at.

If you are new to Meteor, then it will take you certain time to get this things done.

For collectionFS, right now it works for me , however it has a unsolved bug listed in my other post, i.e. doesn’t work with CDN.


#5

And what was the problem - upload itself, or getting access to local saved files ?
Cause for upload there are many popular packages like CFS environment, slingshot
Or now there is meteor-uploads as a new package.

But I remember discussion about accessing local files problems and meteor being bound to it’s own file serving service on mobile…


#6

In fact, @davidsun, I believe that my problem originated from cordova:cordova-plugin-media-capture and the way it handles iOS 9.1.
but, above the details, my problem is somewhat conceptual:
the platform looks amazing, you’re developing ahead and then you hit a brick wall.
now, if it was something esoteric, it would be acceptable, but if a platform introduces itself as ‘good for everything’ i’d expect trivial features to be core features.
anyways, in my case I think that collectionFS is working fine, as it creates a file on the local storage, but it’s a zero bytes size file.
i suspect the cordova:cordova-plugin-media-capture to be the problematic since when the app loads the camera view I see this message in the log:
Snapshotting a view that has not been rendered results in an empty snapshot. Ensure your view has been rendered at least once before snapshotting or snapshot after screen updates.

so, again, I suspect the the cordova capture plugin is the origin of my problem.
@shock, thanks for joining this conversation.

by the way, I will be so happy to understand I did something wrong and there’s a better way to do it.
no ego, only a desire to get things done :smile:


#7

My biggest problem with CFS was that it did not process the data I got from the camera. I remember I had to convert the data to blobs first, which worked fine with slingshot, but CFS did not accept this kind of data. And I was not able to give it a pure File object, as this is not what you get from the device camera.


#8

This sounds like the same problems I had with CollectionFS. As far as I remember, I could track this down to the point where I saw that it created a meta data record for my file, but it did not store the actual content (I used GridFS as a backend). It seemed as if it did not accept the blob I sent to it.


#9

right @waldgeist, this is my exact problem.


#10

Another vote for Slingshot.

CollectionFS make it very clear that it’s not for production, so I’m not sure why it ever shows up as a recommendation (and it frequently does). I gave it a shot and didn’t get very far with it.

Slingshot on the other hand is more stable and works great :thumbsup: For remote storage it should be the default recommendation.


#11

I’ll give it a try today. thanks @natanhornby


#12

Slingshot worked for me as well, but would like to be able to modify the image before it loads to S3 (primarily to reduce size). Did you upload the full size image or is there something you can do to resize before sending to S3?


#13

My personal use-case was that I was allowing users to upload an Avatar. So I used the jquery jCrop plugin to first allow them to crop the image, and then upload it, so the only thing that leaves the client is a small, pre-cropped image.

If your use-case is similar then this thread contains pretty much everything you need: Avatar uploads with Meteor

(Credit to @firegoby!)


Good luck @kikass !


#14

@nathanhornby: I used it for the very same use case, but I wasn’t aware of this forum thread, so I built my local avatar cropping solution a bit differently. :smile:

It is now based on jquery cropper and load-image, which can be imported using these packages: jonblum:jquery-cropper and blueimp:javascript-load-image.

The jquery-cropper offered a much more intuitive UI than jCrop, so I preferred this one.


#15

I’ll have to check it out - if you’ve got an example of it in action id love to see it!


#16

Thanks! Will try that.


#17

@kikass to nail down to the root cause of the problem. Try upload files in photo library, if that works, then the problem is related to cordova:cordova-plugin-media-capture. If upload files failed, then the problem most likely resides on your code or server configuration(i.e. permission).

I haven’t try other approaches, such as slingshot, due to time constrains, and other things. Would like to know your venture results, as very soon I may replace CFS with others due to CDN bug… Please let us know your progress.


#18

thanks @davidsun, this thread seem to be super useful!
i’m regaining my trust in Meteor.
just had a couple of days doing annoying no-dev stuff.
now I’m back, will update regarding my status later on.


Cfs:filesystem upload from ios to server result in zero bytes file
#19

ok guys, i got this one sorted out!
for some strange reason I decided to cling to the packages already installed and wasted so much time on and finally i made it.

here’s a naive implementation:

I used mdg:camera for the camera part and cfs:standard-packages + cfs:filesystem for the upload part.

here’s my template (addEvent.html)
`

Take a photo

submit
`

skipping any css here…

cfs collection must be defined both on client and server:

Images = new FS.Collection("images", { stores: [new FS.Store.FileSystem("images", {path: "~/Documents/dev/chain/.uploads"})]});

add upload permissions on server side:

Images.allow({ 'insert': function () { return true; } });

now, here’s where the little bastard’s sorted out - on a client .js file:

1st - add touch handler on the “take a photo” UI element, the MeteorCamera returns a dataURI, so I store it in a Session var:

Template.addEvent.events({ 'touchstart .clickMeTitle': function(event) { MeteorCamera.getPicture({}, function(error, data) { Session.set('photo', data); }); } });

2nd, add handler to the submit button it read the data from the Session var and convert it to a file object using a function (explained later) so my Template.addEvent.events looks like this now:

Template.addEvent.events({ 'touchstart .clickMeTitle': function(event) { MeteorCamera.getPicture({}, function(error, data) { Session.set('photo', data); }); }, 'touchstart .go': function() { var file = dataURItoFile(Session.get('photo'), 'pic.jpg'); Images.insert(file, function(err, fileObj) {}); } });

and it works!
apparently it was my problem of converting the data correctly, i will check the cordova plug later when I catch up with my dev plan (maybe :smile: )

here’s the dataURI to File converter split into 2 steps for modularity reasons.
and also because all the examples I found handled 2 step at a time…

the function called in my code above is dataURItoFile.
it calls a function for each step
step 1 - convert from dataURI to blob.
step 2 - convert from blob to file

dataURItoFile = function(dataURI, fileName) { var blob = dataURItoBlob(dataURI); var file = blobToFile(blob, fileName); return file; }

dataURItoBlob:

dataURItoBlob = function(dataURI) { var byteString = atob(dataURI.split(',')[1]); var ab = new ArrayBuffer(byteString.length); var ia = new Uint8Array(ab); for (var i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } return new Blob([ab], { type: 'image/jpeg' }); }

and blobToFile which does the minimum required to turn the blob to a proper file object:

blobToFile = function(blob, fileName) { blob.lastModifiedDate = new Date(); blob.name = fileName; return blob; }

a tiny optimisation here, the fileName argument throughout the function calling is pretty much unnecessary since the Images.insert renames the files according to the _id given to the db entry.

that’s it, hope this will save someone else the headache I went through.
thanks to everybody who took part in this thread, it shows how active and reliable this community and platform is.


#20

Thanks @kikass! But I have error file name in server is : images-fs278EnQYjxLB2YNX-undefined