Flutter - Android Web 查看摄像头、麦克风和位置权限问题

问题描述 投票:0回答:1

我创建了一个网络视频聊天应用程序,在拨打电话之前需要获得访问摄像头、麦克风和位置的权限。该应用程序在 Chrome 和 Firefox 等浏览器中运行良好。问题是我正在尝试使用 Android WebView 将此 Web 应用程序集成到 Android 应用程序中。即使在 Web 视图中授予相机、麦克风和位置的权限后,我在打开 Web 应用程序时仍收到“访问被拒绝”错误。我尝试更新 AndroidManifest.xml 文件并使用permission_handler 包,但错误仍然存在。我是 Flutter 新手,希望能帮助解决这个问题。

代码语言:Flutter

pubspec.yaml webview_flutter:^4.10.0 webview_flutter_android:^4.0.1 webview_flutter_wkwebview:^3.16.1 webview_flutter_web:^0.2.3+3 权限处理程序:^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');
    }
  }
}

android flutter webview android-webview hybrid-mobile-app
1个回答
0
投票

您似乎已经做了很多正确的事情,将摄像头、麦克风和位置权限与 Flutter 应用程序中的 WebView 集成,但有几个关键点需要解决。以下是解决该问题的一些可能的解决方案和建议:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

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

您需要在WebView设置中启用权限请求并 使用 WebViewClient 处理它们。

WebViewController.dart

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

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

    final controller = WebViewController();

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

    // Enable media permissions (camera, microphone, etc.) in WebView
    await controller.setMediaPlaybackRequiresUserGesture(false);
    await controller.setAllowUniversalAccessFromFileURLs(true);
    
    // Handle permission requests from the WebView
    await controller.setPermissionRequestHandler(
      (controller, request) async {
        // Automatically accept camera and microphone requests
        if (request.origin == 'https://your-web-app-url.com') {
          if (request.permissions.contains(Permission.camera)) {
            controller.grantPermission(Permission.camera);
          }
          if (request.permissions.contains(Permission.microphone)) {
            controller.grantPermission(Permission.microphone);
          }
        }
        return true;
      }
    );
    
    await controller.loadRequest(Uri.parse(url));
    return controller;
  }

  static Future<void> _requestPermissions() async {
    final statusCamera = await Permission.camera.request();
    final statusMicrophone = await Permission.microphone.request();
    final statusLocation = await Permission.location.request();
    
    if (statusCamera.isGranted && statusMicrophone.isGranted && statusLocation.isGranted) {
      print('Permissions granted');
    } else {
      print('Permissions denied');
      // Optionally, show a dialog to direct users to settings to manually grant permissions
    }
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.