diff --git a/lib/main.dart b/lib/main.dart index dec5a7e..b9f8da0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -239,11 +239,13 @@ class _H5ShellPageState extends State with WidgetsBindingObserver { } void _handleShellBridgeMessage(JavaScriptMessage message) { + Map? payload; String? type; try { final decoded = jsonDecode(message.message); - if (decoded is Map) { - type = decoded['type'] as String?; + if (decoded is Map) { + payload = Map.from(decoded); + type = payload['type'] as String?; } } catch (_) { type = message.message; @@ -252,6 +254,50 @@ class _H5ShellPageState extends State with WidgetsBindingObserver { if (type == 'openAppSettings') { unawaited(openAppSettings()); } + if (type == 'requestMediaPermissions' && payload != null) { + unawaited(_handleMediaPermissionBridgeRequest(payload)); + } + } + + Future _handleMediaPermissionBridgeRequest( + Map payload, + ) async { + final requestId = payload['requestId'] as String?; + if (requestId == null || requestId.isEmpty) { + return; + } + + final permissions = {}; + if (payload['audio'] == true) { + permissions.add(Permission.microphone); + } + if (payload['video'] == true) { + permissions.add(Permission.camera); + } + + final statuses = permissions.isEmpty + ? [] + : await Future.wait( + permissions.map((permission) => permission.request())); + final granted = statuses.every( + (status) => status.isGranted || status.isLimited, + ); + final permanentlyDenied = + statuses.any((status) => status.isPermanentlyDenied); + final restricted = statuses.any((status) => status.isRestricted); + + final detail = jsonEncode({ + 'requestId': requestId, + 'granted': granted, + 'permanentlyDenied': permanentlyDenied, + 'restricted': restricted, + }); + final script = ''' +(() => { + window.dispatchEvent(new CustomEvent('openim-shell-media-permission-result', { detail: $detail })); +})(); +'''; + await _runJavaScriptSafely(script); } void _showTransientShellCover() {