After lots of back and forth trying, able to solve the issue. Below is my complete solution. Hope it will help other who needs it in future.
Thank you so much Yonglun Liu for your big help.
Step 1. Modify the MainActivity
under the Platfrom/Android
folder.
public class MainActivity : MauiAppCompatActivity
{
public static IValueCallback mUploadCallbackAboveL;
public static Android.Net.Uri imageUri;
public static MainActivity Instance;
public static int PHOTO_REQUEST = 10023;
protected override void OnCreate(Bundle bundle) {
base.OnCreate(bundle);
Instance = this;
if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.Camera) != (int)Permission.Granted){
}
}
protected override void OnActivityResult(int requestCode, Result resultCode, Android.Content.Intent intent)
{
if (resultCode == Result.Ok){
if (intent != null && intent.Data !=null) // File picker selected photo
{
if (null == mUploadCallbackAboveL) return;
Android.Net.Uri result = intent == null || resultCode != Result.Ok ? null : intent.Data;
//mUploadMessage.OnReceiveValue(result);
mUploadCallbackAboveL.OnReceiveValue(new Android.Net.Uri[] { result });
mUploadCallbackAboveL = null;
}
else if (requestCode == PHOTO_REQUEST){
if (mUploadCallbackAboveL != null){
onActivityResultAboveL(requestCode, resultCode, intent);
}
}
}
else {
if (resultCode != Result.Ok){
mUploadCallbackAboveL.OnReceiveValue(null);
mUploadCallbackAboveL = null;
return;
}
}
}
private void onActivityResultAboveL(int requestCode, Result resultCode, Android.Content.Intent data){
if (requestCode != PHOTO_REQUEST || mUploadCallbackAboveL == null){
return;
}
Android.Net.Uri[] results = null;
if (resultCode == Result.Ok){
results = new Android.Net.Uri[] { imageUri };
results[0] = MainActivity.imageUri;
}
mUploadCallbackAboveL.OnReceiveValue(results);
mUploadCallbackAboveL = null;
}
}
Step 2. Implement a custom WebChromeClient under the Platfrom/Android
folder.
internal class MyWebChromeClient : WebChromeClient{
private MainActivity activity = null;
public MyWebChromeClient(MainActivity context){
this.activity = context;
}
public override void OnPermissionRequest(PermissionRequest request){
foreach (var resource in request.GetResources()) {
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());
return;
}
}
base.OnPermissionRequest(request);
}
public override bool OnShowFileChooser(WebView webView, IValueCallback filePathCallback, FileChooserParams fileChooserParams){
MainActivity.mUploadCallbackAboveL = filePathCallback;
//PickPhoto;
var imageStorageDir = FileSystem.Current.CacheDirectory;
// Create picked image file path and name, add ticks to make it unique
var file = new Java.IO.File(imageStorageDir + Java.IO.File.Separator + "IMG_" + DateTime.Now.Ticks + ".jpg");
//MainActivity.imageUri = Uri.FromFile(file);
MainActivity.imageUri = FileProvider.GetUriForFile(activity, activity.PackageName + ".fileprovider", file);
//Create camera capture image intent and add it to the chooser
var captureIntent = new Intent(MediaStore.ActionImageCapture);
captureIntent.PutExtra(MediaStore.ExtraOutput, MainActivity.imageUri);
var i = new Intent(Intent.ActionGetContent);
i.AddCategory(Intent.CategoryOpenable);
i.SetType("image/*");
var chooserIntent = Intent.CreateChooser(i, "Choose Image");
chooserIntent.PutExtra(Intent.ExtraInitialIntents, new Intent[] { captureIntent });
MainActivity.Instance.StartActivityForResult(chooserIntent, MainActivity.PHOTO_REQUEST);
return true;
}
}
Step 3. Modify the AndroidManifest.xml under the Platfrom/Android
folder.
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:supportsRtl="true">
<provider android:name="androidx.core.content.FileProvider"
android:authorities="YOUR_PACKAGE_NAME.fileprovider" android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"></meta-data>
</provider>
</application>
<uses-permission android:name="android.permission.CAMERA" />
<!--<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />--> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Required only if your app needs to access images or photos that other apps created -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<!-- Required only if your app needs to access videos that other apps created -->
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<!-- Required only if your app needs to access audio files that other apps created -->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-feature android:name="android.hardware.camera"/>
<uses-sdk android:minSdkVersion="23" android:targetSdkVersion="33" />
<queries>
<intent>
<action android:name="android.media.action.IMAGE_CAPTURE" />
</intent>
</queries>
Step 4. MainPage.Xaml looks like below.
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="UPloadFile.MainPage"
Title="Uplodad file webview">
<WebView Loaded="WebView_Loaded"
x:Name="myWebView"
Source="https://xyz.com">
</WebView>
</ContentPage>
Step 5. MainPage.Xaml.cs looks like below.
public partial class MainPage : ContentPage
{
public Dashboard(){
InitializeComponent();
}
protected override void OnHandlerChanged(){
base.OnHandlerChanged();
#if ANDROID
var webview = myWebView.Handler.PlatformView as Android.Webkit.WebView;
webview.SetWebChromeClient(new STC_Delivery_App.Platforms.Android.MyWebChromeClient(MainActivity.Instance));
if (webview is not null){
webview.Settings.MediaPlaybackRequiresUserGesture = false;
webview.Settings.SetGeolocationEnabled(true);
webview.Settings.JavaScriptEnabled = true;
}
#endif
}
private async void WebView_Loaded(object sender, EventArgs e){
PermissionStatus status = await Permissions.CheckStatusAsync<Permissions.Camera>();
if (status != PermissionStatus.Granted){
if (Permissions.ShouldShowRationale<Permissions.Camera>()) { }
await Permissions.RequestAsync<Permissions.Camera>();
}
status = await Permissions.CheckStatusAsync<Permissions.StorageRead>();
if (status != PermissionStatus.Granted){
if (Permissions.ShouldShowRationale<Permissions.StorageRead>()) { }
await Permissions.RequestAsync<Permissions.StorageRead>();
}
status = await Permissions.CheckStatusAsync<Permissions.StorageWrite>();
if (status != PermissionStatus.Granted){
if (Permissions.ShouldShowRationale<Permissions.StorageWrite>()) { }
await Permissions.RequestAsync<Permissions.StorageWrite>();
}
}
}