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

Flutter拒绝相机权限后权限弹窗反复弹出问题求助

解决qr_code_scanner拒绝相机权限后弹窗反复弹出的问题

问题分析

拒绝相机权限后弹窗反复弹出的核心原因:你仅调用Navigator.pop(context)退出页面,但QRViewController仍在后台尝试获取相机资源,持续触发系统权限请求弹窗。

解决方案1:修改权限回调逻辑,先释放控制器再退出

在_onPermissionSet方法中,先终止相机相关操作,再执行页面退出:

_onPermissionSet(
  BuildContext context,
  QRViewController ctrl,
  bool permissionGranted,
) async {
  if (!permissionGranted) {
    // 释放控制器,停止相机资源请求,避免重复触发权限弹窗
    await ctrl.dispose();
    Navigator.pop(context);
  } else {
    await controller?.resumeCamera();
  }
}

同时补充页面销毁时的控制器释放逻辑,防止内存泄漏:

@override
void dispose() {
  controller?.dispose();
  super.dispose();
}

解决方案2:手动管理相机权限,从根源拦截重复请求

使用permission_handler插件手动控制权限流程,仅当权限允许时才加载QRView:

步骤1:添加依赖

在pubspec.yaml中加入:

dependencies:
  permission_handler: ^10.2.0

步骤2:修改页面逻辑

import 'package:permission_handler/permission_handler.dart';

class QRScannerPage extends StatefulWidget {
  @override
  _QRScannerPageState createState() => _QRScannerPageState();
}

class _QRScannerPageState extends State<QRScannerPage> {
  final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
  QRViewController? controller;
  bool _hasCameraPermission = false;

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

  Future<void> _checkCameraPermission() async {
    final status = await Permission.camera.request();
    setState(() {
      _hasCameraPermission = status.isGranted;
    });
  }

  @override
  Widget build(BuildContext context) {
    if (!_hasCameraPermission) {
      return Scaffold(
        appBar: AppBar(title: const Text('扫码')),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              const Text('需要相机权限才能扫码'),
              ElevatedButton(
                onPressed: () async {
                  await openAppSettings();
                  await _checkCameraPermission();
                },
                child: const Text('去设置开启权限'),
              ),
            ],
          ),
        ),
      );
    }

    return Scaffold(
      body: QRView(
        key: qrKey,
        onQRViewCreated: _onQRViewCreated,
        overlay: QrScannerOverlayShape(
          borderColor: AppColors.APP_PRIMARY_COLOR,
          borderRadius: AppSizeConstants.size10,
          borderLength: AppSizeConstants.size30,
          borderWidth: AppSizeConstants.size10,
          cutOutSize: 300.0,
        ),
        onPermissionSet: (ctrl, permission) async =>
            await _onPermissionSet(context, ctrl, permission),
      ),
    );
  }

  void _onQRViewCreated(QRViewController controller) {
    setState(() {
      this.controller = controller;
    });
    controller.scannedDataStream.listen((scanData) {
      final qrValue = scanData?.code ?? "";
      print("Scanned Data is:$qrValue");
      controller.pauseCamera();
      Navigator.pop(context, qrValue);
    });
  }

  _onPermissionSet(
    BuildContext context,
    QRViewController ctrl,
    bool permissionGranted,
  ) async {
    if (!permissionGranted) {
      await ctrl.dispose();
      Navigator.pop(context);
    } else {
      await controller?.resumeCamera();
    }
  }

  @override
  void dispose() {
    controller?.dispose();
    super.dispose();
  }
}

方案说明

  • 方案1通过释放控制器彻底终止相机请求,避免系统重复弹窗;
  • 方案2通过手动权限管理,完全掌控权限请求流程,从根源避免插件内部的重复请求逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 07:10:24