Ionic Camera使用FILE_URI上传S3时文件损坏问题求助
Hey there, let's break down why your photos are getting corrupted when using FILE_URI and how to fix it. I've run into this exact issue before, so I know the frustration!
Why This Happens
When you set destinationType: FILE_URI, the Camera plugin returns a local file path (like file:///storage/emulated/0/Android/data/com.your.app/cache/IMG_1234.jpg) instead of the actual image data. If you try to upload this path string directly to S3, you're just sending the text of the path—not the binary image file. That's why your uploads are only ~100B and corrupted.
DATA_URL works because it returns the image as a base64-encoded string, which is the actual image content that S3 can parse.
Step-by-Step Fix
To make FILE_URI work, you need to read the actual file content from that local URI using the cordova-plugin-file plugin, then upload the binary data to S3. Here's how to do it:
1. Install the File Plugin
First, add the Cordova File plugin to your project:
cordova plugin add cordova-plugin-file
2. Update Your Code to Read and Upload the File
Replace your existing camera/upload code with this. It reads the file from the FILE_URI path, converts it to a Blob, and prepares it for S3 upload:
import { Camera, CameraOptions } from '@ionic-native/camera'; import { File } from '@ionic-native/file'; import { HttpClient } from '@angular/common/http'; // Inject these in your component's constructor constructor( private camera: Camera, private file: File, private http: HttpClient ) {} async takePhotoAndUploadToS3() { const cameraOptions: CameraOptions = { quality: 80, destinationType: this.camera.DestinationType.FILE_URI, encodingType: this.camera.EncodingType.JPEG, mediaType: this.camera.MediaType.PICTURE, correctOrientation: true // Optional: fixes rotated photos }; try { // Get the file URI from the camera const fileUri = await this.camera.getPicture(cameraOptions); // Resolve the URI to a file entry const fileEntry = await this.file.resolveLocalFileSystemURL(fileUri); // Get the file object from the entry const file = await new Promise<File>((resolve, reject) => { fileEntry.file(resolve, reject); }); // Read the file as an ArrayBuffer (binary data) const fileBuffer = await new Promise<ArrayBuffer>((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result as ArrayBuffer); reader.onerror = reject; reader.readAsArrayBuffer(file); }); // Convert the buffer to a Blob for upload const blob = new Blob([fileBuffer], { type: file.type }); // Create FormData (S3 usually accepts multipart/form-data uploads) const formData = new FormData(); formData.append('file', blob, `photo-${Date.now()}.jpg`); // Add a unique filename // Upload to S3 (replace with your S3 pre-signed URL or upload endpoint) const uploadResponse = await this.http.put( 'https://your-s3-bucket.s3.amazonaws.com/your-path', formData, { headers: { 'Content-Type': 'multipart/form-data' } } ).toPromise(); console.log('Upload successful!', uploadResponse); } catch (error) { console.error('Error during photo/upload:', error); } }
3. Key Notes to Avoid Issues
- Permissions: Make sure your app has the necessary file access permissions. For Android, add these to
config.xml:
For iOS, add these to<platform name="android"> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> </platform>config.xmlto request photo library access:<platform name="ios"> <config-file parent="NSPhotoLibraryUsageDescription" platform="ios" target="*-Info.plist"> <string>Need photo access to take and upload photos</string> </config-file> </platform> - Platform Compatibility: The
resolveLocalFileSystemURLmethod handles both Android'scontent://URIs and iOS'sfile://URIs, so you don't need to write platform-specific path conversion code. - S3 Upload Requirements: If you're using a pre-signed URL for S3, make sure the HTTP method (PUT/POST) matches what the pre-signed URL expects. Also, verify that the Content-Type header matches the image's MIME type (like
image/jpeg).
Why Not Just Use DATA_URL?
While DATA_URL works, it's not ideal for large photos because base64 encoding increases the file size by ~30%. Using FILE_URI with binary uploads is more efficient, especially for high-resolution images.
Let me know if you run into any kinks with this setup—I’m happy to help troubleshoot further!
内容的提问来源于stack exchange,提问作者Dean or Din

