MAUI Android WebView调用录音功能遇Permission denied错误求助
MAUI多项目中WebView加载带录音功能外部URL时的权限问题
在MAUI多项目应用中,使用WebView加载带有录音选项的外部URL,已为此功能创建自定义处理程序且该程序可被调用,但仍遇到权限错误:Uncaught (in promise) NotAllowedError: Permission denied
共享项目代码
public class WebPagewithMenuItem : ContentPage { private static string title = ""; private static string hostUrl = ""; private readonly CustomWebView browser = new CustomWebView(); public WebPagewithMenuItem(string url, string token, string pageName, string hostUrlString) { title = pageName; hostUrl = hostUrlString; var html = setHtml(url, token); switch (DeviceInfo.Platform) { case var value when value == DevicePlatform.WinUI: break; case var value when value == DevicePlatform.iOS: break; default: browser.Source = html; browser.Navigating += Browser_Navigating; browser.On<Microsoft.Maui.Controls.PlatformConfiguration.Android>().SetEnableZoomControls(true).SetDisplayZoomControls(true); Content = browser; break; } } private void Browser_Navigating(object? sender, WebNavigatingEventArgs e) { var args = new DecisionHandlerDelegate(); args.Cancel = e.Cancel; args.Uri = e.Url; WebView_OnNavigationStarted(sender, args); } private HtmlWebViewSource setHtml(string url, string token) { var html = new HtmlWebViewSource { Html = @" <style> .loader { border: 4px solid #f3f3f3; border-radius: 50%; border-top: 4px solid #3498db; width: 40px; height: 40px; -webkit-animation: spin 2s linear infinite; /* Safari */ animation: spin 2s linear infinite; position: absolute; left: calc(50% - 20px); top: calc(50% - 20px); } /* Safari */ @-webkit-keyframes spin { 0% { -webkit-transform: rotate(0deg); } 100% { -webkit-transform: rotate(360deg); } } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } </style> <div class='loader'></div> <form action='" + url + @"' method='post' target='_self' id='formIframe' style='display: none'> <input type = 'hidden' name = 'token' value = '" + token + @"'> <input type = 'submit' value = 'Do Stuff!'/> </form> <script> document.getElementById('formIframe').submit(); </script> " }; return html; } private async void WebView_OnNavigationStarted(object? sender, DecisionHandlerDelegate e) { string uriLower = e.Uri.ToLower(); if (!uriLower.Contains("data:text/html;charset=utf-8;base64")) { if (uriLower.Contains("/externalauth/authaccess") == false && uriLower.Contains("/externalauth/mobilehost") == false && e.Uri.Contains("file:///") == false && e.Uri.Contains("about:blank") == false && uriLower.Contains("/help") == false && uriLower.Contains("errors/mobileerror") == false && uriLower.Contains("security/login") == false && uriLower.Contains("mvc=0") == false) { string urlValue = (System.Net.WebUtility.UrlDecode(e.Uri)).Replace(hostUrl, ".."); string newPageURL = ""; newPageURL = hostUrl + "/externalauth/mobilehost?url=" + System.Net.WebUtility.UrlEncode(urlValue); switch (DeviceInfo.Platform) { case var value when value == DevicePlatform.WinUI: break; default: var webview = (Microsoft.Maui.Controls.WebView)sender; if (webview != null) { webview.Source = newPageURL; } break; } } else if (uriLower.Contains("errors/mobileerror")) { MainThread.BeginInvokeOnMainThread(() => { Navigation.RemovePage(this.Navigation.NavigationStack[this.Navigation.NavigationStack.Count - 1]); Navigation.PopAsync(); }); e.Cancel = true; browser.IsVisible = false; } else if (uriLower.Contains("security/login")) { MainThread.BeginInvokeOnMainThread(() => { Navigation.RemovePage(this.Navigation.NavigationStack[this.Navigation.NavigationStack.Count - 1]); Navigation.PopAsync(); }); e.Cancel = true; browser.IsVisible = false; } } } private void WebPagewithMenuItem_ChildRemoved(object? sender, ElementEventArgs e) { switch (DeviceInfo.Platform) { case var value when value == DevicePlatform.WinUI: var mainPage = ((NavigationPage)Application.Current.MainPage); if (mainPage != null) { mainPage.ToolbarItems.Clear(); } break; default: break; } ((NavigationPage)Application.Current.MainPage).ChildRemoved -= WebPagewithMenuItem_ChildRemoved; } }
CustomWebView
public class CustomWebView : Microsoft.Maui.Controls.WebView { }
Android端代码
public class CustomWebViewHandler : WebViewHandler { protected override void ConnectHandler(Android.Webkit.WebView platformView) { base.ConnectHandler(platformView); // Enable JavaScript and configure other settings platformView.Settings.JavaScriptEnabled = true; platformView.Settings.DomStorageEnabled = true; platformView.Settings.MediaPlaybackRequiresUserGesture = false; platformView.SetWebChromeClient(new CustomWebChromeClient()); } protected override void DisconnectHandler(Android.Webkit.WebView platformView) { platformView.SetWebChromeClient(null); base.DisconnectHandler(platformView); } } public class CustomWebChromeClient : WebChromeClient { public override void OnPermissionRequest(PermissionRequest request) { // Check if microphone access is included in the request if (request.GetResources().Contains(PermissionRequest.ResourceAudioCapture)) { request.Grant(request.GetResources()); } else { base.OnPermissionRequest(request); } } }
MainActivity.cs
protected async override void OnResume() { try { base.OnResume(); PermissionStatus status = await Permissions.CheckStatusAsync<Permissions.Microphone>(); if (status != PermissionStatus.Granted) await Permissions.RequestAsync<Permissions.Microphone>(); } }
MauiProgram(已注册自定义处理程序)
public static class MauiProgram { public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder .UseSharedMauiApp() .ConfigureMauiHandlers((handlers) => { handlers.AddHandler(typeof(CustomWebView), typeof(CustomWebViewHandler)); }); return builder.Build(); } }
AndroidManifest已添加权限
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
内容的提问来源于stack exchange,提问作者D.madushanka
相关产品推荐
相关产品推荐

