XamarinCommunityToolkit: [Bug] [CameraView] [iOS] Taking photos doesn't work on iOS using Hot Restart
Description
I’m using Hot Restart in Windows to debug my Xamarin.Forms app on iOS. Whenever I take a photo (trigger the ShutterCommand), the app UI freezes and the MediaCaptured event never gets called.
I also get this lovely exception:
=================================================================
Basic Fault Address Reporting
=================================================================
Memory around native instruction pointer (0x1010ae8c4):0x1010ae8b4 a8 83 5e f8 09 00 80 52 09 01 00 39 a8 03 5f f8 ..^....R...9.._.
0x1010ae8c4 09 01 40 39 69 0f 00 34 a8 03 5f f8 09 01 c0 39 ..@9
.
=================================================================
Managed Stacktrace:
=================================================================
.4.._....9
0x1010ae8d4 29 8d 00 71 e8 03 09 aa 08 7d 40 d3 1f 69 01 f1 )..q.....}@..i..
0x1010ae8e4 e8 13 00 f9 68 0b 00 54 08 00 00 90 08 61 2c 91 ....h..T.....a,
at <unknown> <0xffffffff>
at UIKit.UIApplication:UIApplicationMain <0x000b8>
at UIKit.UIApplication:Main <0x00020>
at UIKit.UIApplication:Main <0x00038>
at XctCameraApp01.iOS.Application:Main <0x00012>
at <Module>:runtime_invoke_direct_void_string[] <0x0008c>
at <unknown> <0xffffffff>
at System.Reflection.RuntimeMethodInfo:InternalInvoke <0x00030>
at System.Reflection.RuntimeMethodInfo:Invoke <0x000fc>
at System.Reflection.MethodBase:Invoke <0x0001a>
at Xamarin.PreBuilt.iOS.Applications:Main <0x00254>
at <Module>:runtime_invoke_direct_void_string[] <0x00092>
=================================================================
Steps to Reproduce
- CameraPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="XctCameraApp01.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:xct="http://xamarin.com/schemas/2020/toolkit">
<Grid>
<xct:CameraView
x:Name="cameraView"
CaptureMode="Photo"
OnAvailable="cameraView_OnAvailable">
<xct:CameraView.Behaviors>
<xct:EventToCommandBehavior Command="{Binding PhotoCapturedCommand}" EventName="MediaCaptured" />
</xct:CameraView.Behaviors>
</xct:CameraView>
<Button
Margin="20"
Command="{Binding ShutterCommand, Source={x:Reference cameraView}}"
HorizontalOptions="Center"
IsEnabled="{Binding CanTakePhoto}"
Text="Take photo"
VerticalOptions="End" />
</Grid>
</ContentPage>
- CameraPage.xaml.cs
using Xamarin.Forms;
namespace XctCameraApp01
{
public partial class MainPage : ContentPage
{
private readonly MainViewModel _model;
public MainPage()
{
InitializeComponent();
BindingContext = _model = new MainViewModel();
}
private void cameraView_OnAvailable(object sender, bool e)
{
_model.CanTakePhoto = e;
}
}
}
- MainViewModel.cs
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.CommunityToolkit.ObjectModel;
using Xamarin.CommunityToolkit.UI.Views;
using Xamarin.Essentials;
using Xamarin.Forms;
using static Xamarin.Essentials.Permissions;
namespace XctCameraApp01
{
public class MainViewModel : ObservableObject
{
private bool _canTakePhoto;
public bool CanTakePhoto
{
get => _canTakePhoto;
set => SetProperty(ref _canTakePhoto, value);
}
public ICommand PhotoCapturedCommand => new AsyncCommand<MediaCapturedEventArgs>(PhotoCapturedAsync);
private async Task PhotoCapturedAsync(MediaCapturedEventArgs args)
{
await SavePhotoAsync(args.ImageData);
}
private async Task SavePhotoAsync(byte[] photoData)
{
var readStatus = await CheckAndRequestPermissionAsync(new StorageRead());
if (readStatus != PermissionStatus.Granted)
{
// Notify user permission was denied
return;
}
var writeStatus = await CheckAndRequestPermissionAsync(new StorageWrite());
if (writeStatus != PermissionStatus.Granted)
{
// Notify user permission was denied
return;
}
var savedPhotoPath = await SavePhotoFileAsync(photoData, Guid.NewGuid().ToString() + ".jpg");
LastSavedPhotoPath = savedPhotoPath;
}
private async Task<string> SavePhotoFileAsync(byte[] photoData, string fileName)
{
var dirPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
Directory.CreateDirectory(dirPath);
var savedPhotoPath = Path.Combine(dirPath, fileName);
using (var fs = new FileStream(savedPhotoPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
{
await fs.WriteAsync(photoData, 0, photoData.Length);
return savedPhotoPath;
}
}
public async Task<PermissionStatus> CheckAndRequestPermissionAsync<T>(T permission) where T : BasePermission
{
var status = await permission.CheckStatusAsync();
if (status != PermissionStatus.Granted)
{
status = await permission.RequestAsync();
}
return status;
}
}
}
- Launch app on an iOS device using Hot Restart and click the ‘Take photo’ button
Expected Behavior
CameraView takes a photo and triggers the MediaCaptured event
Actual Behavior
The MediaCaptured event doesn’t get triggered, the camera preview keeps going.
Basic Information
- Version with issue: 1.0.2
- Last known good version: ?
- IDE: VS 2019 Professional v16.8.5
- Platform Target Frameworks:
- iOS: Default (14.3 I guess)
- Android: 10.0
- UWP: nope
- Android Support Library Version: Android X
- Nuget Packages:
- Xamarin.Forms 5.0.0.1931
- Xamarin.Essentials 1.6.1
- Affected Devices:
- iPad Air 2 (iOS 13.7)
Reproduction repo
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 33 (10 by maintainers)
This happens in production, App Store apps, not just in development. They get one or two photos and then it stops firing the event.
Still happening for me, even tried 1.3.0-pre1 and it still happening. Sometimes it works for one or two photos and then it stops working.
I didn’t get it to work in any version, at least not when using Hot Restart.
I never tried it when connected to a Mac (my setup doesn’t allow that), so I have no idea whether that works or not. And sadly, the iOS simulator doesn’t support a camera, so that’s not an option.
@ShinichiHezemansCortegs I’m not aware of any alternative to the
CameraView. I’ve found many example implementations of a camera view renderer but none of them worked on all platforms, some didn’t work at all.I’m going to assume this is fixed for now then. If that is not the case for Hot Restart @michaldivis please let me know!
Still happening for me. Sometimes it works for one or two photos and then it stops working. (1.2.0 version)
Resolved in the 1.2.0 version.
Hi - I’m having the same issue when calling cameraView.Shutter() the MediaCapture event isn’t being hit. I’m seeing this in Debug mode as well as Release mode. MediaCaptureFailed also doesn’t get hit
@pictos I’ve attached a reproduction repo. You can find it here: https://github.com/michaldivis/camera-view-app