You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter集成Android WebView遇摄像头、麦克风、位置权限拒绝问题

问题:Flutter WebView集成网页视频聊天应用时权限被拒绝(Access Denied)

开发的网页视频聊天应用在Chrome、Firefox等浏览器中运行正常,但集成到Android WebView后,即使已授予摄像头、麦克风和位置权限,打开应用仍出现“Access Denied”错误。已尝试更新AndroidManifest.xml文件并使用permission_handler包,问题依旧。


环境依赖

webview_flutter: ^4.10.0
webview_flutter_android: ^4.0.1
webview_flutter_wkwebview: ^3.16.1
webview_flutter_web: ^0.2.3+3
permission_handler: ^11.3.1

已尝试的配置与代码

AndroidManifest.xml

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

<uses-feature android:name="android.hardware.location.gps" />
<uses-feature android:name="android.hardware.location" />
<uses-feature
    android:name="android.hardware.camera"
    android:required="true" />

<activity>
  ...
  <intent-filter>
    <action android:name="android.intent.action.MAIN"/>
    <category android:name="android.intent.category.LAUNCHER"/>
  </intent-filter>
  <intent-filter android:label="Deep Link">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:host="profile" android:scheme="scan" />
  </intent-filter>
   <intent-filter android:label="App Links">
   <action android:name="android.intent.action.VIEW" />
   <category android:name="android.intent.category.DEFAULT" />
   <category android:name="android.intent.category.BROWSABLE" />
   <data android:host="profile" android:scheme="https" />
  </intent-filter>
</activity>
 <activity android:name="io.flutter.embedding.android.FlutterActivity">
 <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing" android:value="true" />
</activity>

WebView.dart

import 'package:flutter/material.dart';
import 'package:vc/utils/app_state.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:vc/utils/WebViewController.dart';

class WebViewPage extends StatefulWidget {
  final String url;

  const WebViewPage({Key? key, required this.url}) : super(key: key);

  @override
  State<WebViewPage> createState() => _WebViewPageState();
}

class _WebViewPageState extends State<WebViewPage> {
  late WebViewController _controller;
  final String redirectUrl = "vc://thankyou";

  @override
  void initState() {
    super.initState();
    _initializeWebView();
  }

  Future<void> _initializeWebView() async {
    try {
      final controller = await CustomWebViewController.createController(
        url: widget.url,
        redirectUrl: redirectUrl,
        onRedirect: _handleRedirection,
      );
      setState(() {
        _controller = controller;
      });
    } catch (e) {
      debugPrint('Error initializing WebViewController: $e');
    }
  }

  void _handleRedirection(String url) {
    debugPrint("Redirecting to: $url");
    final uniqueID = AppState().uniqueID ?? '';
    Navigator.pop(context);
    if (uniqueID.isNotEmpty) {
      Navigator.pushNamed(context, '/thankyou', arguments: uniqueID);
    } else {
      Navigator.pushNamed(context, '/thankyou');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("CallPage"),
      ),
      body: _controller == null
          ? const Center(child: CircularProgressIndicator())
          : WebViewWidget(controller: _controller),
    );
  }
}

WebViewController.dart

import 'package:permission_handler/permission_handler.dart';
import 'package:webview_flutter/webview_flutter.dart';

class CustomWebViewController {
  static Future<WebViewController> createController({
    required String url,
    required String redirectUrl,
    required Function(String) onRedirect,
  }) async {
    await _requestCameraPermission();

    final controller = WebViewController();

    await controller.setJavaScriptMode(JavaScriptMode.unrestricted);
    await controller.setNavigationDelegate(
      NavigationDelegate(
        onPageStarted: (String currentUrl) {
          if (currentUrl.startsWith(redirectUrl)) {
            onRedirect(currentUrl);
          }
        },
      ),
    );
    await controller.loadRequest(Uri.parse(url));
    return controller;
  }

  static Future<void> _requestCameraPermission() async {
    final status = await Permission.camera.request();
    if (status.isGranted) {
      print('Camera permission granted');
    } else if (status.isPermanentlyDenied) {
      print('Camera permission permanently denied');
      await openAppSettings();
    } else {
      print('Camera permission denied');
    }
  }
}

解决步骤

1. 补充请求所有必要权限

当前仅请求了摄像头权限,需要同时请求麦克风和位置权限,修改权限请求方法:

static Future<void> _requestAllPermissions() async {
  // 批量请求摄像头、麦克风、位置权限
  final statuses = await [
    Permission.camera,
    Permission.microphone,
    Permission.location,
  ].request();

  // 输出各权限状态
  statuses.forEach((permission, status) {
    if (status.isGranted) {
      print('${permission.name} permission granted');
    } else if (status.isPermanentlyDenied) {
      print('${permission.name} permission permanently denied');
      openAppSettings();
    } else {
      print('${permission.name} permission denied');
    }
  });
}

在createController方法中调用_requestAllPermissions()替代原_requestCameraPermission()。

2. 配置Android WebView媒体权限策略

添加Android平台专属配置,允许WebView自动授予媒体权限:

import 'package:webview_flutter_android/webview_flutter_android.dart';

// 在createController方法的controller初始化后添加:
if (controller.platform is AndroidWebViewController) {
  final androidController = controller.platform as AndroidWebViewController;
  // 允许无需用户手势即可播放媒体
  await androidController.setMediaPlaybackRequiresUserGesture(false);
  // 处理WebView权限请求
  await androidController.setPermissionRequestHandler(
    (WebViewPermissionRequest request) {
      request.grant(request.resources);
    },
  );
}

3. 完善AndroidManifest.xml配置

补充位置权限并启用硬件加速:

<!-- 添加精确/粗略位置权限 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

<!-- 在主Activity标签内启用硬件加速 -->
<activity
  ...
  android:hardwareAccelerated="true">
  ...
</activity>

4. 处理WebView权限请求回调

在NavigationDelegate中添加权限请求处理逻辑:

await controller.setNavigationDelegate(
  NavigationDelegate(
    onPageStarted: (String currentUrl) {
      if (currentUrl.startsWith(redirectUrl)) {
        onRedirect(currentUrl);
      }
    },
    // 添加权限请求处理
    onPermissionRequest: (PermissionRequest request) {
      request.grant(request.resources);
    },
  ),
);

内容的提问来源于stack exchange,提问作者user2806353

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 02:05:56