Search code examples
androidionic-frameworkcameraandroid-cameracordova-plugins

IONIC camera plugin FILE_URI returning different file path format based on selected file type (video/picture)


I have a problem where the uri returned is in the format:

"content://com.android.providers.media.documents/document/image%3A18112"

instead of:

"/storage/emulated/0/WhatsApp/Media/WhatsApp Animated Gifs/VID-20191026-WA0003.mp4"

This seems to only be a problem when selecting a picture from the gallery. With video files it is the correct format. my version for the plugin is:

"@ionic-native/camera": "^5.15.1"

"cordova-plugin-camera": "^4.1.0"

Which are the latest versions for as far as I know. I am testing on a samsung galaxy S8.

My code is below:

import { Injectable } from '@angular/core';
import { CameraOptions, Camera, MediaType } from '@ionic-native/camera/ngx';
import { CameraProviderResponse } from '../objects/cameraProviderResponse';

@Injectable()
export class CameraProvider {

    constructor(public camera: Camera) {

    }

    openCamera(selectedMediaType: MediaType, allowedMediaType: MediaType): Promise<CameraProviderResponse> {
        const options: CameraOptions = {
            sourceType: this.camera.PictureSourceType.SAVEDPHOTOALBUM,
            destinationType: this.camera.DestinationType.FILE_URI,
            mediaType: selectedMediaType
        };
        return this.camera.getPicture(options).then((mediaPath) => {
            let re = /(?:\.([^.]+))?$/;
            let fileExtension = re.exec(mediaPath)[0];
            let mediaType;
            if (fileExtension === '.jpeg' || fileExtension === '.jpg' || fileExtension === '.png' || fileExtension === '.gif' && (allowedMediaType === MediaType.ALLMEDIA || allowedMediaType === MediaType.PICTURE)) {
                mediaType = MediaType.PICTURE;
            }
            else if (fileExtension === '.mp4' && (allowedMediaType === MediaType.ALLMEDIA || allowedMediaType === MediaType.PICTURE)) {
                mediaType = MediaType.VIDEO;
            }
            else {
                return this.openCameraFailed();
            }
            return {
                success: true,
                mediaPath: mediaPath,
                mediaType: mediaType,
                fileExtension: fileExtension

            };
        }, error => {
            return this.openCameraFailed();
        }).catch(error => {
            console.log(error);
            return this.openCameraFailed();
        });
    }

    openCameraFailed(): CameraProviderResponse {
        return {
            success: false
        };
    }
}

If you need more information. Please ask.


Solution

  • I currently fixed it like this:

    import { Injectable } from '@angular/core';
    import { CameraOptions, Camera, MediaType } from '@ionic-native/camera/ngx';
    import { CameraProviderResponse } from '../objects/cameraProviderResponse';
    import { FilePath } from '@ionic-native/file-path/ngx';
    //bug: temp fix stack overflow post: https://stackoverflow.com/questions/58581038/ionic-camera-plugin-file-uri-returning-wrong-filepath?noredirect=1#comment103477183_58581038
    @Injectable()
    export class CameraProvider {
    
      constructor(public camera: Camera, public filePath: FilePath) {
    
      }
    
      openCamera(selectedMediaType: MediaType, allowedMediaType: MediaType): Promise<CameraProviderResponse> {
        const options: CameraOptions = {
          sourceType: this.camera.PictureSourceType.SAVEDPHOTOALBUM,
          destinationType: this.camera.DestinationType.FILE_URI,
          mediaType: selectedMediaType
        };
        return this.camera.getPicture(options).then((mediaPath) => {      
          let fileExtension = this.getFileExtension(mediaPath);
          if(this.getMediaType(fileExtension) === null) {
            return this.filePath.resolveNativePath(mediaPath)
            .then(path => {
              return this.getCameraProviderResponse(allowedMediaType, path);
            })
            .catch(err => {
              console.log(err);
              return this.openCameraFailed();          
            });
          }
          else {
            return this.getCameraProviderResponse(allowedMediaType, mediaPath);
          }
        }, error => {
          return this.openCameraFailed();
        }).catch(error => {
          console.log(error);
          return this.openCameraFailed();
        });
      }
    
      getCameraProviderResponse(allowedMediaType: MediaType, path:string) {
        let fileExtension = this.getFileExtension(path);
        let mediaType = this.getMediaType(fileExtension);
         if(mediaType === null) {
           return this.openCameraFailed();
         }
          return {
            success: true,
            mediaPath: path,
            mediaType: mediaType,
            fileExtension: fileExtension
    
          };
      }
    
      //fix for android
      getFileExtension(path: string) {
        let re = /(?:\.([^.]+))?$/;
        return re.exec(path)[0];
      }
      //fix for android
      getMediaType(fileExtension: string) {
        if (fileExtension === '.jpeg' || fileExtension === '.jpg' || fileExtension === '.png' || fileExtension === '.gif') {
          return MediaType.PICTURE;
        }
        else if (fileExtension === '.mp4') {
          return MediaType.VIDEO;
        }
        else return null;
      }
    
      openCameraFailed(): CameraProviderResponse {
        return {
          success: false
        };
      }
    }
    

    It feels a bit hacky but it does the trick for now. Buying me some time to take a closer look at the issue. If I find a better solution I'll post it here as well! In the meantime. If anyone else finds a better solution to this problem, please post it here!