Flutter PIP 插件 ---- iOS Video Call

以下是一篇关于在 iOS 中实现画中画(PiP)功能的技术博客:

iOS 画中画(PiP)功能实现指南

简介

画中画(Picture in Picture, PiP)是一项允许用户在使用其他应用时继续观看视频内容的功能。本文将详细介绍如何在 iOS 应用中实现 PiP 功能。

系统要求

  • iOS 15.0 及以上版本
  • AVKit 框架

核心组件

实现 PiP 功能主要涉及以下几个核心组件:

  1. AVPictureInPictureController - 负责管理 PiP 会话
  2. AVPictureInPictureControllerContentSource - 定义 PiP 内容源
  3. AVPictureInPictureVideoCallViewController - 控制 PiP 窗口的视图控制器

实现步骤

1. 检查设备支持

首先需要检查设备是否支持 PiP 功能:

objc 复制代码
- (BOOL)isSupported {
    if (@available(iOS 15.0, *)) {
        return [AVPictureInPictureController isPictureInPictureSupported];
    }
    return NO;
}

2. 创建 PiP 视图

需要创建一个自定义视图来显示 PiP 内容:

objc 复制代码
@interface PipView : UIView
@end

@implementation PipView
+ (Class)layerClass {
    return [AVSampleBufferDisplayLayer class];
}
@end

3. 配置 PiP 控制器

设置 PiP 控制器需要以下步骤:

objc 复制代码
- (BOOL)setup:(PipOptions *)options {
    if (!self.isSupported) {
        return NO;
    }
    
    if (@available(iOS 15.0, *)) {
        // 创建 PiP 视图
        _pipView = [[PipView alloc] init];
        
        // 创建视图控制器
        AVPictureInPictureVideoCallViewController *pipViewController = 
            [[AVPictureInPictureVideoCallViewController alloc] init];
        pipViewController.preferredContentSize = options.preferredContentSize;
        [pipViewController.view addSubview:_pipView];
        
        // 创建内容源
        AVPictureInPictureControllerContentSource *contentSource =
            [[AVPictureInPictureControllerContentSource alloc]
                initWithActiveVideoCallSourceView:options.sourceContentView
                contentViewController:pipViewController];
                
        // 初始化 PiP 控制器
        _pipController = [[AVPictureInPictureController alloc]
            initWithContentSource:contentSource];
        _pipController.delegate = self;
        _pipController.canStartPictureInPictureAutomaticallyFromInline = 
            options.autoEnterEnabled;
            
        return YES;
    }
    
    return NO;
}

4. 控制 PiP 会话

启动 PiP:
objc 复制代码
- (BOOL)start {
    if (!self.isSupported) {
        return NO;
    }
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 0.1),
        dispatch_get_main_queue(), ^{
            if (self->_pipController.isPictureInPicturePossible) {
                [self->_pipController startPictureInPicture];
            }
    });
    
    return YES;
}
停止 PiP:
objc 复制代码
- (void)stop {
    if (self->_pipController.isPictureInPictureActive) {
        [self->_pipController stopPictureInPicture];
    }
}
释放资源:
objc 复制代码
- (void)dispose {
    if (@available(iOS 15.0, *)) {
        self->_pipController.contentSource = nil;
    }
    
    if (self->_isPipActived) {
        self->_isPipActived = NO;
        [self->_pipStateDelegate pipStateChanged:PipStateStopped error:nil];
    }
}

5. 实现状态回调

通过实现 AVPictureInPictureControllerDelegate 协议来处理 PiP 状态变化:

objc 复制代码
- (void)pictureInPictureControllerDidStartPictureInPicture:
    (AVPictureInPictureController *)pictureInPictureController {
    _isPipActived = YES;
    [_pipStateDelegate pipStateChanged:PipStateStarted error:nil];
}

- (void)pictureInPictureControllerDidStopPictureInPicture:
    (AVPictureInPictureController *)pictureInPictureController {
    _isPipActived = NO;
    [_pipStateDelegate pipStateChanged:PipStateStopped error:nil];
}

- (void)pictureInPictureController:
    (AVPictureInPictureController *)pictureInPictureController
    failedToStartPictureInPictureWithError:(NSError *)error {
    [_pipStateDelegate pipStateChanged:PipStateFailed error:error.description];
}

注意事项

  1. PiP 功能仅支持 iOS 15.0 及以上版本
  2. 启动 PiP 时需要适当延迟以确保正常显示
  3. 自动进入 PiP 模式需要在 setup 时配置 autoEnterEnabled 选项
  4. 释放资源时建议使用 contentSource = nil 而不是直接调用 stopPictureInPicture
  5. PiP 窗口的默认大小建议设置为至少 100x100,否则可能导致启动失败

最佳实践

  1. 在初始化时检查设备是否支持 PiP 功能
  2. 实现适当的错误处理和状态回调
  3. 在应用进入后台时,如果启用了自动进入选项,PiP 会自动启动
  4. 注意内存管理,及时释放不需要的资源

总结

iOS 的 PiP 功能实现主要依赖于 AVKit 框架,通过合理配置 AVPictureInPictureController 及其相关组件,可以为用户提供流畅的画中画体验。在实现过程中需要注意版本兼容性、状态管理和资源释放等问题。

参考

PS

本次实现还不太全面,出来的PIP窗口只是一个背景黑色,还没有实现视频的显示,后续会持续更新。

相关推荐
RickeyBoy3 小时前
解决 Swift Testing 中 DI 容器的竞态条件
ios
键盘鼓手苏苏3 小时前
Flutter 三方库 p2plib 的鸿蒙化适配指南 - 实现高性能的端到端(P2P)加密通讯、支持分布式节点发现与去中心化数据流传输实战
flutter·harmonyos·鸿蒙·openharmony
加农炮手Jinx4 小时前
Flutter for OpenHarmony:postgrest 直接访问 PostgreSQL 数据库的 RESTful 客户端(Supabase 核心驱动) 深度解析与鸿蒙适配指南
数据库·flutter·华为·postgresql·restful·harmonyos·鸿蒙
加农炮手Jinx4 小时前
Flutter 组件 heart 适配鸿蒙 HarmonyOS 实战:分布式心跳监控,构建全场景保活检测与链路哨兵架构
flutter·harmonyos·鸿蒙·openharmony
钛态4 小时前
Flutter 三方库 http_mock_adapter — 赋能鸿蒙应用开发的高效率网络接口 Mock 与自动化测试注入引擎(适配鸿蒙 HarmonyOS Next ohos)
android·网络协议·flutter·http·华为·中间件·harmonyos
王码码20354 小时前
Flutter for OpenHarmony:Flutter 三方库 algoliasearch 毫秒级云端搜索体验(云原生搜索引擎)
android·前端·git·flutter·搜索引擎·云原生·harmonyos
王码码20354 小时前
Flutter 三方库 dns_client 的鸿蒙化适配指南 - 告别 DNS 劫持、探索 DNS-over-HTTPS (DoH) 技术、构建安全的鸿蒙网络请求环境
flutter·harmonyos·鸿蒙·openharmony·dns_client
键盘鼓手苏苏4 小时前
Flutter 组件 highlighter 适配鸿蒙 HarmonyOS 实战:高性能语法高亮,构建大规模代码分析与文本染色架构
flutter·harmonyos·鸿蒙·openharmony
国医中兴4 小时前
Flutter 三方库 langchain_google 的鸿蒙化适配指南 - 链接 Gemini 智慧中枢、LangChain AI 实战、鸿蒙级智能应用专家
flutter·langchain·harmonyos
左手厨刀右手茼蒿4 小时前
Flutter for OpenHarmony: Flutter 三方库 shamsi_date 助力鸿蒙应用精准适配波斯历法(中东出海必备)
android·flutter·ui·华为·自动化·harmonyos