[Bug] [iOS] CapturePhotoAsync File Not Found
Description
When using the new MediaPicker.CapturePhotoAsync API, a file not found error is encountered when trying to access the file. This only occurs in iOS; in Android it works as expected.
Steps to Reproduce
- Add Xamarin.Essentials 1.6
- Take a photo by calling
await MediaPciker.CapturePhotoAsync(); - Access the file from the FullPath property of the resulting FileResult
Expected Behavior
The file returned by the FullPath property of the FileResult returned by this method should provide access to the photo taken
Actual Behavior
The path returns a File Not Found error
Basic Information
-
Version with issue: 1.6.0
-
Last known good version: NA
-
IDE: Visual Studio for Mac 8.8.2 (build 41)
-
Platform Target Frameworks:
- iOS: 12.2
- Android: 28
-
Affected Devices: iPhone XS Max
Reproduction Link
The following repo contains a small demo project that reproduces this issue:
https://github.com/matt-goldman/EssentialsCameraBug
If you run this on Android and take a picture, the picture will display on the screen. If you do the same on iOS, the screen remains blank. By debugging you can see that the filepath has a value, but the file cannot be returned. In other scenarios (not reproduced here) trying to access the file elsewhere (e.g. in a service to upload it to an API) a File Not Found exception is thrown.
Is there any workarounds to this? Can we append a path to the filename to get the full path?
Is there any workarounds to this? Can we append a path to the filename to get the full path?
I haven't found a workaround, but in all honesty I haven't really dived into it much further than this. I'm not even sure whether an image is captured. I reverted to the CrossMedia plugin for now.
cheers @matt-goldman, I went down this route first, looks like I'll be moving over to CrossMedia as well.
FWIW, it looks like the iOS implementation, and maybe other platforms, want you to use the stream object. You can see this in the iOS implementation code here.
internal UIImageFileResult(UIImage image)
: base()
{
uiImage = image;
FullPath = Guid.NewGuid().ToString() + FileSystem.Extensions.Png;
FileName = FullPath;
}
The way that I resolved it is to just read from the stream and copy the image to the cache file.
var cameraResponse = await MediaPicker.CapturePhotoAsync ().ConfigureAwait(false);
var stream = await cameraResponse?.OpenReadAsync ().ConfigureAwait(false);
var fileResultPath = string.Empty;
if(stream != null && stream != Stream.Null)
{
var tempFile = Path.Combine (FileSystem.CacheDirectory, cameraResponse?.FileName);
using (var fileStream = new FileStream(tempFile, FileMode.CreateNew))
{
await stream.CopyToAsync(fileStream).ConfigureAwait(false);
await stream.FlushAsync ().ConfigureAwait (false);
}
fileResultPath = tempFile;
await stream.DisposeAsync ().ConfigureAwait (false);
}
// This path is good
var doSomethingWithThis = fileResultPath;
Hi!, the bug is still there ... just updated the xamarin essentials inside an app, only to find this is still broken under 1.7.0.
+1
+1
Same here... still not working on Xamarin.Essentials v1.7.7. The Android implementation works fine, and returns a FileResult with the FileName and FullPath set properly. Meaning... The fullpath includes the complete path to the folder... and the filename.
But, the iOS implementation returns the same string value for both properties. And, trusting the "FullPath" property to be what it says, results in an exception.
Is there a fix for this?