Search code examples
iosvisual-studioxamarinmvvmcross

Unable to take picture with Xamarin and MvvmCross on iOS


I'm working on an iOS app, which needs to be able to take a picture (to do some stuff with).

I'm using Xamarin with MvvmCross 6.2.0 and have imported the MvxPictureChooser plugin.

I have added NSPhotoLibraryAddUsageDescription to my Info.plist

...
<key>NSPhotoLibraryAddUsageDescription</key>
<string>This app needs to be able to save your expense attachments as images.</string>
<key>UIRequiresFullScreen</key>
<true/>
...

Now, when I try to use the ChoosePictureFromLibrary, all goes well.

If, on the other hand, I try to use TakePicture(int, int, Action, Action), I get an Exception which contains the error: NSInvalidArgumentException Reason: Source type 1 not available

My code looks like this:

private void DoTakePictureCommand()
    {
        var picChooser = Mvx.IoCProvider.Resolve<IMvxPictureChooserTask>();
        try
        {
            picChooser.TakePicture(_envProvider.Environment.JpegSize, _envProvider.Environment.JpegQuality, (stream) =>
            {
                using (var ms = new MemoryStream())
                {
                    stream.CopyToAsync(ms);
                    ReceiptJpegData = ms.ToArray();

                    _log.Trace("Picture bytes: {0}", ReceiptJpegData.Length);

                    InvokeOnMainThread(ImageComplete);
                }
            }, () =>
            {

            });
        }
        catch (Exception e)
        {
            Debug.Write(e);
        }
    }

The complete error is here:

[0:] Foundation.MonoTouchException: Objective-C exception thrown. Name: NSInvalidArgumentException Reason: Source type 1 not available Native stack trace:

0 CoreFoundation 0x000000011c41429b __exceptionPreprocess + 331 1 libobjc.A.dylib 0x000000011d2e8735 objc_exception_throw + 48 2 UIKitCore 0x0000000126d03553 -[UIImagePickerController sourceType] + 0 3 xxxiOS 0x000000010ed801b9 xamarin_dyn_objc_msgSend + 217 4 ??? 0x0000000141e58257 0x0 + 5400527447

at ObjCRuntime.Runtime.ThrowNSException (System.IntPtr ns_exception) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/12.0.0.15/src/Xamarin.iOS/ObjCRuntime/Runtime.cs:398

at ObjCRuntime.Runtime.throw_ns_exception (System.IntPtr exc) [0x00000] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/runtime/Delegates.generated.cs:126

at (wrapper native-to-managed) ObjCRuntime.Runtime.throw_ns_exception(intptr) --- End of stack trace from previous location where exception was thrown --- at (wrapper managed-to-native) ObjCRuntime.Messaging.void_objc_msgSend_Int64(intptr,intptr,long) at UIKit.UIImagePickerController.set_SourceType (UIKit.UIImagePickerControllerSourceType value) [0x00015] in /Library/Frameworks/Xamarin.iOS.framework/Versions/12.0.0.15/src/Xamarin.iOS/UIKit/UIImagePickerController.g.cs:587 at MvvmCross.Plugin.PictureChooser.Platforms.Ios.MvxImagePickerTask.TakePicture (System.Int32 maxPixelDimension, System.Int32 percentQuality, System.Action`1[T] pictureAvailable, System.Action assumeCancelled) [0x00014] in <8539a731432e4b45b49dd5ca22de5afd>:0 at xxx.DoTakePictureCommand () [0x0000d] in C:\Users\xxxx\Documents\IdeaProjects\xxxx\xxxx\XXX.Core\ViewModels\AddExpenseViewModel.cs:447 0 CoreFoundation 0x000000011c41429b __exceptionPreprocess + 331 1 libobjc.A.dylib 0x000000011d2e8735 objc_exception_throw + 48 2 UIKitCore
0x0000000126d03553 -[UIImagePickerController sourceType] + 0 3
xxxiOS 0x000000010ed801b9 xamarin_dyn_objc_msgSend + 217 4 ???
0x0000000141e58257 0x0 + 5400527447 2018-09-27 23:15:03.294036+0200 xxxiOS[46563:4418172] 2018-09-27 11:15:03 [TRACE] (MvvmCross.Logging.MvxLog) iOSNavigation 2018-09-27 23:15:03.294886+0200 xxxiOS[46563:4418172] 2018-09-27 11:15:03 [TRACE] (MvvmCross.Logging.MvxLog) PresentationAttribute not found for AddExpenseView. Assuming animated Child presentation CalabashServer | XTC_SKIP_LPSERVER_TOKEN is not in the app environment CalabashServer | Will start LPServer with identifier: c36c12ce937d044d55d0c208f9d4502868233513

UPDATE

I have now tried deploying the code to my iPhone 7 which has been updated to iOS 12, and the app crashes as soon as it attempts to start the camera.

I have also tried hardcoding the int values:

private void DoTakePictureCommand()
{
    var picChooser = Mvx.IoCProvider.Resolve<IMvxPictureChooserTask>();
    try
    {
        picChooser.TakePicture(640, 50, (stream) =>
        {
            using (var ms = new MemoryStream())
            {
                stream.CopyToAsync(ms);
                ReceiptJpegData = ms.ToArray();

                _log.Trace("Picture bytes: {0}", ReceiptJpegData.Length);

                InvokeOnMainThread(ImageComplete);
            }
        }, () =>
        {

        });
    }
    catch (Exception e)
    {
        Debug.Write(e);
    }
}

But the result is the same.

UPDATE

I created a small sample project which replicates the problem. The app uses both choose picture and take picture - only choose picture works. I have posted it to a public repo on Github: PictureApp


Solution

  • OK, nailed it!

    I'll leave a solution here for other app-developer newbies, who run into this issue.

    The solution to the problem was actually quite simple: All I had to do, was add

    <key>NSCameraUsageDescription</key>
    <string></string>
    

    to Info.plist.

    It wasn't until I decided to drop MvvmCross.Plugin.PictureChooser and use Xam.Plugin.Media instead, that I got an understandable error message - basically something along the lines of: "you need to add NSCameraUsageDescription to Info.plist since iOS 10"