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.