MAUI多权限请求失败问题(原Xamarin.Essentials可正常运行)
MAUI权限请求
RequestAsync await后无响应,需多次启动才能正常执行 问题现象
从Xamarin.Essentials迁移至MAUI后,调用Permissions.RequestAsync时,await之后的代码完全不执行(示例中的Serilog.Log.Error("This is never run!")从未输出)。每次启动应用仅能完成一个权限的请求流程,需连续启动4次后,所有权限都被授予,代码才能完整执行。
调用代码:
await Utilities.AppPermissions.RequestAppPermissions();
权限请求代码:
public static async Task<bool> RequestAppPermissions() { try { //First round of location permissions Serilog.Log.Debug($"Check 'LocationWhenInUse' Permission"); if (await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>() != PermissionStatus.Granted) { Serilog.Log.Debug($"Request'LocationWhenInUse' Permission"); await Permissions.RequestAsync<Permissions.LocationWhenInUse>(); Serilog.Log.Error("This is never run!"); } //Request LocationAlways Permission Serilog.Log.Debug($"Check 'LocationAlways' Permission"); if (await Permissions.CheckStatusAsync<Permissions.LocationAlways>() != PermissionStatus.Granted) { Serilog.Log.Debug($"Request 'LocationAlways' Permission"); await Permissions.RequestAsync<Permissions.LocationAlways>(); Serilog.Log.Error("This is never run!"); } //Notifications if (OperatingSystem.IsAndroidVersionAtLeast(33)) { Serilog.Log.Debug($"Check 'PostNotifications' Permission"); if (await Permissions.CheckStatusAsync<Permissions.PostNotifications>() != PermissionStatus.Granted) { Serilog.Log.Debug($"Request 'PostNotifications' Permission"); await Permissions.RequestAsync<Permissions.PostNotifications>(); } } return true; } catch (Exception ex) { Serilog.Log.Fatal(ex, "Failed to request permissions"); return false; } }
环境信息:
- 所有NuGet包已更新至最新版本(截至9月15日)
- Visual Studio 2022 17.11.3
问题分析
- UI线程上下文缺失:MAUI的权限请求API必须在UI主线程执行,若调用时处于非UI线程,
await后无法正确切换回原上下文,导致后续代码挂起。 - 权限依赖未处理:
LocationAlways权限需要LocationWhenInUse已被授予,连续无依赖的请求会打乱MAUI的权限处理逻辑,引发阻塞。 - 无状态反馈处理:原代码未接收
RequestAsync的返回状态,也未处理用户拒绝权限的场景,导致流程中断后无法继续。
解决方案
1. 强制在UI主线程执行权限请求
用MainThread.InvokeOnMainThreadAsync包装整个权限请求逻辑,确保上下文正确:
public static async Task<bool> RequestAppPermissions() { return await MainThread.InvokeOnMainThreadAsync(async () => { try { // 处理LocationWhenInUse权限 var locationWhenInUseStatus = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>(); Serilog.Log.Debug($"Check 'LocationWhenInUse' Permission: {locationWhenInUseStatus}"); if (locationWhenInUseStatus != PermissionStatus.Granted) { Serilog.Log.Debug($"Request 'LocationWhenInUse' Permission"); locationWhenInUseStatus = await Permissions.RequestAsync<Permissions.LocationWhenInUse>(); Serilog.Log.Debug($"LocationWhenInUse Permission Result: {locationWhenInUseStatus}"); if (locationWhenInUseStatus == PermissionStatus.Denied) { Serilog.Log.Warning("LocationWhenInUse permission denied"); return false; } } // 依赖LocationWhenInUse授予后,再请求LocationAlways if (locationWhenInUseStatus == PermissionStatus.Granted) { var locationAlwaysStatus = await Permissions.CheckStatusAsync<Permissions.LocationAlways>(); Serilog.Log.Debug($"Check 'LocationAlways' Permission: {locationAlwaysStatus}"); if (locationAlwaysStatus != PermissionStatus.Granted) { Serilog.Log.Debug($"Request 'LocationAlways' Permission"); locationAlwaysStatus = await Permissions.RequestAsync<Permissions.LocationAlways>(); Serilog.Log.Debug($"LocationAlways Permission Result: {locationAlwaysStatus}"); } } // 处理Android 13+通知权限 if (OperatingSystem.IsAndroidVersionAtLeast(33)) { var notificationStatus = await Permissions.CheckStatusAsync<Permissions.PostNotifications>(); Serilog.Log.Debug($"Check 'PostNotifications' Permission: {notificationStatus}"); if (notificationStatus != PermissionStatus.Granted) { Serilog.Log.Debug($"Request 'PostNotifications' Permission"); notificationStatus = await Permissions.RequestAsync<Permissions.PostNotifications>(); Serilog.Log.Debug($"PostNotifications Permission Result: {notificationStatus}"); } } return true; } catch (Exception ex) { Serilog.Log.Fatal(ex, "Failed to request permissions"); return false; } }); }
2. 修正Android权限配置
确认Platforms/Android/Properties/AndroidManifest.xml已添加完整权限声明:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
3. 验证步骤
- 清理解决方案并重新生成
- 卸载设备上的现有应用(避免缓存权限状态干扰)
- 重新部署应用,观察权限请求流程及日志输出
- 确认每个权限请求后的后续代码正常执行
内容的提问来源于stack exchange,提问作者JohnJore
相关产品推荐
相关产品推荐

