MAUI WebView应用麦克风权限被拒问题求助
我在MAUI WebView应用中,通过JavaScript调用navigator.mediaDevices.getUserMedia访问麦克风时,持续收到"Permission Not Allowed"错误。已经在AndroidManifest.xml中配置了RECORD_AUDIO等相关权限,手机系统也已允许麦克风访问权限,但WebView无法像Android设备上的Chrome浏览器那样正常工作。
AndroidManifest权限配置
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.MICROPHONE" /> <uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
录音相关JavaScript代码
async function setRecordButtonListeners() { var myRecorder = { objects: { context: null, stream: null, recorder: null }, init: function () { if (null === myRecorder.objects.context) { myRecorder.objects.context = new ( window.AudioContext || window.webkitAudioContext ); } }, start: function () { try { var options = { audio: true, video: false }; console.log("Recording started...."); navigator.mediaDevices.getUserMedia(options).then(function (stream) { myRecorder.objects.stream = stream; myRecorder.objects.recorder = new Recorder( myRecorder.objects.context.createMediaStreamSource(stream), { numChannels: 1 } ); myRecorder.objects.recorder.record(); }).catch(function (err) { }); writeToOutput(err); setRecordTimer(myRecorder); playPopSound(); } }, stop: function (listObject) { if (null !== myRecorder.objects.stream) { myRecorder.objects.stream.getAudioTracks()[0].stop(); } if (null !== myRecorder.objects.recorder) { myRecorder.objects.recorder.stop(); // Validate object /*if (null !== listObject) {*/ // Export the WAV file myRecorder.objects.recorder.exportWAV(async function (blob) { var url = (window.URL || window.webkitURL) .createObjectURL(blob); // Prepare the playback var audioObject = document.createElement("audio"); audioObject.setAttribute("controls", ""); audioObject.setAttribute("controlsList", "noremoteplayback"); audioObject.setAttribute('src', url); console.log("Recording stopped...."); playPopSound(); //Prepare the upload link var savedToServer = await postAudioRecording(blob); //var messages = document.getElementById("messages"); }); } } } }; // Prepare the recordings list var listObject = document.getElementById("recordingList"); // Prepare the record button document.getElementById("audioRecordButton").addEventListener("click", function () { // Initialize the recorder myRecorder.init(); // Get the button state var buttonState = !!this.getAttribute('data-recording'); // Toggle if (!buttonState) { this.setAttribute('data-recording', 'true'); myRecorder.start(); } else { this.setAttribute('data-recording', ''); myRecorder.stop(listObject); } }); }; var recorderTimeout; function setRecordTimer(recorder) { recorderTimeout = setTimeout(function () { document.getElementById("audioRecordButton").click(); clearTimeout(recorderTimeout); }, 3600000); } async function postAudioRecording(blob) { event.preventDefault(); var form = document.getElementById("userRecordedAudioForm"); var formData = new FormData(form); formData.append("audio_data", blob, "audio.wav"); formData.append("chatID", document.getElementById("chatIDValue").innerHTML); const response = await (await fetch("Chat?handler=UploadAudio", { method: "post", body: formData })).text(); var jsonObject = JSON.parse(response); if (jsonObject.Success = true) { sendAudioMessage(jsonObject.chatID, jsonObject.messageID); } else { console.log(jsonObject); } } function stopRecording() { var button = document.getElementById("audioRecordButton"); var isRecording = button.dataset.recording; clearTimeout(recorderTimeout); if (isRecording) { button.click(); } } function playPopSound() { new Audio("/audio/assets/pop.mp3").play(); }
错误出现在navigator.mediaDevices.getUserMedia(options)的catch回调中。
MainPage.xaml配置
<?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" xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit" x:Class="CreatorGameMobile.MainPage"> <Page.Behaviors> <toolkit:StatusBarBehavior x:Name="statusBar" /> </Page.Behaviors> <WebView x:Name="webview"></WebView> </ContentPage>
MainPage.xaml.cs代码
public MainPage() { InitializeComponent(); webview.Source = "https://creatorgame.app"; }
MainActivity.cs代码
protected override async void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); HandleIntent(Intent); CreateNotificationChannelIfNeeded(); }
测试页面为HTTPS协议站点。
请问我在WebView中开启麦克风权限还遗漏了哪些配置?
你需要补充以下几个关键配置和代码修改:
1. 动态申请权限
Android 6.0及以上版本需要动态申请危险权限,即使在Manifest中声明了,也需要在运行时请求用户授权。修改MainActivity.cs,添加权限申请逻辑:
using Android.App; using Android.Content.PM; using Android.OS; namespace YourAppNamespace; [Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)] public class MainActivity : MauiAppCompatActivity { private const int RequestAudioPermissions = 1; protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); HandleIntent(Intent); CreateNotificationChannelIfNeeded(); // 动态申请录音权限 RequestAudioPermission(); } private void RequestAudioPermission() { if (CheckSelfPermission(Android.Manifest.Permission.RecordAudio) != Permission.Granted) { RequestPermissions(new[] { Android.Manifest.Permission.RecordAudio }, RequestAudioPermissions); } } // 处理权限申请结果 public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults) { base.OnRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == RequestAudioPermissions) { if (grantResults.Length > 0 && grantResults[0] == Permission.Granted) { // 权限已授予,可正常使用麦克风 } } } }
2. 配置WebView的权限委托
MAUI的WebView需要设置PermissionsRequested事件,处理网页的权限请求,否则WebView会默认拒绝。修改MainPage.xaml.cs:
using Microsoft.Maui.Controls; namespace YourAppNamespace; public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); webview.Source = "https://creatorgame.app"; // 监听WebView权限请求 webview.PermissionsRequested += Webview_PermissionsRequested; } private void Webview_PermissionsRequested(object sender, WebViewPermissionsRequestedEventArgs e) { foreach (var permission in e.Permissions) { // 允许麦克风权限请求 if (permission.PermissionType == WebViewPermissionType.Microphone) { e.ShouldGrantPermission = true; break; } } } }
3. 启用WebView的JavaScript和媒体支持
确保WebView启用了JavaScript和媒体相关设置,在MainPage.xaml中添加WebView的配置:
<WebView x:Name="webview" JavaScriptEnabled="True" MediaPlaybackRequiresUserAction="False"> </WebView>
4. 修复JS代码中的错误
你的JS代码中start方法存在错误:writeToOutput(err)在catch块外面,此时err未定义,会导致报错。修改catch块:
navigator.mediaDevices.getUserMedia(options).then(function (stream) { myRecorder.objects.stream = stream; myRecorder.objects.recorder = new Recorder( myRecorder.objects.context.createMediaStreamSource(stream), { numChannels: 1 } ); myRecorder.objects.recorder.record(); }).catch(function (err) { writeToOutput(err); // 把错误处理移到catch块内 }); // 移除外面的writeToOutput(err); setRecordTimer(myRecorder); playPopSound();
完成以上配置后,WebView应该可以正常请求并获取麦克风权限了。
内容的提问来源于stack exchange,提问作者Jeremy Bean

