Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iOS13 file_uri error picking video from gallery #506

Closed
3 tasks done
litiobat opened this issue Sep 22, 2019 · 47 comments · Fixed by #580
Closed
3 tasks done

iOS13 file_uri error picking video from gallery #506

litiobat opened this issue Sep 22, 2019 · 47 comments · Fixed by #580

Comments

@litiobat
Copy link

Bug Report

Problem

In iOS 13, picking video from Roll returns a bad FILE_URI no proprietary (only affected picking video, no photo)

What is expected to happen?

Return a valid proprietary FILE_URI url to work with it (for upload to server, for example)
like: file:///var/mobile/Containers/Data/Application/98D7C3AE-A24F-46CE-A3B4-CF03B26355BE/tmp/video.mp4

What does actually happen?

Returns a invalid non proprietary FILE_URI with no access to work with, like:
file:///private/var/mobile/Containers/Data/PluginKitPlugin/43792FA5-A8F8-4ECA-8CCE-0C5877088858/tmp/trim.7F9B8FC4-3307-4452-9F96-46A5D9A9DDD5.MOV

Information

Using any iOS device, like iPhone upgraded to iOS 13, try to pick a video (no photo) and then load the FILE_URI returned by plugin. If you'll try to use this FILE_URI to any action, like upload the file to server for example, the log in xcode says "Error opening file. Error Domain=NSCocoaErrorDomain Code=257. You are not allowed to read this file."
** Note: This function works correctly before upgrade to iOS13. I've tried it to many iOS devices with the same result.

Command or Code

var options = {
destinationType: 1,
sourceType : 0,
mediaType: 1
};
navigator.camera.getPicture(correcto, fail, options);

Environment, Platform, Device

MacOS Mojave, using Xcode 11 and iPhone Xs upgraded to iOS 13

Version information

Cordova 9, Camera Plugin upgraded today
MacOS Mojave, using Xcode 11 and iPhone Xs upgraded to iOS 13

Checklist

  • I searched for existing GitHub issues
  • I updated all Cordova tooling to most recent version
  • I included all the necessary information above
@litiobat
Copy link
Author

*** ADITIONAL INFO: I've found in Stack Overflow this information about this problem (to help you to solve it)

The problem was the image picker delegate passed the file's url to another class that then handled copying the file. This has worked fine for several years in our application but with iOS 13, once the image picker delegate goes away, the url immediately becomes invalid.

@litiobat
Copy link
Author

Hi again!
Here is the solution (sorry, I don't know how to open a new tree), to help any other user.

in CDVCamera.m change THIS:

  • (CDVPluginResult*)resultForVideo:(NSDictionary*)info
    {
    NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] absoluteString];
    return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:filePath];
    }

to THIS:

  • (CDVPluginResult*)resultForVideo:(NSDictionary*)info
    {
    NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] path];

    NSArray* spliteArray = [moviePath componentsSeparatedByString: @"/"];
    NSString* lastString = [spliteArray lastObject];
    NSError *error;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"tmp"];
    NSString *filePath = [documentsDirectory stringByAppendingPathComponent:lastString];
    [fileManager copyItemAtPath:moviePath toPath:filePath error:&error];

    return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:filePath];
    }

@markerio
Copy link

@litiobat This is the case now for iOS 13.

We've just upgraded our testing devices to iOS 13, and we found that we aren't able to select video files from the gallery camera roll. Your fix should be merged with the master branch.

Any clues? Many thanks
@jcesarmobile @shazron @timbru31 and to anybody who can help

@markerio
Copy link

markerio commented Sep 25, 2019

Attention!

If your app has video upload feature, then this issue will be one of the most important issues you will face when your app users start upgrading their iOS devices to v13. I believe that not all cordova developers have upgraded their testing devices yet, thats why this thread is not getting so much attention.

Thanks for @litiobat and for his efforts in helping the community solving this issue. Please read his description and the comment he added then after.

I have an app in production, which has video upload feature. I forked the master plugin and applied @litiobat's fix, for any of you guys interested in solving this issue, you can use this fork below:

<plugin spec="https://github.com/markerio/cordova-plugin-camera.git" source="git" />

I have to add that this didn't solely fix the issue for me, because the returned path is not prefixed with the file:// protocol, so please keep in mind that in the success callback check for the file protocol and fix that accordingly, as follows:

function onVideoSourceSuccess(fileURI) {
// fix
fileURI = fileURI.indexOf('file://')==0?fileURI:'file://'+fileURI;
// continue your code here
}

I believe applying this fix in the master plugin is better and safer for all, however some developers can't wait for the next release.

Wish the best for all.

@breautek
Copy link
Contributor

breautek commented Sep 25, 2019

Sounds like there are already some potential solutions here. We'd welcome any PRs. Cordova is a small team of volunteers.

@claudiozam
Copy link

Hi, same problem on IOS 13.

@rdcs
Copy link

rdcs commented Oct 10, 2019

Just wanted to add my 2 cents. I have seen this problem too, when I upgraded to IOS 13. I am using Xam.Plugin.Media to access movie files and in my code I was using System.IO.File.Move and that is where the exception occurs. In looking at my internal debug and crash log I saw that the exception is on System.IO.FileSystem.DeleteFile, which is accurate since a move will delete the source file. I used System.IO.File.Copy and there was no issue. The only problem may be, what happens to all the files in the private directory? Do they get deleted when the app closes? Not really sure. But, the bottom line is that you can access movies from the Photos using the picker.

@rdcs
Copy link

rdcs commented Oct 14, 2019 via email

@tmk1991
Copy link

tmk1991 commented Oct 19, 2019

The directory for videos simply changed. I parse the file uri response to add in file:/// if missing and to remove private if its in the path. However, the change seeps to be within the URL :

Videos Broken:
file:///private/var/mobile/Containers/Data/PluginKitPlugin/...

Photos work:
file:///var/mobile/Containers/Data/Application/...

Even if i switch to DATA_URL it still returns the path above on videos

@tmk1991
Copy link

tmk1991 commented Oct 19, 2019

After forking with @markerio 's suggestion, I found that my FILE_URI was still not being accepted. This time I was getting error code 5 - Encoding Err. :(

Now the URL is:
file:///var/mobile/Containers/Data/Application/6CDD6A9A-4694-40FF-A381-82DFB8AAC19E/tmp/trim.0932D2E4-2811-49EF-8D12-6FA86EFDCA34.MOV

This is what ended up working:
apache/cordova-plugin-file#346 (comment)

tmk1991 added a commit to TDTECHLINK/cordova-plugin-camera that referenced this issue Oct 19, 2019
@rituparnaGuha
Copy link

@litiobat Hi is this work for ios lower version like 12 or else?

@Taylorsuk
Copy link

@litiobat fix worked for me on selection of the video from library, however the issue remains when recording a video and then returning the path for viewing.

Weirdly I also have a broken Android app. See the URL differences between Android and iOS in the images below:

Has anyone else had a broken android version?

Android
Screenshot 2019-10-23 at 22 13 12

iOS
Screenshot 2019-10-23 at 21 34 51

@maxymczech
Copy link

You sir are a true intellectual! Thank you, very cool.

@gitdisrupt
Copy link

Hi again!
Here is the solution (sorry, I don't know how to open a new tree), to help any other user.

in CDVCamera.m change THIS:

  • (CDVPluginResult*)resultForVideo:(NSDictionary*)info
    {
    NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] absoluteString];
    return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:filePath];
    }

to THIS:

  • (CDVPluginResult*)resultForVideo:(NSDictionary*)info
    {
    NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] path];
    NSArray* spliteArray = [moviePath componentsSeparatedByString: @"/"];
    NSString* lastString = [spliteArray lastObject];
    NSError *error;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"tmp"];
    NSString *filePath = [documentsDirectory stringByAppendingPathComponent:lastString];
    [fileManager copyItemAtPath:moviePath toPath:filePath error:&error];
    return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:filePath];
    }

I can confirm that this fix worked for us for iOS 13.2.2.
We also tested this on an iPhone running iOS 12.4.1 for backward compatibility.
Both are working correctly with this fix.
I have not yet tested 13.2 or 13.1. Anyone?

@riddletd
Copy link

Hi again!
Here is the solution (sorry, I don't know how to open a new tree), to help any other user.
in CDVCamera.m change THIS:

  • (CDVPluginResult*)resultForVideo:(NSDictionary*)info
    {
    NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] absoluteString];
    return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:filePath];
    }

to THIS:

  • (CDVPluginResult*)resultForVideo:(NSDictionary*)info
    {
    NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] path];
    NSArray* spliteArray = [moviePath componentsSeparatedByString: @"/"];
    NSString* lastString = [spliteArray lastObject];
    NSError *error;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"tmp"];
    NSString *filePath = [documentsDirectory stringByAppendingPathComponent:lastString];
    [fileManager copyItemAtPath:moviePath toPath:filePath error:&error];
    return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:filePath];
    }

I can confirm that this fix worked for us for iOS 13.2.2.
We also tested this on an iPhone running iOS 12.4.1 for backward compatibility.
Both are working correctly with this fix.
I have not yet tested 13.2 or 13.1. Anyone?

This works for me. iOS 13.1.3

@neerajsaxena0711
Copy link

So I am having a "Upload Video from gallery" feature on my app. When I run it on iOS emulator, it works as expected. That is, I am able to choose a video file from the gallery, and then upload it.
However when I run the app on my iPhone, I am able to pick the file from the gallery and then I get error code - 1.

Here is my code -

My options are -

public options = {
allowEdit: true,
SAVEDPHOTOALBUM: true,
sourceType: this.camera.PictureSourceType.SAVEDPHOTOALBUM,
mediaType: this.camera.MediaType.VIDEO,
destinationType: this.camera.DestinationType.NATIVE_URI,
}

My getVideo function -

async openVideo() { try { await this.camera.getPicture(this.options).then((filreUri => { window.resolveLocalFileSystemURL(filreUri, FE => { FE.file(async file => { // this.presentToast("I have come here"); this.fileInfo = file; if (file.type == "video/mp4") { const FR = new FileReader(); FR.onloadend = ((res: any) => { let AF = res.target.result; this.blob = new Blob([new Uint8Array(AF)], { type: file.type }); console.log("Done"); }); FR.readAsArrayBuffer(file); } else { // } }); }, (error)=>{ console.log("error resolving file"+ error) }); })).catch((err) => { this.fileInfo = "" console.log("Inside err of camera.getpicture"); }); } catch (e) { } finally { // console.log( "Finally", JSON.stringify(this.fileInfo)); if (this.fileInfo != undefined) this.navCtrl.push('UpoadMediaPage', { "blob": this.blob}); } }

My code goes into - error resolving file - with error code - 1

I have tried the changes mentioned above by @markerio - changed my camera.h and camera.m files
and also solution provided by @litiobat.

Am I doing something wrong?
Kindly help.

@saurabh-dk
Copy link

Hi, can someone please give a sample code for video upload which is working? I have exactly same problem as @neerajsaxena0711 and @litiobat's solution and @markerio's fork did not work for me too. Same with @tmk1991's comment.
Thanks.

@markerio
Copy link

markerio commented Nov 24, 2019

@saurabhDuzumaki @neerajsaxena0711 Please find below the simplest implementation of picking a video from the camera roll in iOS13. Tested in all v13 releases including the latest v13.2.3.

First, please follow @litiobat fix and change CDVCamera.m file as suggested. I forked the master plugin and applied @litiobat's fix, here is the link for any of you guys interested in this fork:

<plugin spec="https://github.com/markerio/cordova-plugin-camera.git" source="git" />

Then, setup the plugin to retrieve a video from the device's gallery. The picker should be triggered as follows:

navigator.camera.getPicture(onSuccess, onFail, {
  saveToPhotoAlbum: false,
  correctOrientation: true,
  allowEdit: false,
  mediaType: Camera.MediaType.VIDEO,
  sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
  destinationType: Camera.DestinationType.FILE_URI
  });

The success callback should be as follows:

function onSuccess(fileURI) {
  // fix path for file:// protocol
  fileURI = (parseInt(fileURI.indexOf('file://'))==0)?fileURI:'file://'+fileURI;
  // resolve and locate file
  window.resolveLocalFileSystemURL(fileURI, function success(fileEntry) {
    // retrieve file entry
    fileEntry.file(function(fileObj) {
      // debug
      console.log(fileEntry.nativeURL);
      console.log(fileObj.localURL);
      console.log(fileObj.name);
      console.log(fileObj.size);
      // continue from here
      // ...
      // ...
    }, function(error) {
      console.log('file entry error');
      });
  }, function (error) {
    console.log('resolve error');
    });
  }

Please reply back if you find this helpful. Hope this helps.

@guillem-sopra
Copy link

guillem-sopra commented Nov 25, 2019

@markerio 's solution works. If you want to use the Promise you could do as follows:

fileUri = await navigator.camera.getPicture(options).then((fileURI) => {
    return fileURI.indexOf('file://') === -1 ? `file://${fileURI}` : fileURI;
});

@neerajsaxena0711
Copy link

Yes, I can confirm that @markerio 's solution is working on iOS 13.1.2. Tested on real device. Thanks a ton! Was scratching my head over this since a long time.
Another issue that I am facing is that, I am unable to play the chosen video file using the video tag.
The path that I receive is -

"cdvfile://localhost/temporary/trim.8AEDB9C9-6E4C-4F65-8029-D453842E91F6.MOV"
I even tried converting it to nativePath using entry.toURL(); method which gives me the path

"file:///Users/Neeraj-saxena/Library/Developer/CoreSimulator/Devices/9D5725F4-968E-4669-8EAF-CCC0971BE8AF/data/Containers/Data/Application/6A311514-1F0D-416B-8895-84F1EBE0F58C/tmp/trim.0032325E-5FD8-4B5B-9937-A478BD958F8C.MOV"

My video tag is - <video autoplay controls #myvideo>

@neerajsaxena0711
Copy link

neerajsaxena0711 commented Nov 29, 2019

Can anyone tell me how do I play the "chosen" video from the gallery? The URL that I get doesn't seem to work when embedded with the video tag. I have tried a lot of solutions like converting the URL to localURL, nativeURL, etc. But couldn't get the path right. Happening both on Android and iOS.

My File entry object is -

 {"name":"20191107_170431.mp4",
"localURL":"cdvfile://localhost/root/storage/07ED-F818/DCIM/Camera/20191107_170431.mp4",
"type":"video/mp4","lastModified":1573183466000,
"lastModifiedDate":1573183466000,
"size":15140263,"start":0,"end":15140263}

@tryhardest
Copy link

@Taylorsuk did you get it sorted on Android?

@Taylorsuk
Copy link

@tryhardest Afraid not. I elected to use standard HTML inputs in a round about way and took the opportunity to remove another Cordova plugin from my app.

@neerajsaxena0711
Copy link

@Taylorsuk What issue are you facing on android?

@neerajsaxena0711
Copy link

@litiobat @markerio

Can anyone tell me how do I play the "chosen" video from the gallery? The URL that I get doesn't seem to work when embedded with the video tag. I have tried a lot of solutions like converting the URL to localURL, nativeURL, etc. But couldn't get the path right. Happening both on Android and iOS.

My File entry object is -

{"name":"20191107_170431.mp4",
"localURL":"cdvfile://localhost/root/storage/07ED-F818/DCIM/Camera/20191107_170431.mp4",
"type":"video/mp4","lastModified":1573183466000,
"lastModifiedDate":1573183466000,
"size":15140263,"start":0,"end":15140263}

@Taylorsuk
Copy link

@neerajsaxena0711 I summarised all the issues in this here #506 (comment)

@breautek breautek added the has-pr label Dec 9, 2019
@paivaric
Copy link

Tks @markerio, it worked for me.

@wingo7
Copy link

wingo7 commented Jan 31, 2020

IOS: The same issue, when I want to copy file with File plugin or upload it to firebase storage I have an error, FIle not found. Received file path is: 'file:///private/var/mobile/Containers/Data/PluginKitPlugin/89C88915-49F8-4B74-83D0-011C8B617DD9/tmp/trim.654E18A8-8AE3-4D51-96BD-3FB1D990E77C.MOV'.
I can watch a video, I don't have any issues with that, the problem is only with upload/copy functions

@samuelfaj
Copy link

Thank GOD i found this!!!!

Thank you so much @neerajsaxena0711

@rricamar
Copy link

Does this mean that #533 is not necessary anymore? 🤔

@rricamar
Copy link

Does this mean that #533 is not necessary anymore? 🤔

Didn't see that issue mentioned was from UnityNativeGallery 😰

@gritsa
Copy link

gritsa commented Sep 29, 2020

Hi again!
Here is the solution (sorry, I don't know how to open a new tree), to help any other user.

in CDVCamera.m change THIS:

  • (CDVPluginResult*)resultForVideo:(NSDictionary*)info
    {
    NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] absoluteString];
    return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:filePath];
    }

to THIS:

  • (CDVPluginResult*)resultForVideo:(NSDictionary*)info
    {
    NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] path];
    NSArray* spliteArray = [moviePath componentsSeparatedByString: @"/"];
    NSString* lastString = [spliteArray lastObject];
    NSError *error;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"tmp"];
    NSString *filePath = [documentsDirectory stringByAppendingPathComponent:lastString];
    [fileManager copyItemAtPath:moviePath toPath:filePath error:&error];
    return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:filePath];
    }

THIS IS THE ONE THAT WORKED FOR ME!

I hope this is incorporated in the official plugin soon.

@TylerBrinks
Copy link

Are there plans to incorporate this change? While it works on a developer's environment, CI/CD processes build apps by way if install pods will revert manual changes to the non-working contained in the plugin's package.

@PegasusAwesome
Copy link

PegasusAwesome commented Nov 6, 2020

Hi all,

Just used the 5.0.1 version in my app, and this version has solved this problem for us.
Thanks a million!

@HassanALi128
Copy link

Hi all,

Just used the 5.0.1 version in my app, and this version has solved this problem for us.
Thanks a million!

this works for me. Thanks

@abhishek0196
Copy link

Hello everyone I tried the same method, I am still getting nil from

 NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] path];

Can anyone please help, I have all these three permissions related to camera in my info.plist

  • Privacy - Photo Library Usage Description
  • Privacy - Photo Library Additions Usage Description
  • Privacy - Camera Usage Description

Is there any other key which I need to add to the plist file ?

@codal-shubhamb
Copy link

I have solved this issue just by removing and adding camera plugin in my application, You should try this too. The changes in Cordova-camera plugin which solves the issue are as following:
Filename - https://github.com/apache/cordova-plugin-camera/blob/master/src/ios/CDVCamera.m and just search "ResultForVideo" and there are these three lines are added in latest plugin
// On iOS 13 the movie path becomes inaccessible, create and return a copy
if (IsAtLeastiOSVersion(@"13.0")) {
moviePath = [self createTmpVideo:[[info objectForKey:UIImagePickerControllerMediaURL] path]];
}

@MustakTalukder
Copy link

Hi again! Here is the solution (sorry, I don't know how to open a new tree), to help any other user.

in CDVCamera.m change THIS:

  • (CDVPluginResult*)resultForVideo:(NSDictionary*)info
    {
    NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] absoluteString];
    return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:filePath];
    }

to THIS:

  • (CDVPluginResult*)resultForVideo:(NSDictionary*)info
    {
    NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] path];
    NSArray* spliteArray = [moviePath componentsSeparatedByString: @"/"];
    NSString* lastString = [spliteArray lastObject];
    NSError *error;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"tmp"];
    NSString *filePath = [documentsDirectory stringByAppendingPathComponent:lastString];
    [fileManager copyItemAtPath:moviePath toPath:filePath error:&error];
    return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:filePath];
    }

Hi All,

  • Go to your Xcode, And follow this comment, just replace the code. It works for me.
  • Go to your Xcode
  • Search for "(CDVPluginResult*)resultForVideo:(NSDictionary*)info" in your XCode project
  • Replace the code according to the instructions provided in this comment : LINK
  • I have attached a photo to show you how I did it.
  • photo
    Screenshot 2024-04-01 at 6 04 36 AM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment