Skip to main content

Hello,

 

 I have a LWC launched from a quick action on the Service Appointment Object which allows you to select photos (and take photos) (with Lightning-input type="File" ) from the mobile device, choose a category and then load the files against the Service Appointment. This was inspired by the followed article using the "createcontentDocumentAndVersion()" method:

 

 https://developer.salesforce.com/docs/atlas.en-us.mobile_offline.meta/mobile_offline/use_images_upload_while_offline_example.htm?_ga=2.13362482.444796757.1718292871-1251538021.1718292871

 

Basically in my code when pictures are selected (or a photo taken), I loop through the selected pictures and add them to an array, which allows the user to click the "Upload file" buttons multiple times and save the pictures in one shot at the end.

 

Now, this works perfectly fine on iPhones but not on Android where the following error is randomly thrown when calling the createContentDocumentAndVersion method:

 

"notreadablerror : the requested file could not be read typically due to permission problems"

 

We have found a pattern in our test scenarios where it looks like when we are mixing "Choosing from the Library" and "Taking a Picture". But it's not always occuring. 

 

My question is why does this work perfectly on an iPhone but not on Android? Is there a limitation on android using the lightning-Input and / or createContentDOcumentAndVersion method?

 

Here's my js code as a reference (sorry my tabbing is all screwed when pasting):

 

// fileUpload.js

import { LightningElement, api, track, wire } from "lwc";

import { ShowToastEvent } from "lightning/platformShowToastEvent";

import { createContentDocumentAndVersion, createRecord} from "lightning/uiRecordApi";

import { processImage } from 'lightning/mediaUtils';

 

// Imports for forced-prime ObjectInfo metadata work-around

import { getObjectInfos } from "lightning/uiObjectInfoApi";

import CONTENT_DOCUMENT from "@salesforce/schema/ContentDocument";

import CONTENT_VERSION from "@salesforce/schema/ContentVersion";

import CONTENT_DOCUMENT_LINK from "@salesforce/schema/ContentDocumentLink";

 

export default class FileUpload extends LightningElement {

@api

recordId;

@track

uploadingFile = false;

 

@track

errorMessage = "";

 

connectedCallback() {

        this.filesArray = [];

 }

@wire(getObjectInfos, {

       objectApiNames: [ CONTENT_DOCUMENT, CONTENT_VERSION, CONTENT_DOCUMENT_LINK ],

})

objectMetadata;

@track

filesArray = [];

// Input handlers

handleFilesInputChange(event) {

     const filesInput = event.detail.files;

    if (filesInput) {

        for (let i = 0; i < filesInput.length; i++) {

              const currentFile = filesInput[i];

              console.log('++currentFile ' + JSON.stringify(currentFile));

              let fileProperty = {

                "filename" : currentFile.name,

                "title" : currentFile.name ,

                "description" : "",

                "pictureCategory" : "NONE",

                "fileData" : currentFile,

                "imageSrc" :  URL.createObjectURL(currentFile)

        }

         this.filesArray.push(fileProperty);

       }

       console.log('++ARRAY' + JSON.stringify(this.filesArray));

    }

}

 

handlePictureCategoryChange(event) {

        this.filesArray[event.target.dataset.index].pictureCategory = event.detail.value;

 }

 

removeEntry(event) {

      this.filesArray.splice(event.target.dataset.index, 1);

}

 

// Restore UI to default state

resetInputs() {

      this.filesArray = [];

      this.errorMessage = "";

}

 

// Handle uploading a file, initiated by user clicking Upload button

async handleUploadClick() {

 

// Make sure we're not already uploading something

if (this.uploadingFile) {

     return;

}

 

// Make sure we have something to upload

if (this.filesArray.length == 0) {

      return;

}

 

try {

     this.uploadingFile = true;

 

     for (let i = 0; i < this.filesArray.length; i++) {

          const currentFile = this.filesArray[i];

          let formattedDescription = currentFile.description;

          if (currentFile.pictureCategory) {

              formattedDescription += '\n';

             formattedDescription += '[{' + currentFile.pictureCategory + '}]';

         }

       // Create a ContentDocument and related ContentDocumentVersion for the file

        const contentDocumentAndVersion =

             await createContentDocumentAndVersion({

                 title: currentFile.title,

               description: formattedDescription ,

              fileData: currentFile.fileData

        });

      // If component is run in a record context (recordId is set), relate

      // the uploaded file to that record

 

      if (this.recordId) {

         const contentDocumentId = contentDocumentAndVersion.contentDocument.id;

         await this.createContentDocumentLink(this.recordId, contentDocumentId);

      }

}

 

// Status and state updates

console.log("++File upload created and enqueued.");

this.notifySuccess();

this.resetInputs();

} catch (error) {

console.error('++ERROR ' + error );

this.errorMessage = error ;

} finally {

this.uploadingFile = false;

}

}

 

readFile(file) {

return new Promise((resolve, reject) => {

 

  const reader = new FileReader();

  reader.onloadend = (ev) => {

resolve(ev.target.result);

  };

  reader.onerror = () => {

reject(

  `There was an error reading file: '${file.name}', error: ${reader.error}`

);

  };

  try {

reader.readAsDataURL(file);

  } catch (err) {

reject(new Error('Cannot to read the input data from file: ' + file.name + ' ' + err ));

  }

});

  }

 

dataURLtoFile(dataUrl, fileName) {

let fileBlob = this.dataURLtoBlob(dataUrl);

return new File([fileBlob], fileName, {

  type: fileBlob.type,

  lastModified: new Date().getTime()

});

  }

 

dataURLtoBlob(dataURL) {

let arr = dataURL.split(",");

let mime = arr[0].match(/:(.*?);/)[1];

let bstr = window.atob(arr[1]);

let n = bstr.length;

let u8arr = new Uint8Array(n);

while (n--) {

  u8arr[n] = bstr.charCodeAt(n);

}

return new Blob([u8arr], { type: mime });

  }

 

// Create link between new file upload and target record

async createContentDocumentLink(recordId, contentDocumentId) {

await createRecord({

apiName: "ContentDocumentLink",

fields: {

LinkedEntityId: recordId,

ContentDocumentId: contentDocumentId,

ShareType: "V",

},

});

console.log("ContentDocumentLink record created.");

}

 

notifySuccess() {

this.dispatchEvent(

new ShowToastEvent({

title: "Upload Successful",

message: "File enqueued for upload.",

variant: "success",

})

);

}

 

    get pictureCategoryOptions() {

        return [

{ label: 'None', value: 'NONE' },

            { label: 'Appliance', value: 'APPL' },

            { label: 'Caution Tag', value: 'CAUT' },

            { label: 'Meter', value: 'MTR' }

        ];

    }

 

}

3 respostas
  1. 9 de jul. de 2025, 17:10

    Does anyone know the resolution to this? 

0/9000