Upload Multiple Files to S3 Using FileInput in Mobile

  1. My goal: I am trying to upload files to S3 using the FileInput component in the mobile application.
  2. Issue: The issue is exactly the same as this: Upload images to S3 from Mobile Input if I upload a file from a computer, it works fine and I can see the original file in S3. However, when I do the same thing from the mobile application using the same component and logic, I see a .txt file in S3 instead of the original file. The .txt file contains the Base64 file data.
  3. Steps I've taken to troubleshoot: I tried different methods and approaches from the Retool forum, but none of them worked.
  4. Additional info: This is on Retool Cloud, and here is some code and screenshots.
// prepareFiles js
const files = fileInput.files || [];

const processedFiles = await Promise.all(
  files.map(async (f) => {
    const dataUrl = await utils.getDataByObjectURL(f.uri);
    const base64Data = dataUrl.split(",")[1];

    return {
      fileData: base64Data,
      fileType: f.type,
      fileName: `user_${Date.now()}_${f.name.replace(/\s+/g, "_")}`
    };
  })
);

// Store in variable instead of additionalScope
uploadQueue.setValue(processedFiles);
// startUpload js
// Reset index
currentUploadIndex.setValue(0);

for (let i = 0; i < uploadQueue.value.length; i++) {
  currentUploadIndex.setValue(i);

  // Trigger S3 query (no additionalScope needed)
  await s3Upload.trigger();
}

// Clear queue after success
uploadQueue.setValue([]);
utils.showNotification({
  title: "Upload complete",
  type: "success"
});

// submit
await prepareFiles.trigger();
await startUpload.trigger();

Offline mode is also enabled for this query, as it is marked as an offline write.

Hi @chirag_kalsariya,

At a quick glance, it might be worth trying to store the files in local storage instead of a variable (per this workaround Offline Image Uploads with Local Storage and JavaScript)

But I'll follow up after I've done some testing!

Right now, I am not focusing on offline mode, but the file upload is not working in online mode either.

Here is a simple code example:

const files = FileInput.files || [];

await Promise.all(
  files.map(async (f) => {
    const dataUrl = await utils.getDataByObjectURL(f.uri);
    const [info, base64Data] = dataUrl.split(",");

    return onlineS3Upload.trigger({
      additionalScope: {
        fileDataInfo: info,
        fileData: base64Data,
        fileType: f.type,
        fileName: `user_${Date.now()}_${f.name.replace(/\s+/g, "_")}`,
      },
    });
  })
);

I am able to get all the files from the input, convert them to Base64, and trigger the S3 upload using additionalScope. and my s3 query look like this

This code works completely fine on the web. However, when I use it on Android, it does not work. I can see the Base64 data string stored in S3, but the uploaded file is not valid. Issue in android and ios both.

Same issue as this Upload images to S3 from Mobile Input - #8 by cedric.liike

I also tried using static values for the upload data to verify the behavior, but the file in S3 is still not working.

The values I tried were from a small text file containing β€œhello world”:

data:text/plain;base64,SGVsbG8gV29ybGQKSGVsbG8gV29ybGQKSGVsbG8gV29ybGQKSGVsbG8gV29ybGQKSGVsbG8gV29ybGQKSGVsbG8gV29ybGQKSGVsbG8gV29ybGQ= 
SGVsbG8gV29ybGQKSGVsbG8gV29ybGQKSGVsbG8gV29ybGQKSGVsbG8gV29ybGQKSGVsbG8gV29ybGQKSGVsbG8gV29ybGQKSGVsbG8gV29ybGQ= 
text/plain;base64,SGVsbG8gV29ybGQKSGVsbG8gV29ybGQKSGVsbG8gV29ybGQKSGVsbG8gV29ybGQKSGVsbG8gV29ybGQKSGVsbG8gV29ybGQKSGVsbG8gV29ybGQ= 

Hi @chirag_kalsariya,

Got it! Thanks so much for the simple repro steps. I'm seeing the same behavior. This appears to be a new Retool bug where the content-type isn't properly set when uploading from a mobile device. We should have a fix coming soon!

If you need a fix in the meantime, the following JS modification seems to be working for me (I tested with a simple text file):
fileData: retoolContext.platform ==='web' ? base64Data : f.uri,

However, once the fix goes live, this code will break. Once I see that the fix has shipped, I will post an update here