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

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 定位问题修复

  1. 启用WebView定位支持
    取消Android端代码中androidController.setGeolocationEnabled(true);的注释,显式开启WebView的定位功能。

  2. 同步权限请求与WebView初始化
    当前_requestPermissions()和_initializeWebView()并行执行,可能导致WebView初始化时权限未获取完成。修改initState为异步初始化:

    @override
    void initState() {
      super.initState();
      _init();
    }
    
    Future<void> _init() async {
      await _requestPermissions();
      _initializeWebView();
      setState(() {});
    }
    
  3. 完善定位注入逻辑
    补充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}});
      };
    ''');
    
  4. 检查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 摄像头问题修复

  1. 延迟执行摄像头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);
            });
          ''');
        }
      },
    )
    
  2. 添加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,提问作者Ердан Дуйсембиев

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 14:02:08