美文网首页
iOS14 画中画调研

iOS14 画中画调研

作者: 生产八哥 | 来源:发表于2021-09-25 18:23 被阅读0次

    iOS14 画中画 调研

    画中画(PictureInPicture)在iOS9就已经推出了,不过之前都只能在iPad使用,iPhone要使用画中画就得更新到iOS14才能使用。

    苹果在iOS14中开放了手机端对画中画的支持,方便在app退出前台时仍然可以播放视频。 画中画的开启,本质上还是需要依赖系统播放器,同时UI、动画等都是系统原生提供的,因此自定义空间很小。

    目前有三种方式实现画中画:

    • WKWebView自带
    • 如果对播放器要求不大的可以直接使用AVPlayerViewController,自身就提供画中画功能可直接使用,设置allowsPictureInPicturePlayback = YES即可展示出画中画按钮。
    • 自定义的播放器要开启画中画那就使用AVPictureInPictureController来包装,也是很简单易用,并且动画效果内部已经实现,只需要注意画中画按钮需要用户自己去实现,画中画图标系统已有相关APIpictureInPictureButtonStartImage

    总共需要以下几步:

    • 开启后台模式,即Xcode中后台能力中的第一个勾选框

    • 创建AVPictureInPictureController(你一定要让用户通过操作(点击按钮等)来开始画中画显示。 不能直接在代码中直接startPictureInPicture ,这样的话你的APP上架审核会被拒绝,因为苹果本身是不希望用户自定义画中画的。)

    • [AVPictureInPictureController isPictureInPictureSupported]允许的情况下,设置AVAudioSession的category为AVAudioSessionCategoryPlayback

    • 可以播放遵守HLS协议的.m3u8的直播

    • 如果业务使用系统播放器,那么这里一般不会有问题,因为播放器已经正确显示了。但是如果业务使用了自定义播放器,同时也希望具有画中画能力,那么通常会创建一个隐藏的系统播放器,作为画中画功能的承载。这时候就要注意保证用于渲染的view、layer正确地加入到了层级中

    具体代码如下:

    // init player
        NSURL *url = [NSURL URLWithString:@"https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8"];
        //使用playerItem初始化AVPlayer的目的是为了监听播放器的`status`状态
        self.playerItem = [AVPlayerItem playerItemWithURL:url];
        [self.playerItem addObserver:self
                     forKeyPath:@"status"
                        options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew
                        context:nil];
        self.player = [[AVPlayer alloc] initWithPlayerItem:self.playerItem ];
        
        // init player layer
        AVPlayerLayer * playerLayer = (AVPlayerLayer *)self.playerView.layer;
        playerLayer.player = self.player;
        
        // init pip controller
        self.pipController = [[AVPictureInPictureController alloc] initWithPlayerLayer:playerLayer];
        self.pipController.delegate = self;
        //监听'pictureInPicturePossible'是为了让自定义的画中画按钮是否显示/隐藏 或者 能否点击,因为有些时候即使设备支持,但是需要AVPlayer等到直播流可以播放的一个状态才可以为possible
        [self.pipController addObserver:self
                             forKeyPath:@"pictureInPicturePossible"
                                options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew
                                context:nil];
    
       if ([AVPictureInPictureController isPictureInPictureSupported]) {
            NSLog(@"该设备支持画中画功能");
            //开启画中画后台声音权限
            NSError *error = nil;
            [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
            [[AVAudioSession sharedInstance] setActive:YES error:nil];
            if (error) {
                NSLog(@"请求权限失败的原因为%@",error);
            }
        } else {
            NSLog(@"该设备不支持画中画功能");
        }
        
        //在点击画中画按钮的时候 开启画中画
         if (self.pipController.isPictureInPictureActive) {
            [self.pipController stopPictureInPicture];
        } else {
            [self.pipController startPictureInPicture];
        }
        
        //status状态一共三种 可以在不同的状态下设置不同的交互
        AVPlayerItemStatusReadyToPlay:
        AVPlayerItemStatusFailed:
        AVPlayerItemStatusUnknown:
        
    

    注意点:
    一、 AVPictureInPictureController的初始化通过将要展示视频的视图的view的 AVPlayerLayer来初始化。为了达到这种目的视频播放的视图的layer返回应该是AVPlayerLayer,重写+layerClass方法使得在创建的时候能返回一个不同的图层子类。UIView会在初始化的时候调用+layerClass方法,然后用它的返回类型来创建宿主图层。即需要在展示视频的view视图里有如下类方法

    + (Class)layerClass {
        return [AVPlayerLayer class];
    }
    

    二、 startPictureInPicture并不是立马触发,而是需要在视频可以开始播放时才允许打开。所以如果不加载一个本地加载的动画视频的话,界面上不会立马显示出画中画,给用户造成一种不灵敏的感觉。所以 先循环播放一个本地的 loading 视频来开启画中画,同时等待直播可以开始播放时,再将画中画的画面切换成真正的直播内容。

    三、 因为AVPlayer只能播放本地视频或者HLS直播流,而AVPictureInPictureController的初始化需要用到AVPlayer。但公司目前的设备推流机制是直接客户端接受YUV数据并用OpenGL渲染,没有经过服务器取流,所以画中画暂时无法实现。

    //欢迎大家交流并指出错误,谢谢

    官方文档

    相关文章

      网友评论

          本文标题:iOS14 画中画调研

          本文链接:https://www.haomeiwen.com/subject/ykgxnltx.html