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

Flutter camera包iOS端权限变更致应用崩溃问题求助

解决Flutter camera包iOS权限修改后崩溃问题

问题分析

iOS系统在应用后台修改相机权限后,会强制应用重新处理相关硬件资源。camera包官方示例未适配这种场景下的相机资源释放与重新初始化逻辑,导致非法访问相机资源触发SIGKILL崩溃。

解决方案

1. 监听应用生命周期,前台回调重置相机

在Flutter层通过WidgetsBindingObserver监听应用回到前台的事件,此时先释放旧相机资源,再重新检查权限并初始化相机:

class CameraPage extends StatefulWidget {
  @override
  _CameraPageState createState() => _CameraPageState();
}

class _CameraPageState extends State<CameraPage> with WidgetsBindingObserver {
  CameraController? _controller;
  List<CameraDescription>? _cameras;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    _initCamera();
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    _controller?.dispose();
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    // 应用回到前台时重置相机
    if (state == AppLifecycleState.resumed) {
      _resetCamera();
    }
  }

  Future<void> _initCamera() async {
    final status = await Permission.camera.status;
    if (status.isGranted) {
      _cameras = await availableCameras();
      _controller = CameraController(
        _cameras![0],
        ResolutionPreset.medium,
      );
      await _controller?.initialize();
      if (mounted) setState(() {});
    }
  }

  Future<void> _resetCamera() async {
    // 必须先释放旧控制器,避免资源冲突
    await _controller?.dispose();
    // 重新初始化相机
    await _initCamera();
  }

  // 引导用户前往设置的逻辑
  void _openAppSettings() async {
    await openAppSettings();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _controller?.value.isInitialized == true
          ? CameraPreview(_controller!)
          : Center(
              child: ElevatedButton(
                onPressed: _openAppSettings,
                child: const Text("前往设置开启相机权限"),
              ),
            ),
    );
  }
}

2. 原生层补充权限变化监听(可选)

如果Flutter层监听不够及时,可在iOS的AppDelegate中添加系统权限通知监听,通过MethodChannel通知Flutter层重置相机:

import UIKit
import Flutter
import AVFoundation

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    
    // 监听相机设备连接/断开通知(权限变化会触发此类通知)
    NotificationCenter.default.addObserver(
      self,
      selector: #selector(cameraPermissionChanged),
      name: NSNotification.Name.AVCaptureDeviceWasConnected,
      object: nil
    )
    NotificationCenter.default.addObserver(
      self,
      selector: #selector(cameraPermissionChanged),
      name: NSNotification.Name.AVCaptureDeviceWasDisconnected,
      object: nil
    )
    
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
  
  @objc func cameraPermissionChanged() {
    let channel = FlutterMethodChannel(name: "your.app.channel/camera_permission", binaryMessenger: window?.rootViewController as! FlutterBinaryMessenger)
    channel.invokeMethod("resetCamera", arguments: nil)
  }
}

在Flutter层注册MethodChannel接收通知:

@override
void initState() {
  super.initState();
  WidgetsBinding.instance.addObserver(this);
  // 注册MethodChannel
  const MethodChannel _channel = MethodChannel('your.app.channel/camera_permission');
  _channel.setMethodCallHandler((call) async {
    if (call.method == 'resetCamera') {
      await _resetCamera();
    }
  });
  _initCamera();
}

3. 强化权限检查逻辑

确保在初始化相机前严格校验权限状态,避免未授权时尝试访问相机资源,推荐使用permission_handler包进行权限管理。

关键注意事项

  • 每次重置相机必须先释放旧的CameraController,再创建新实例,避免硬件资源占用冲突
  • 权限变化后不可复用原有相机实例,必须重新获取相机列表并初始化
  • 操作UI前检查mounted状态,避免页面销毁后执行无效更新

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 13:04:58