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

Swift应用添加AVCaptureVideoPreviewLayer实现相机预览时显示黑屏如何解决

AVCaptureVideoPreviewLayer 黑屏问题排查方案

常见触发原因及修复方式

  • 相机权限未配置:iOS 要求访问相机前必须在 Info.plist 中添加 NSCameraUsageDescription 字段,配置权限申请的说明文案,未配置的情况下系统会拒绝相机访问,直接出现黑屏。
  • 预览图层尺寸未设置:你当前代码未给 previewLayer 设置大小,默认尺寸为0,无法正常渲染画面。需要将 previewLayer 的frame设置为和父容器的bounds一致,同时可设置 videoGravity 控制画面适配规则。
  • 捕获会话启动阻塞主线程:AVCaptureSession 的 startRunning() 是耗时操作,直接在主线程调用会阻塞UI渲染,需要放到后台串行队列执行。
  • 运行环境问题:模拟器不支持相机预览能力,必须使用真机调试。
  • 重复添加会话输入:viewWillAppear 会在页面每次展示时触发,多次调用会重复添加输入源导致会话异常,建议将会话配置逻辑移到 viewDidLoad 仅执行一次。

修正后的参考代码

var cameraInput : AVCaptureDeviceInput!
// 单独创建相机操作的串行队列,避免阻塞主线程
let cameraQueue = DispatchQueue(label: "com.yourapp.cameraQueue")
var videoSession : AVCaptureSession = AVCaptureSession()
var previewLayer : AVCaptureVideoPreviewLayer!

override func viewDidLoad() {
    super.viewDidLoad()
    setupCamera()
}

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    // 每次页面布局变更时更新预览层尺寸,适配横竖屏切换
    previewLayer.frame = view.bounds
}

func setupCamera() {
    // 先判断相机权限状态,未授权先申请权限
    switch AVCaptureDevice.authorizationStatus(for: .video) {
    case .notDetermined:
        AVCaptureDevice.requestAccess(for: .video) { [weak self] granted in
            if granted {
                self?.configureSession()
            }
        }
    case .authorized:
        configureSession()
    default:
        print("相机权限未开启")
        return
    }
}

func configureSession() {
    cameraQueue.async { [weak self] in
        guard let self = self else { return }
        // 配置会话前先判断是否已经在运行,避免重复配置
        guard !self.videoSession.isRunning else { return }
        
        guard let videoCamera = AVCaptureDevice.default(for: .video)
        else{
            print("Camera Device doesnt work")
            return
        }
        
        guard
            let cameraInput = try? AVCaptureDeviceInput(device: videoCamera),
            self.videoSession.canAddInput(cameraInput)
        else { return }
        self.videoSession.addInput(cameraInput)
        
        DispatchQueue.main.async {
            self.previewLayer = AVCaptureVideoPreviewLayer(session: self.videoSession)
            // 设置画面适配模式
            self.previewLayer.videoGravity = .resizeAspectFill
            self.previewLayer.frame = self.view.bounds
            self.view.layer.addSublayer(self.previewLayer)
            
            self.cameraQueue.async {
                self.videoSession.startRunning()
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Mr Astronaut

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 02:03:00