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

Swift实现iPad相机Picture in Picture(PiP)功能技术咨询

iPad 相机视图 PiP 功能简化实现方案(iOS 16+)

针对iOS 16及以上版本,无需模拟视频通话流程,直接通过AVFoundation结合AVKit的原生API就能实现相机画面的画中画(PiP)功能,步骤如下:

核心优势

  • 无需依赖CallKit或模拟通话状态,完全基于原生相机捕获+PiP API实现
  • 自定义程度高,可直接控制相机参数、预览界面
  • 适配iOS 16+的简化PiP逻辑,代码量少

实现步骤

1. 配置权限与后台模式

  • 在Info.plist中添加NSCameraUsageDescription字段,填写相机使用说明(如"用于显示相机画面的画中画功能")
  • 在项目后台模式中开启Audio, AirPlay, and Picture in Picture(确保PiP活跃时相机可在后台持续捕获)

2. 代码实现

导入依赖框架

import AVFoundation
import AVKit

定义核心属性

class CameraPiPViewController: UIViewController {
    private var captureSession: AVCaptureSession!
    private var previewLayer: AVCaptureVideoPreviewLayer!
    private var pipController: AVPictureInPictureController?

初始化相机与PiP控制器

func setupCameraAndPiP() {
    // 请求相机权限
    AVCaptureDevice.requestAccess(for: .video) { [weak self] granted in
        guard granted, let self = self else { return }
        DispatchQueue.main.async {
            // 初始化捕获会话
            self.captureSession = AVCaptureSession()
            self.captureSession.sessionPreset = .hd1280x720 // 按需选择分辨率
            
            // 添加前置相机输入
            guard let camera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .front) else { return }
            guard let input = try? AVCaptureDeviceInput(device: camera) else { return }
            
            if self.captureSession.canAddInput(input) {
                self.captureSession.addInput(input)
            }
            
            // 创建预览层并添加到视图
            self.previewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession)
            self.previewLayer.frame = self.view.bounds
            self.previewLayer.videoGravity = .resizeAspectFill
            self.view.layer.addSublayer(self.previewLayer)
            
            // 利用预览层的PiP源初始化控制器(iOS 16+新增特性)
            if let pipSource = self.previewLayer.pictureInPictureSource {
                self.pipController = AVPictureInPictureController(pictureInPictureSource: pipSource)
                self.pipController?.delegate = self
            }
            
            // 启动相机捕获
            self.captureSession.startRunning()
        }
    }
}

触发PiP功能(示例:按钮点击)

@IBAction func togglePiP(_ sender: UIButton) {
    guard let pipController = pipController, pipController.isPictureInPictureSupported else { return }
    
    if pipController.isPictureInPictureActive {
        pipController.stopPictureInPicture()
    } else {
        pipController.startPictureInPicture()
    }
}

实现PiP代理(处理状态变化)

extension CameraPiPViewController: AVPictureInPictureControllerDelegate {
    func pictureInPictureControllerDidStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
        // PiP启动后可隐藏本地预览层
        previewLayer.isHidden = true
    }
    
    func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
        // PiP停止后恢复本地预览
        previewLayer.isHidden = false
    }
}

3. 关键说明

  • 无需使用UIImagePickerController:该系统控制器为封装实现,无法获取内部捕获会话或预览层,不支持自定义PiP扩展
  • iOS 16+的核心简化点:AVCaptureVideoPreviewLayer新增pictureInPictureSource属性,直接作为PiP控制器的数据源,无需额外转换视频流
  • 后台运行保障:PiP活跃时,系统会自动维持相机捕获会话的后台运行状态,无需额外复杂配置

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 11:45:57