Flutter WebView问题求助:Android定位失效、iOS摄像头无法显示
Flutter WebView 跨平台权限与功能异常解决方案
问题描述
- Android端无法获取定位信息
- iOS端摄像头/视频无法正常显示
- 其他支持摄像头和定位功能的网站可正常运行,项目采用Flutter WebView实现,服务端基于Python Flask搭建
相关代码
Flutter WebView 页面代码
import 'dart:io'; import 'package:flutter/material.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:webview_flutter/webview_flutter.dart'; import 'package:webview_flutter_android/webview_flutter_android.dart'; import 'package:geolocator/geolocator.dart'; class FaceIDPage extends StatefulWidget { const FaceIDPage({Key? key}) : super(key: key); @override _FaceIDPageState createState() => _FaceIDPageState(); } class _FaceIDPageState extends State<FaceIDPage> { late final WebViewController _controller; @override void initState() { super.initState(); _requestPermissions(); _initializeWebView(); } Future<void> _requestPermissions() async { if (Platform.isIOS) { await [ Permission.camera, Permission.microphone, Permission.location, ].request(); } else if (Platform.isAndroid) { await [ Permission.camera, Permission.location, Permission.microphone, ].request(); } } Future<Position> _getCurrentPosition() async { bool serviceEnabled; LocationPermission permission; serviceEnabled = await Geolocator.isLocationServiceEnabled(); if (!serviceEnabled) { return Future.error('Location services are disabled.'); } permission = await Geolocator.checkPermission(); if (permission == LocationPermission.denied) { permission = await Geolocator.requestPermission(); if (permission == LocationPermission.denied) { return Future.error('Location permissions are denied'); } } if (permission == LocationPermission.deniedForever) { return Future.error('Location permissions are permanently denied.'); } return await Geolocator.getCurrentPosition(); } void _setGeolocationInWebView(WebViewController controller) async { try { Position position = await _getCurrentPosition(); await controller.runJavaScript(''' navigator.geolocation.getCurrentPosition = function(success, error) { success({coords: {latitude: ${position.latitude}, longitude: ${position.longitude}}}); }; '''); } catch (e) { debugPrint('Ошибка при получении координат: $e'); } } void _initializeWebView() { final PlatformWebViewControllerCreationParams params = PlatformWebViewControllerCreationParams(); _controller = WebViewController.fromPlatformCreationParams( params, onPermissionRequest: (resources) async { return resources.grant(); }, ) ..setJavaScriptMode(JavaScriptMode.unrestricted) ..setBackgroundColor(Colors.transparent) ..setNavigationDelegate( NavigationDelegate( onPageFinished: (String url) { _setGeolocationInWebView(_controller); }, ), ) ..loadRequest(Uri.parse('https://pyth.***')); if (Platform.isAndroid) { final AndroidWebViewController androidController = _controller.platform as AndroidWebViewController; AndroidWebViewController.enableDebugging(true); androidController.setMediaPlaybackRequiresUserGesture(false); //androidController.setGeolocationEnabled(true); } else if (Platform.isIOS) { _controller.runJavaScript(''' navigator.mediaDevices.getUserMedia({ video: true, audio: true }) .then(stream => { const video = document.createElement('video'); video.srcObject = stream; video.setAttribute('playsinline', true); video.play(); document.body.appendChild(video); }) .catch(error => { console.error('Ошибка при доступе к камере: ', error); }); '''); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('FaceID Верификация'), ), body: WebViewWidget(controller: _controller), ); } }
服务端说明
服务端基于Python Flask搭建,app.py包含index.html及相关JS、CSS资源。
解决方案
Android 定位问题修复
启用WebView定位支持
取消Android端代码中androidController.setGeolocationEnabled(true);的注释,显式开启WebView的定位功能。同步权限请求与WebView初始化
当前_requestPermissions()和_initializeWebView()并行执行,可能导致WebView初始化时权限未获取完成。修改initState为异步初始化:@override void initState() { super.initState(); _init(); } Future<void> _init() async { await _requestPermissions(); _initializeWebView(); setState(() {}); }完善定位注入逻辑
补充watchPosition方法的模拟,避免Web端因方法不存在报错:await controller.runJavaScript(''' navigator.geolocation.getCurrentPosition = function(success, error) { success({coords: {latitude: ${position.latitude}, longitude: ${position.longitude}, accuracy: 100}}); }; navigator.geolocation.watchPosition = function(success) { success({coords: {latitude: ${position.latitude}, longitude: ${position.longitude}, accuracy: 100}}); }; ''');检查AndroidManifest权限
确保android/app/src/main/AndroidManifest.xml中添加定位权限:<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
iOS 摄像头问题修复
延迟执行摄像头JS代码
将iOS端的摄像头调用代码移至onPageFinished回调中,确保页面加载完成后再执行:NavigationDelegate( onPageFinished: (String url) { _setGeolocationInWebView(_controller); if (Platform.isIOS) { _controller.runJavaScript(''' navigator.mediaDevices.getUserMedia({ video: true, audio: true }) .then(stream => { const video = document.createElement('video'); video.srcObject = stream; video.setAttribute('playsinline', true); video.play(); document.body.appendChild(video); }) .catch(error => { console.error('Ошибка при доступе к камере: ', error); }); '''); } }, )添加Info.plist权限描述
在ios/Runner/Info.plist中添加权限说明,否则iOS会拒绝权限请求:<key>NSCameraUsageDescription</key> <string>需要访问摄像头进行人脸识别验证</string> <key>NSMicrophoneUsageDescription</key> <string>需要访问麦克风进行语音验证</string> <key>NSLocationWhenInUseUsageDescription</key> <string>需要访问位置信息完成验证</string>
通用检查项
- 更新所有相关Flutter插件到最新稳定版:
webview_flutter、permission_handler、geolocator - 使用真机测试,避免模拟器的定位/摄像头模拟限制
- 确认Flask服务端的HTTPS配置有效,Web API(
getUserMedia、geolocation)要求页面运行在HTTPS环境(localhost除外)
内容的提问来源于stack exchange,提问作者Ердан Дуйсембиев
相关产品推荐
相关产品推荐

