What's the best way to upload a user selected image with maximum quality?

We have a capacitor app that allows the user to upload a profile picture. The problem is that if the image is too large, uploading fails. I’ve read the paragraph in the Http API documentation about large files: The solution helps for android, but not for iOS.

My question: what’s the best way to upload a user selected image from the app?

In my testing so far, anything above 1.5MB fails (roughly, not consistent)?

We can use the camera API and set maximum width and height and quality, which is great! Although this does not guarantee a specific file size.

How can we get the best maximum quality image upload without going over the limits?

Context:
After selecting an image, we allow the user to further crop the image. We currently do this frontend, which fails also sometimes because of memory constraints. And we can move this to the backend, but the point is: we want the original file upload to be as high quality as possible, so that the crop is also still of good quality.

Native support timeline?
the Http API mentions file upload support coming at some point. Does anyone know estimated timeline for this?

Cordova plugin?
Also I found a cordova plugin that seems to allow large files. I don’t think we can just use this plugin in a Capacitor project can we?
(This is our first project with Capacitor and we’ve never used ionic/cordova yet)

@flyon regarding cordova plugin,

in capacitor project it’s okay to mix capacitor plugins with cordova plugins, “If you can find a Capacitor plugin that does what you want, prioritize that”.

Before I asked What is the difference between capasitor plugins & ionic native pluginss and got good answer from @rapropos.

When using pluigns capacitor/cordova it’s good to check when last commit was done, and it seems like cordova-plugin-file-transfer not actively maintained. Sometimes plugins need migrations, for example when capacitor 5 was released it required plugin developers to migrate their plugins to capacitor 5. Capcitor 5 comes with benefits though.

@flyon regarding “uploading fails”

  1. Is it crashing the app?
  2. Is your backend returning error?
  3. are you uploading image as base64, setting android:largeHeap="true" basically means hey android give my app more heap space and andoird be like “Ok I will try, but I can’t promise”?

Because the project (angular/capacitorjs) I’m currently working we upload short videos. We did testing and some iOS devices could upload 30-40MBs and Android up to 60MBs. As a result we just set MAX_UPLOAD_SIZE to 30MB on client side.

@sultanmyrza thanks for the info! We might try the cordova plugin, but only if needed. Very interesting that you are able to upload 30MB! What sort of request do you use for that? A Http POST request with the Capacitor Http plugin? How is the data formatted?

are you uploading image as base64

Yes, I tried both a base64 string and I tried a FormData. Both work on web and android but fail on iOS.

are you setting android:largeHeap=“true”

Yes we did this. On Android no issues currently. But on iOS a 2MB file fails as described below

Is it crashing the app? / is you backend returning error?

No for both questions. It silently refuses to make a HTTP request. The javascript code that executes fetch is called. The Capacitor Http plugin logs the request:

But then nothing else happens. The backend never receives the request. And even more strange, the catch() and then() clauses are never called. No error. Nothing.

@flyon okay thank you for information, I will try to create simple ionic/capacitor project and try to reproduce your issue on iOS.

great thanks. FYI, we’re just using capacitor. Nothing is imported related to ionic.

I don’t know about the interiors of the HTTP API, however I’m fairly familiar with the native fetch API. When uploading a file as a POST value the size is limited. However when sending it in the body of the request, large files can be uploaded without issues. Try this code:

            fetch('your-server-side-script', {
                method: 'POST',
                body: image_to_be_uploaded
            }).then(response => {
                return response.text()
            }).then(text => {
                console.log(text);
                // do anything you like with the response
            });

@Sempervivum, yes that’s exactly what we’re doing. Sending a large string (base64 image) as the body of a fetch POST request.

It fails as described, both when just using plain fetch as well as when using the HTTP plugin, which patches fetch to use native libraries instead.

Would you mind to post the code that does this?
And the output in the network tab of the developer tools.
However, there might be restrictions on iOS I don’t know about.

From experience, you are better off using the Cordova file transfer plugin.
We are using this fork since it fixes some iOS issues → GitHub - sitewaerts/cordova-plugin-file-transfer: Apache Cordova Plugin file-transfer on a production app with ~10M uploads per year (photo, audio, video files).

Everything else we tried fails one way or the other.