2
votes

I am using cordova-plugin-camera to access the camera in Android. This was working fine until I changed the Target SDK version to API 26: Android 8.0 (Oreo) in order to be able to upload to the Google play store which now requires this version or above.

The error I get is

file:///data/user/0/{mypackage}/cache/Capture.jpg exposed beyond app through ClipData.Item.getUri()

which I believe is due to a change in how apps can access the file system from Android Nougat - see android.os.FileUriExposedException: file:///storage/emulated/0/test.txt exposed beyond app through Intent.getData().

I have tried fixing the issue with different versions of cordova, cordova android and the camera plugin as per https://github.com/ionic-team/ng-cordova/issues/1381 but in each case as soon as I change the TargetSDK to 26 I get the same error on an Android 8 phone.

I have added the following to my AndroidManifest.xml file

            <provider android:authorities="com.okappy.okappy.provider" android:exported="false" android:grantUriPermissions="true" android:name="android.support.v4.content.FileProvider">
        <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/camera_provider_paths" />
    </provider>

And I have checked that I have a camera_provider_paths.xml with the following

    <paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>

I have also tried editing the following lines in cordova/camera/CordovaURI.java to forcibly ignore the fileUri but it made no difference

    public Uri getCorrectUri()
{
    /*if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
        return androidUri;
    else
        return fileUri;
    */
    return androidUri;

}

I have the following versions

  • 8.1.2 ([email protected])

  • android 7.1.2

  • cordova-plugin-camera 4.0.3

  • cordova-plugin-console 1.0.3
  • cordova-plugin-file 6.0.1

I am using Compile SDK version 28.0.3, MinumumSDK version of 21 and TargetSDK version of 26.

Thanks in advance for your help

1

1 Answers

2
votes

The issue is with our code rather than the plugin - view issue on github

We were using the following code

function captureImage() {
    navigator.device.capture.captureImage(captureImageSuccess, captureImageError, {limit: 1});
}

function captureImageSuccess(mediaFiles) {
    uploadFile(mediaFiles[0]);
}

function uploadFile(mediaFile,fileType) { //#F333
    var win = function (r) {
}

var options = new FileUploadOptions();
    ImageURL=mediaFile.fullPath;
    options.fileName = (fileType)? mediaFile.name : mediaFile.file; //#F333
    options.mimeType = "multipart/form-data";
    var params = new Object();
    params.fileName = 'AndroidPhoneUpload';
    params.imageType = (fileType)?fileType:'Picture';   //#F333
    var printName = prompt("Add a title","");  //#F644
    if (printName){
        params.printedName = printName;
    }
    window.resolveLocalFileSystemURL(ImageURL, function(fileEntry) {
        fileEntry.file(function(fileObj) {
            params.fileSize = ""+fileObj.size;
        });
    });
    options.params = params;
    var ft = new FileTransfer();
    ft.upload(ImageURL, encodeURI("uploadURL"),win,fail,options);
}

We've replaced the captureImage function with the following addImage function

function setOptions(srcType) {
    var options = {
        quality: 50,
        limit: 1,
        destinationType: Camera.DestinationType.FILE_URI,
        // In this app, dynamically set the picture source, Camera or photo gallery
        sourceType: srcType,
        encodingType: Camera.EncodingType.JPEG,
        mediaType: Camera.MediaType.PICTURE,
        allowEdit: false,
        correctOrientation: true  
    }
    return options;
}

function addImage() {

  var srcType = Camera.PictureSourceType.CAMERA;
  var options = setOptions(srcType);

  navigator.camera.getPicture(function cameraSuccess(imageUri) {
        var options = new FileUploadOptions();
        options.fileKey="file";

        options.fileName="test";
        options.mimeType="multipart/form-data";

        var params = new Object();
        params.fileName = 'AndroidPhoneUpload';
        params.imageType = 'Picture';
        var printName = prompt("Add a title","");
        if (printName){
            params.printedName = printName;
        }
        options.params = params;
        navigator.notification.alert("Your media is being uploaded.", null, "Add media");

        var ft = new FileTransfer();
        ft.upload(imageUri, encodeURI("uploadURL"), win, fail, options);

    }, function captureImageError(error) {
        console.debug("Unable to obtain picture: " + error, "app");
    }, options);
}

To further clarify, I believe the issue was because we were using the camera to capture the image, but then trying to upload the media file from storage which was causing the permissioning issues with the new version of Android.