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

AVFoundation+SwiftUI自定义相机授权后仅显示白屏问题求助

自定义相机白屏及初始化错误问题

我花费数周尝试创建自定义相机,试过多种教程均未成功。目前代码结构看似合理,但在真机上授予相机权限后仅显示白屏。此前在setUp函数的let input = try AVCaptureDeviceInput(device: device)行曾出现致命错误,尝试可选绑定仍未解决。以下是我的代码及权限设置:

App 入口代码

import SwiftUI
import FirebaseCore

@main
struct FirebaseAuthYoutubeApp: App {
    @StateObject var viewModal = AuthViewModel()
    
    init() {
        FirebaseApp.configure()
    }
    
    
    var body: some Scene {
        WindowGroup {
           /* ContentView()
                .environmentObject(viewModal)
       */
            CameraView2()
        }
        
    }
}

相机实现代码

import SwiftUI
import AVFoundation
import UIKit


struct CamerVIEW2Kavsoft: View {
    var body: some View {
        Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
    }
}

struct CamerVIEW2Kavsoft_Previews: PreviewProvider {
    static var previews: some View {
        CameraView2()
    }
}

struct CameraView2: View {
    @StateObject var camera = cameraModel()
    var body: some View{
        ZStack{
            
            // 相机预览层
            CameraPreview(camera: camera)
                .ignoresSafeArea(.all, edges: .all)
            
            VStack{
                
                if camera.isTaken {
                    
                    HStack{
                        Spacer()
                        Button(action: camera.retaTake, label: {
                            Image(systemName: "arrow.triangle.2.circlepath.camera")
                                .foregroundColor(.black)
                                .padding()
                                .background(Color.white)
                                .clipShape(Circle())
                        })
                        .padding(.trailing,10)
                        
                    }
                }
                
                Spacer()
                
                HStack {
                    
                    // 拍照后显示保存和重拍按钮
                    if camera.isTaken {
                        
                        Button(action: {if !camera.isSaved{camera.savePic()}}, label: {
                            Text(camera.isSaved ? "已保存" : "保存")
                            .foregroundColor(.black)
                            .fontWeight(.semibold)
                            .padding(.vertical,10)
                            .padding(.horizontal,20)
                            .background(Color.white)
                            .clipShape(Capsule())
                               
                               })
                        .padding(.leading)
                        Spacer()
                        
                    } else {
                        
                        Button(action: {camera.takePic()}, label: {
                            
                            ZStack{
                                
                                Circle()
                                    .fill(Color.white)
                                    .frame(width: 65, height: 65)
                                
                                Circle()
                                    .stroke(Color.white, lineWidth: 2)
                                    .frame(width: 75, height: 75)
                            }
                            
                        })
                    }
                }
                .frame(height: 75)
            }
        }
        .onAppear(perform: {
            camera.Check()
        })
    }
}


// 相机模型类
class cameraModel: NSObject, ObservableObject,  AVCapturePhotoCaptureDelegate {
    @Published var isTaken = false
    @Published var session = AVCaptureSession()
    @Published var alert = false
    
    // 照片输出对象
    @Published var output = AVCapturePhotoOutput()
    
    // 预览层
    @Published var preview : AVCaptureVideoPreviewLayer!
    
    @Published var isSaved = false
    @Published var picData = Data(count: 0)
    
    
    func Check() {
        // 检查相机权限
        switch AVCaptureDevice.authorizationStatus(for:  .video) {
        case .authorized:
            // 权限已授权,初始化会话
            setUp()
            return
        case .notDetermined:
            // 未确定权限,请求授权
            AVCaptureDevice.requestAccess(for: .video) { (status) in
                if status {
                    self.setUp()
                }
            }
            
        case .denied:
            // 权限被拒绝,弹出提示
            self.alert.toggle()
            return
        default:
            return
            
        }
        
    }
    
    func setUp() {
        // 初始化相机会话
        do {
            // 开始配置会话
            self.session.beginConfiguration()
            
            // 获取后置双摄像头设备
            if let device = AVCaptureDevice.default(.builtInDualCamera, for: .video, position: .back) {
                
                do {
                    let input = try AVCaptureDeviceInput(device: device)
                    
                    // 检查并添加输入到会话
                    if self.session.canAddInput(input) {
                        self.session.addInput(input)
                    }
                } catch {
                    print(error.localizedDescription)
                }
                
                // 添加输出到会话
                if self.session.canAddOutput(self.output) {
                    self.session.addOutput(self.output)
                }
                
                self.session.commitConfiguration()
            }
        }catch {
                print(error.localizedDescription)
            }
        }
        
        // 拍照功能
        func takePic(){
            DispatchQueue.global(qos: .background).async {
                self.output.capturePhoto(with: AVCapturePhotoSettings(), delegate: self)
                self.session.stopRunning()
                
                DispatchQueue.main.async {
                    withAnimation{self.isTaken.toggle()}
                    self.isSaved = false
                }
            }
        }
        
        // 重拍功能
        func retaTake() {
            DispatchQueue.global(qos: .background).async {
                self.session.startRunning()
                
                DispatchQueue.main.async {
                    withAnimation{self.isTaken.toggle()}
                }
            }
        }
        
        
        func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
            if error != nil{
                return
            }
            
            print("照片已拍摄...")
            
            guard let imageData = photo.fileDataRepresentation() else {return}
            self.picData = imageData
        }
        
        // 保存照片到相册
        func savePic() {
            let image = UIImage(data: self.picData)!
            
            UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
            self.isSaved = true
            
            print("保存成功")
        }
    }
    
    // 相机预览视图
    struct CameraPreview: UIViewRepresentable {
        
        @ObservedObject var camera : cameraModel
        func makeUIView(context: Context) -> UIView {
            
            let view = UIView(frame: UIScreen.main.bounds)
            
            camera.preview = AVCaptureVideoPreviewLayer(session: camera.session)
            camera.preview.frame = view.frame
            
            camera.preview.videoGravity = .resizeAspectFill
            view.layer.addSublayer(camera.preview)
            
            // 启动会话
            camera.session.startRunning()
            
            return view
        }
        
        func updateUIView(_ uiView: UIView, context: Context) {
            
        }
    }

Info.plist 权限设置

权限设置


问题解决方法

  1. 设备适配问题:
    部分设备无builtInDualCamera(如单摄像头iPhone SE),需替换为通用后置摄像头获取逻辑:

    // 替换原设备获取代码
    guard let device = AVCaptureDevice.default(.video, for: .video, position: .back) ??
            AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) else {
        print("无法获取后置摄像头")
        return
    }
    
  2. 初始化致命错误修复:
    添加设备配置锁定逻辑,避免设备状态异常导致的初始化失败:

    do {
        try device.lockForConfiguration()
        device.activeVideoMinFrameDuration = CMTimeMake(value: 1, timescale: 30)
        device.activeVideoMaxFrameDuration = CMTimeMake(value: 1, timescale: 30)
        device.unlockForConfiguration()
        
        let input = try AVCaptureDeviceInput(device: device)
        if self.session.canAddInput(input) {
            self.session.addInput(input)
        }
    } catch {
        print("输入创建失败: \(error.localizedDescription)")
    }
    
  3. 会话启动时机调整:
    移除CameraPreview中的会话启动代码,在setUp配置完成后启动:

    // 在setUp函数的session.commitConfiguration()后添加
    DispatchQueue.global(qos: .userInitiated).async {
        self.session.startRunning()
    }
    

内容的提问来源于stack exchange,提问作者Carl Rudling

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 19:19:51