ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Flutter Camera 插件(camera 包)完整接入指南:相机预览、拍照录像、图像流与权限生命周期管理

Flutter Camera 插件(camera 包)完整接入指南:相机预览、拍照录像、图像流与权限生命周期管理 Flutter Camera 插件camera 包完整接入指南相机预览、拍照录像、图像流与权限生命周期管理【免费下载链接】packagesA collection of useful packages maintained by the Flutter team项目地址: https://gitcode.com/GitHub_Trending/pac/packages本篇技术指南以 Flutter 团队官方维护的camera插件位于本仓库packages/camera/camera为对象系统讲解如何在 Android、iOS、Web 三端快速接入摄像头能力从平台工程配置Info.plist 权限声明、CameraX/Camera2 后端选型、核心 API 调用链availableCameras→CameraController.initialize→CameraPreview到拍照、录像、Dart 侧图像流、生命周期释放与六类权限错误码的完整处理方案。读完本文你将能够基于本仓库源码搭建一个可运行的全屏相机应用并理解其底层平台分发机制与各控制接口的实现细节。一、插件概览与平台支持camera是 Flutter 官方插件federated plugin即联邦插件架构用于访问设备摄像头支持 iOS、Android 与 Web 三大平台。其定位与核心能力见 README 与 pubspec.yaml 中的描述控制相机、预览相机画面、采集图像与视频并将图像缓冲区流式传输到 Dart 层。平台支持矩阵平台支持范围AndroidSDK 24iOSiOS 13.0Web见camera_web包camera_web 实现从 pubspec.yaml 可以看出该插件采用联邦分发策略各平台由独立实现包承接flutter: plugin: platforms: android: default_package: camera_android_camerax ios: default_package: camera_avfoundation web: default_package: camera_web dependencies: camera_android_camerax: ^0.7.4 camera_avfoundation: ^0.10.2 camera_platform_interface: ^2.13.1 camera_web: ^0.3.3 flutter_plugin_android_lifecycle: ^2.0.2即Android 默认走 camera_android_camerax基于 CameraXiOS 走 camera_avfoundation基于 AVFoundationWeb 走 camera_web。作为 Flutter 团队维护的官方插件其版本约束为 SDK^3.12.0、Flutter3.44.0以当前仓库pubspec.yaml为准。核心功能特性根据 README 的 Features 一节插件提供四项核心能力实时相机预览在 Widget 中展示实时相机画面拍照捕获快照并保存为文件录像录制视频图像流从 Dart 侧访问相机图像流逐帧回调。二、环境准备与依赖安装在你的 Flutter 项目pubspec.yaml中添加依赖dependencies: camera: ^0.12.1camera是 endorsed官方背书联邦插件只需依赖这一个包各平台实现包会在构建时自动解析引入。添加依赖后执行flutter pub get即可。三、平台工程配置iOSInfo.plist 权限声明在ios/Runner/Info.plist中添加两行配置Privacy - Camera Usage Description键NSCameraUsageDescription相机使用用途说明Privacy - Microphone Usage Description键NSMicrophoneUsageDescription麦克风使用用途说明录像需要音频。以文本方式编辑Info.plist时加入如下 XML 片段来自 READMEkeyNSCameraUsageDescription/key stringyour usage description here/string keyNSMicrophoneUsageDescription/key stringyour usage description here/string说明iOS 在应用访问相机/麦克风前必须声明用途字符串否则系统会直接终止应用。即使你的功能不需要录音也建议一并声明麦克风用途因为录像 API 默认enableAudio true。AndroidCameraX 与 Camera2 后端选型Android 端默认使用 camera_android_camerax基于 CameraX实现它对更多设备有更好的兼容性但存在一些局限性例如对部分设备的支持限制详见该包 README 的 limitations 列表。如果希望使用基于 Camera2 的 camera_android 实现该实现不包含 CameraX 的那些限制需按照该包 README 的 Usage 说明进行配置替换。此外若希望在应用退到后台时仍允许图像流image streaming还需要额外的配置步骤具体见 camera_android_camerax 的后台图像流说明。补充当前仓库中同时维护了camera_android_cameraxCameraX与camera_androidCamera2两套 Android 实现二者目录并列于packages/camera/下可根据设备兼容性需求选择。Web 集成Web 平台的实现细节请参考 camera_web 包 的 README其中包含 Web 平台特有的限制说明如部分 API 不可用、图像格式差异等。四、核心 API 与标准使用流程camera包的公开 API 统一从 lib/camera.dart 导出它重新导出了平台接口层的核心类型CameraDescription、CameraException、CameraLensDirection、CameraLensType、ExposureMode、FlashMode、FocusMode、ImageFormatGroup、ResolutionPreset、VideoStabilizationMode、XFile以及CameraController、CameraImage、CameraPreview三个核心类。标准的使用链路分为四步1. 枚举可用摄像头availableCameras()final ListCameraDescription cameras await availableCameras();该函数在源码中实现为对平台接口的一层薄封装camera_controller.dartFutureListCameraDescription availableCameras() async { return CameraPlatform.instance.availableCameras(); }它返回设备上所有可用摄像头的描述列表每个CameraDescription包含摄像头标识、lensDirection前摄front、后摄back、外接external见 camera_description.dart等信息。初始化失败时可能抛出CameraException。2. 创建控制器CameraControllerfinal CameraController controller CameraController( cameras[0], // 选定的摄像头描述 ResolutionPreset.max, // 分辨率预设 );CameraController继承自ValueNotifierCameraValuecamera_controller.dart因此可以通过监听其valueCameraValue类型来响应状态变化。构造函数支持以下参数参数默认值说明description必填摄像头描述对象resolutionPreset必填分辨率预设影响录像与拍照质量enableAudiotrue录制的视频是否包含音频fpsnull帧率帧/秒若提供则覆盖分辨率预设的设置videoBitratenull视频编码比特率若提供则覆盖分辨率预设audioBitratenull音频编码比特率若提供则覆盖分辨率预设imageFormatGroupnull原始图像格式为null时回退到平台默认格式ResolutionPreset是一个目标分辨率不保证精确——设备不支持时平台实现会回退到更高或更低分辨率。其定义见 resolution_preset.dartenum ResolutionPreset { low, // iOS 上 352x288Android/Web 约 240p medium, // 约 480p high, // 约 720p veryHigh, // 约 1080p ultraHigh, // 约 2160p max, // 设备支持的最高分辨率 }3. 初始化controller.initialize()await controller.initialize();初始化成功后controller.value.isInitialized变为truevalue.previewSize携带预览尺寸。从源码camera_controller.dart可见其内部依次完成订阅设备方向变化事件onDeviceOrientationChanged通过CameraPlatform.instance.createCameraWithSettings创建相机会话等待onCameraInitialized事件调用initializeCamera并更新CameraValue设置isInitialized、previewSize、exposureMode、focusMode等状态。4. 展示预览CameraPreviewWidget build(BuildContext context) { if (!controller.value.isInitialized) { return Container(); } return CameraPreview(controller); }CameraPreview是展示实时相机画面的 Widgetcamera_preview.dart。从源码可以看到它内部通过ValueListenableBuilder监听控制器状态根据方向自动计算AspectRatio并且在 Android 上使用RotatedBox按设备方向旋转预览画面_wrapInRotatedBox、_getQuarterTurns方法确保竖屏/横屏下预览方向正确。五、拍照takePicture()控制器初始化完成后即可调用拍照final XFile file await controller.takePicture();返回的XFile指向保存图片的文件可配合Image.file移动端或Image.networkWeb见示例代码中的注释说明展示若上一次拍照尚未返回就再次调用会抛出CameraExceptioncode 为Previous capture has not returned yet.见 camera_controller.dart拍照期间value.isTakingPicture为true可调用setJpegImageQuality(int quality)设置 JPEG 压缩质量1~100仅对 JPEG 格式生效不支持时平台会忽略而不是抛错。六、录像startVideoRecording / stopVideoRecording// 开始录制 await controller.startVideoRecording(); // 结束录制返回视频文件 final XFile videoFile await controller.stopVideoRecording();关键细节camera_controller.dartstartVideoRecording({onAvailable, enablePersistentRecording true})可传入onAvailable回调将视频帧同时流式传给该回调enablePersistentRecording默认true表示持久录制——只能通过显式调用stopVideoRecording停止且会忽略生命周期事件、录制期间的setDescription等通常会导致录制停止的事件目前仅在 Android 上生效pauseVideoRecording()/resumeVideoRecording()暂停/恢复录制仅 iOS 与 Android SDK 24 可用录制状态可通过value.isRecordingVideo、value.isRecordingPaused判断iOS 上可提前调用prepareForVideoRecording()预准备录制会话以消除开始录像时的预览卡顿该操作在 Android 与 Web 上是 no-op。七、Dart 侧图像流startImageStream若需要对每一帧图像做实时处理如扫码、目标检测可使用图像流await controller.startImageStream((CameraImage image) { // 处理每一帧图像 });源码要点camera_controller.dart回调类型为onLatestImageAvailable始终返回最新一帧中间帧会被丢弃需要先通过supportsImageStreaming()确认平台支持与CameraPreview同时运行时建议使用ResolutionPreset.lowhigh及以上在低端设备上会造成预览明显掉帧图像流进行中不可同时录像会抛异常停止用stopImageStream()回调中的CameraImagecamera_image.dart包含format图像格式、width/height、planes像素平面列表含字节数据与行距bytesPerRow等布局信息以及lensAperture、sensorExposureTime、sensorSensitivity等元数据注意它不是可直接用于 UI 展示的资源。八、生命周期状态处理重要从0.5.0 版本起插件不再自动处理生命周期变化开发者必须自行控制相机资源的创建与释放否则可能导致异常行为。推荐通过混入WidgetsBindingObserver并重写didChangeAppLifecycleState来处理示例取自 example/lib/main.dart与 README 一致override void didChangeAppLifecycleState(AppLifecycleState state) { final CameraController? cameraController controller; // App state changed before we got the chance to initialize. if (cameraController null || !cameraController.value.isInitialized) { return; } if (state AppLifecycleState.inactive) { cameraController.dispose(); } else if (state AppLifecycleState.resumed) { _initializeCameraController(cameraController.description); } }处理要点进入inactive如来电、下拉通知栏、切后台时dispose()释放相机资源回到resumed时基于保存的description重新初始化控制器每次重建前务必检查isInitialized避免对未初始化控制器误操作dispose()是幂等的源码中_isDisposed标志保证重复调用安全返回且会取消设备方向订阅并释放平台侧相机资源camera_controller.dart。九、相机访问权限与错误处理初始化相机控制器时可能抛出权限错误开发者应当妥善处理。CameraExceptioncamera_exception.dart由code与description构成以下是可能出现的全部权限错误码README错误码触发场景CameraAccessDenied用户拒绝相机访问权限CameraAccessDeniedWithoutPrompt目前仅 iOS用户此前已拒绝过权限iOS 不允许二次弹出授权弹窗用户需前往设置 隐私 相机手动开启CameraAccessRestricted目前仅 iOS相机访问受限制用户无法授权如家长控制AudioAccessDenied用户拒绝音频访问权限AudioAccessDeniedWithoutPrompt目前仅 iOS用户此前已拒绝过音频权限需前往设置 隐私 麦克风手动开启AudioAccessRestricted目前仅 iOS音频访问受限制用户无法授权如家长控制在官方示例 example/lib/main.dart 中针对上述每种错误码都给出了对应的 UI 反馈策略} on CameraException catch (e) { switch (e.code) { case CameraAccessDenied: showInSnackBar(You have denied camera access.); case CameraAccessDeniedWithoutPrompt: // iOS only showInSnackBar(Please go to Settings app to enable camera access.); case CameraAccessRestricted: // iOS only showInSnackBar(Camera access is restricted.); case AudioAccessDenied: showInSnackBar(You have denied audio access.); case AudioAccessDeniedWithoutPrompt: // iOS only showInSnackBar(Please go to Settings app to enable audio access.); case AudioAccessRestricted: // iOS only showInSnackBar(Audio access is restricted.); default: _showCameraException(e); } }十、进阶控制能力CameraController还提供了丰富的拍摄控制接口全部定义于 camera_controller.dart可在实际应用中按需组合能力API说明闪光灯setFlashMode(FlashMode)off/auto/always/torch见 flash_mode.dart缩放getMinZoomLevel()/getMaxZoomLevel()/setZoomLevel(double)缩放值应在最小与最大之间超出会抛CameraException对焦setFocusMode(FocusMode)/setFocusPoint(Offset?)对焦点坐标为归一化值0,0~1,1null恢复默认曝光setExposureMode(ExposureMode)/setExposurePoint(Offset?)/getMinExposureOffset()/getMaxExposureOffset()/setExposureOffset(double)曝光偏移单位为 EV1 EV 表示亮度翻倍自动取整到最近步进防抖getSupportedVideoStabilizationModes()/setVideoStabilizationMode(mode, {allowFallback true})allowFallback为false且不支持指定模式时抛ArgumentError方向锁定lockCaptureOrientation([DeviceOrientation?])/unlockCaptureOrientation()不传参数时锁定当前设备方向预览暂停pausePreview()/resumePreview()支持手动暂停/恢复预览切换摄像头setDescription(CameraDescription)录像中调用时需配合持久录制Android官方示例 example/lib/main.dart 展示了这些能力的完整集成双指手势缩放_handleScaleUpdate中通过setZoomLevel实现、点击取景器同时对焦与测光onViewFinderTap中同时调用setExposurePoint与setFocusPoint、闪光灯/曝光/对焦模式切换面板、前后摄像头切换、拍摄缩略图展示等是学习生产级相机交互的绝佳参考。十一、完整可运行示例以下是 README 提供的最小全屏相机预览示例与 example/lib/readme_full_example.dart 完全一致import package:camera/camera.dart; import package:flutter/material.dart; late ListCameraDescription _cameras; Futurevoid main() async { WidgetsFlutterBinding.ensureInitialized(); _cameras await availableCameras(); runApp(const CameraApp()); } /// CameraApp is the Main Application. class CameraApp extends StatefulWidget { /// Default Constructor const CameraApp({super.key}); override StateCameraApp createState() _CameraAppState(); } class _CameraAppState extends StateCameraApp { late CameraController controller; override void initState() { super.initState(); controller CameraController(_cameras[0], ResolutionPreset.max); controller .initialize() .then((_) { if (!mounted) { return; } setState(() {}); }) .catchError((Object e) { if (e is CameraException) { switch (e.code) { case CameraAccessDenied: // Handle access errors here. break; default: // Handle other errors here. break; } } }); } override void dispose() { controller.dispose(); super.dispose(); } override Widget build(BuildContext context) { if (!controller.value.isInitialized) { return Container(); } return MaterialApp(home: CameraPreview(controller)); } }要点回顾WidgetsFlutterBinding.ensureInitialized()确保在runApp前完成平台通道初始化因为availableCameras()是异步的平台调用初始化完成后通过setState触发重建渲染CameraPreviewinitialize()失败时通过CameraException.code区分错误类型在dispose()中释放控制器。十二、测试与验证camera包在仓库中配有完整的 Dart 单元测试见 camera 包 test 目录覆盖控制器初始化、拍照、录像、图像流、生命周期释放、错误处理等核心路径平台层还有对应的原生单元测试如 camera_android_camerax 测试、camera_avfoundation 测试。你可以参考这些测试理解各 API 的预期行为与异常路径并在自己的项目中编写类似测试来验证相机功能的正确性。总结本文基于仓库中的 camera 包 及其 README完整覆盖了 Flutter 相机能力接入的全流程平台工程配置iOS 权限声明、Android CameraX/Camera2 选型、核心 API 调用链枚举摄像头 → 创建并初始化控制器 → 预览/拍照/录像/图像流、生命周期资源管理、六类权限错误码处理以及闪光灯、缩放、对焦、曝光等进阶控制。配合源码级说明读者既能获得开箱即用的实战代码也能理解每个接口背后的平台分发机制与状态模型从而在自己的 Flutter 应用中稳健地集成相机能力。【免费下载链接】packagesA collection of useful packages maintained by the Flutter team项目地址: https://gitcode.com/GitHub_Trending/pac/packages创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表