Camera option didn't appeared on MAUI android .net 8.0 WebView

Ei Ei Phyu 0 Reputation points
2024-09-09T09:07:17.1933333+00:00

My WebView does not show the camera functionality when the user interacts with the web page. This issue affects the ability to capture or upload images from the page. I have already added the necessary camera-related permissions to the AndroidManifest.xml file and tried using the WebChromeClient method, but neither solution worked for me. Could you please provide sample source code or share working code if possible?

.NET MAUI
.NET MAUI
A Microsoft open-source framework for building native device applications spanning mobile, tablet, and desktop.
3,596 questions
{count} votes

2 answers

Sort by: Most helpful
  1. Leon Lu (Shanghai Wicresoft Co,.Ltd.) 76,551 Reputation points Microsoft Vendor
    2024-09-17T09:36:44.8533333+00:00

    Hello,

    =================Update================

    But web page hit error net:ERR_ACCESS_DENIED after take the photo and click on submit button.

    I get the same issue. You can open your AndroidManifest.xml, add android:usesCleartextTraffic="true" in the <application> tag.

    Then open MainActivity.cs add Manifest.Permission.ReadExternalStorage like following code in the OnCreate method.

       ActivityCompat.RequestPermissions(this, new[] { Manifest.Permission.Camera, Manifest.Permission.RecordAudio, Manifest.Permission.ModifyAudioSettings, Manifest.Permission.ReadExternalStorage }, 0);
    

    Next, open MauiProgram.cs and find CustomizeWebViewHandler, add allow access content for the webview settings.

      private static void CustomizeWebViewHandler()
            {
    #if ANDROID26_0_OR_GREATER
            Microsoft.Maui.Handlers.WebViewHandler.Mapper.ModifyMapping(
                nameof(Android.Webkit.WebView.WebChromeClient),
                (handler, view, args) =>
                {
                    handler.PlatformView.Settings.JavaScriptEnabled = true;
                    handler.PlatformView.Settings.AllowContentAccess = true;
                    handler.PlatformView.Settings.AllowFileAccess = true;
                    handler.PlatformView.SetWebChromeClient(new WebViewCameraDemo.Platforms.Android.MyWebChromeClient(handler));               
                }
                );
    #endif
            }
    

    After check the source code of onShowFileChooser, if you want to open the camara, you need to implement open camera code in the OnShowFileChooser method of MyWebChromeClient like following code. I open the camera by Intent

    using Android.Content;
    using Android.Icu.Text;
    using Android.Icu.Util;
    using Android.OS;
    using Android.Provider;
    using Android.Webkit;
    using Microsoft.Maui.Handlers;
    using Microsoft.Maui.Platform;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
     
    namespace WebViewCameraDemo.Platforms.Android
    {
        internal class MyWebChromeClient : MauiWebChromeClient
        {
            public MyWebChromeClient(IWebViewHandler handler) : base(handler)
            {
     
            }
            public static IValueCallback mUploadCallbackAboveL;
            public override bool OnShowFileChooser(global::Android.Webkit.WebView webView, IValueCallback filePathCallback, FileChooserParams fileChooserParams)
            {
                mUploadCallbackAboveL= filePathCallback;
                takePhoto();
                return true;
            }
     
            private void takePhoto()
            {
                //close the policy, if not you will get Android.OS.FileUriExposedException:exposed beyond app through ClipData.Item.getUri()'
                StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
                StrictMode.SetVmPolicy(builder.Build());
     
                Intent intent = new Intent(MediaStore.ActionImageCapture);
                intent.PutExtra(MediaStore.ExtraOutput, MainActivity.imageUri);
                MainActivity.Instance.StartActivityForResult(intent, MainActivity.REQUEST_CODE);
     
     
                // Select the picture from the local file
                //        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
                //        i.addCategory(Intent.CATEGORY_OPENABLE);
                //        i.setType("image/*");
                //        startActivityForResult(Intent.createChooser(i, "Image Chooser"), REQUEST_CODE);
            }
     
            public override void OnPermissionRequest(PermissionRequest request)
            {
                // Process each request
                foreach (var resource in request.GetResources())
                {
                    // Check if the web page is requesting permission to the camera
                    if (resource.Equals(PermissionRequest.ResourceVideoCapture, StringComparison.OrdinalIgnoreCase))
                    {
                        // Get the status of the .NET MAUI app's access to the camera
                        //PermissionStatus status = Permissions.CheckStatusAsync<Permissions.Camera>().Result;
     
                        //// Deny the web page's request if the app's access to the camera is not "Granted"
                        //if (status != PermissionStatus.Granted)
                        //    request.Deny();
                        //else
                        //    request.Grant(request.GetResources());
     
                        try
                        {
                            request.Grant(request.GetResources());
                            base.OnPermissionRequest(request);
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex);
                        }
                        return;
                    }
                }
     
                base.OnPermissionRequest(request);
            }
        }
    }
    

    After taking the photo, we need to handle this result and notify the android system with broadcast. I handle it in the MainActivity.cs, you can refer to it.

    sing Android;
    using Android.App;
    using Android.Content;
    using Android.Content.PM;
    using Android.OS;
    using Android.Util;
    using AndroidX.Core.App;
    using WebViewCameraDemo.Platforms.Android;
     
    namespace WebViewCameraDemo
    {
        [Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
        public class MainActivity : MauiAppCompatActivity
        {
            public static int REQUEST_CODE = 10004556;
            public static Android.Net.Uri imageUri;
            public static MainActivity Instance;
         protected override void OnCreate(Bundle? savedInstanceState)
            {
                base.OnCreate(savedInstanceState);
                Instance = this;
                // set the path of save the photo file
                string filePath = Android.OS.Environment.ExternalStorageDirectory + Java.IO.File.Separator
                + Android.OS.Environment.DirectoryPictures + Java.IO.File.Separator;
                string fileName = "IMG_" + DateTime.Now.Millisecond + ".jpg";
                imageUri = Android.Net.Uri.FromFile(new Java.IO.File(filePath + fileName));
                ActivityCompat.RequestPermissions(this, new[] { Manifest.Permission.Camera, Manifest.Permission.RecordAudio, Manifest.Permission.ModifyAudioSettings }, 0);
     
            }
    
            protected override void OnActivityResult(int requestCode, Result resultCode, Intent? data)
            {
                base.OnActivityResult(requestCode, resultCode, data);
     
                if (requestCode== REQUEST_CODE)
                {
                    chooseAbove(requestCode, data);
                }   
            }
            private void chooseAbove(int resultCode, Intent data)
            {
     
                if (resultCode== REQUEST_CODE)
                {
                    updatePhotos();
     
                    if (data != null)
                    {
                        // handle the picture
                        Android.Net.Uri[] results;
                        Android.Net.Uri uriData = data.Data;
                        if (uriData != null)
                        {
                            results = new Android.Net.Uri[] { uriData };
                            foreach (Android.Net.Uri uri in results)
                            {
                                Log.Info("test", "return uri:" + uri.ToString());
                            }
                            MyWebChromeClient.mUploadCallbackAboveL.OnReceiveValue(results);
                        }
                        else
                        {
                            MyWebChromeClient.mUploadCallbackAboveL.OnReceiveValue(null);
                        }
                    }
                    else
                    {
                        MyWebChromeClient.mUploadCallbackAboveL.OnReceiveValue(new Android.Net.Uri[] { imageUri });
                    }
                }
                MyWebChromeClient.mUploadCallbackAboveL = null;
            }
     
            private void updatePhotos()
            {
                //Send the broadcast to notify the system to reflash file
                Intent intent = new Intent(Intent.ActionMediaScannerScanFile);
                intent.SetData(imageUri);
                SendBroadcast(intent);
            }
        }
    }
    

    Best Regards,

    Leon Lu


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.

  2. EI EI PHYU 0 Reputation points
    2024-09-27T06:07:57.7266667+00:00

    Hi Leon,

    Thank you so much for your help.

    I had found a way to upload which is very similar with what you shared and I added some source code to get what I need. My AlertDialog can show up with 3 buttons now which is one for Camera, one for pick picture from photo gallery and Cancel button to go back to main page. I will update on my GitHub source code as well.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.