Forum Xamarin.Forms

Open mobile camera in webview

ZoobZoob AEMember ✭✭

I'm building an application where i load website in a webview.

On website i open device camera ( take pics etc ) and its working perfectly fine on all browsers but when i load same application in xamarin.forms web view, mobile camera doesn't show up. Any idea what could be the reason ?

Regards
TA

Answers

  • ZoobZoob AEMember ✭✭

    Little help would be great.

  • ZoobZoob AEMember ✭✭

    I think its not possible in Xamarin.

  • LyndonHugheyLyndonHughey USUniversity ✭✭✭

    Are there other ways you can trigger the device camera? If the webview is being called from another view, can you have a trigger within the webview that notifies a property in the parent view to trigger the camera?

  • ZoobZoob AEMember ✭✭

    @LyndonHughey thank you for the reply. At least there is out someone who took my question seriously since I'm stuck on this point for weeks and my management is killing me with hell of emails :(

    I don't think so we can call xamarin code from webview since application that i load in webview is hosted in some other server. Please let me know if you have something in your mind, I can try.

    Regards
    TA

  • LyndonHugheyLyndonHughey USUniversity ✭✭✭

    @Zoob I've not worked with the WebView very often but it seems there are a couple solutions on this thread:
    https://forums.xamarin.com/discussion/72681/what-is-the-easiest-way-to-call-c-method-from-javascript-in-webview

    I personally like the idea of mapping an action to a URI call in your webview. See the last post for details. I hope this helps you out.

  • JS_GJS_G USMember ✭✭

    @Zoob have you fixed your issue. I'm trying to achieve the same. Please advise?

  • AdrianGhiAdrianGhi USMember ✭✭

    I'm having the same problem like you guys.. Do you find any solution? In Xamarin.iOS, the camera is working, but in Xamarin.Android is not working...

  • devendra_jorigaldevendra_jorigal Member ✭✭

    I'm having the same problem like you guys.. Do you find any solution? In Xamarin.iOS, the camera is working, but in Xamarin.Android is not working
    Please provide solution for the same

  • tanveertanveer Member ✭✭
    edited May 2018

    There must be a way to do that but unfortunately we had the same problem but didn't manage to find any solution.

  • MondonnoMondonno Member ✭✭

    Anyone of Xamarin.iOS & Xamarin.Droid Experts can't help?

  • JGoldbergerJGoldberger USMember, Forum Administrator, Xamarin Team, University Xamurai
    edited April 23

    See my answer here

    https://stackoverflow.com/a/67236543/2913599

    Android's WebChromeClient provides an Intent for a file chooser by default. What this default chooser intent offers varies depending on Android OS version. On Android 6 and 7, when you select Gallery, there is an option to open the camera, but on later Android OS versions, there is no Gallery and there is no Camera option available.

    As per Android docs on the FileChooserParams, which is provided to the OnShowFileChooser method of the WebChromeClient, the CreateIntent() method:

    Creates an intent that would start a file picker for file selection. The Intent supports choosing files from simple file sources available on the device. Some advanced sources (for example, live media capture) may not be supported and applications wishing to support these sources or more advanced file operations should build their own Intent.

    So although your app will need the permissions noted in other answers (read and write to external storage, and the Camera permission), if you want to offer the camera as an options, you have to build it yourself.

    For Xamarin.Forms, you can leverage the Xamarin.Essentials.MediaPicker API to avoid having to deal with Android Intents directly, setting up ContentProviders, etc.

    Here is a solution that you can add to a custom Xamarin.Forms WebViewRenderer (using code from MediaPicker docs):

    [assembly: ExportRenderer(typeof(WebView), typeof(MyWebViewRenderer))]
    namespace YourAppNameSpace.Droid 
    {
        public class MyWebViewRenderer: WebViewRenderer
        {
    
            public MyWebViewRenderer(Context context) : base(context) { }
    
            protected override FormsWebChromeClient GetFormsWebChromeClient()
            {
                return new CameraFormsWebChromeClient();
            }
        }
    }
    

    And the CameraFormsWebChromeClient class:

        public class CameraFormsWebChromeClient : FormsWebChromeClient
        {
            string _photoPath;
            public override bool OnShowFileChooser(Android.Webkit.WebView webView, Android.Webkit.IValueCallback filePathCallback, FileChooserParams fileChooserParams)
            {
    
                AlertDialog.Builder alertDialog = new AlertDialog.Builder(MainActivity.Instance);
                alertDialog.SetTitle("Take picture or choose a file");
                alertDialog.SetNeutralButton("Take picture", async (sender, alertArgs) =>
                {
                    try
                    {
                        var photo = await MediaPicker.CapturePhotoAsync();
                        var uri = await LoadPhotoAsync(photo);
                        filePathCallback.OnReceiveValue(uri);
                    }
                    catch (System.Exception ex)
                    {
                        System.Console.WriteLine($"CapturePhotoAsync THREW: {ex.Message}");
                    }
                });
                alertDialog.SetNegativeButton("Choose picture", async (sender, alertArgs) =>
                {
                    try
                    {
                        var photo = await MediaPicker.PickPhotoAsync();
                        var uri = await LoadPhotoAsync(photo);
                        filePathCallback.OnReceiveValue(uri);
                    }
                    catch (System.Exception ex)
                    {
                        System.Console.WriteLine($"PickPhotoAsync THREW: {ex.Message}");
                    }
                });
                alertDialog.SetPositiveButton("Cancel", (sender, alertArgs) =>
                {
                    filePathCallback.OnReceiveValue(null);
                });
                Dialog dialog = alertDialog.Create();
                dialog.Show();
                return true;
            }
    
            async Task<Android.Net.Uri[]> LoadPhotoAsync(FileResult photo)
            {
                // cancelled
                if (photo == null)
                {
                    _photoPath = null;
                    return null;
                }
                // save the file into local storage
                var newFile = Path.Combine(FileSystem.CacheDirectory, photo.FileName);
                using (var stream = await photo.OpenReadAsync())
                using (var newStream = System.IO.File.OpenWrite(newFile))
                    await stream.CopyToAsync(newStream);
                _photoPath = newFile;
                Android.Net.Uri uri = Android.Net.Uri.FromFile(new Java.IO.File(_photoPath));
                return new Android.Net.Uri[] { uri };
            }
        }
    

    I just used the native Android Dialog for the choose or take picture selection. You can create your own UI, of course. The main thing is that you have to return 'true' from the OnShowFileChooser method to let the WebChromeClient know that you will be invoking the filePathCallback and providing a result. If you return false, you will get a native exception since the WebChromeClient was told that this method is not going to provide a result, so it provides it's own null result and we get a "Duplicate showFileChooser result" error. Also you need to save the taken picture, and then provide a Android.Net.Uri[] to the filePathCallback.OnReceiveValue method. And you must call this callback if true is returned from OnShowFileChooser, so if the user cancels, you need to call filePathCallback.OnReceiveValue(null);

Sign In or Register to comment.