美文网首页iOS
iOSReplayKit实践

iOSReplayKit实践

作者: 七里田间的守望者 | 来源:发表于2020-07-23 15:59 被阅读0次

    本文主要介绍iOS设备关于ReplayKit框架的发展过程和在每个阶段增加了哪些功能,并在提供实现相应功能的代码和思路

    ReplayKit 是啥?干啥用的?

    由于历史原因,苹果一直都没有提供官方的App的屏幕录制相关的SDK,直到iOS9也就是WWDC15的时候才开始提供ReplayKit框架,但是由于当时的目的是给游戏开发者录制玩游戏的视频,作为社交分享的。所以它的API相对来说简单很多只有简单的开始录制视频和停止录制视频。

    iOS9

    开始录制视频的API

    if ([[RPScreenRecorder sharedRecorder] isAvailable]) {
        [[RPScreenRecorder sharedRecorder] startRecordingWithMicrophoneEnabled:YES handler:^(NSError * _Nullable error) {
                
        }];
    }
    

    调用开始录屏的时候系统会弹出一个弹窗,需要用户进行确认后才能正常录制

    image.png

    停止录制视频的API

    [[RPScreenRecorder sharedRecorder] stopRecordingWithHandler:^(RPPreviewViewController *previewViewController, NSError *  error){
        
        [self presentViewController:previewViewController animated:YES completion:^{
            NSLog(@"presentViewController");
        }];
    }];
    

    调用停止录制视频接口时会弹出下面的界面,让用户进行操作

    image.png

    上面的两个接口有下面的限制:

    • 不能获取到视频录制时的数据,只能在停止录制视频的时候获取到苹果已经处理合成好的MP4文件
    • 不能直接获取录制好的视频文件,需要先通过用户存储到相册,你才能通过相册去访问到该文件
    • 停止录制的时候需要弹出一个视频的预览窗口,你可以在这个窗口进行保存或者取消或者分享该视频文件
    • 你还可以直接编辑该视频
      由于上面的限制,你只能在用户存储录制的视频保存到相册你才能访问。想要上传该视频到服务器,你还需要把相册的那个视频先想办法copy到沙盒中,然后再开始上传服务器。

    关于为啥不能获取该视频我解释下:
    因为录制好的视频文件是存在系统的某个位置,而不是你的App沙盒,所以访问不到。具体看下图说明

    image.png

    iOS10

    到了WWDC16,经过了一年的沉淀苹果对ReplayKit进行了升级,下面我们来对比下相比iOS9多了哪些功能。

    • 可以捕捉到App屏幕录制的数据流了,分别为视频帧 麦克风 App内声音
    • 增加了ReplayKit的扩展分别为Broadcast Upload ExtensionBroadcast Setup UI Extension
    • Broadcast Upload Extension 是处理捕捉到App屏幕录制的数据的
    • Broadcast Setup UI Extension一些关于屏幕捕捉的UI交互
    • 上面两个插件是相互独立的
    下面说iOS10下的ReplayKi该怎么使用

    App该怎么做

    • 开始录制视频
    if (![RPScreenRecorder sharedRecorder].isRecording) {
        [RPBroadcastActivityViewController loadBroadcastActivityViewControllerWithHandler:^(RPBroadcastActivityViewController * _Nullable broadcastActivityViewController, NSError * _Nullable error) {
            if (error) {
                NSLog(@"RPBroadcast err %@", [error localizedDescription]);
            }
            broadcastActivityViewController.delegate = self; // 它的代理方法是下面的这个 0
            [self presentViewController:broadcastActivityViewController animated:YES completion:nil];
        }];
    }
    

    上面的方法是加载起来录屏扩展的UI界面,并在回调函数里面设置代理后弹出控制器。
    代理方法如下所示

    0 这个方法 在 Broadcast Setup UI Extension中的userDidFinishSetup函数调用后执行

    - (void)broadcastActivityViewController:(RPBroadcastActivityViewController *)broadcastActivityViewController didFinishWithBroadcastController:(RPBroadcastController *)broadcastController error:(NSError *)error
    API_AVAILABLE(ios(10.0))
    {
        [broadcastActivityViewController dismissViewControllerAnimated:YES
                                                            completion:nil];
        NSLog(@"BundleID %@", broadcastController.broadcastExtensionBundleID);
        self.broadcastController = broadcastController;
        self.broadcastController.delegate = self; // 它的代理方法如下面的三个 1、2
        if (error) {
            NSLog(@"BAC: %@ didFinishWBC: %@, err: %@",
                  broadcastActivityViewController,
                  broadcastController,
                  error);
            return;
        }
        
        [broadcastController startBroadcastWithHandler:^(NSError * _Nullable error) {
            if (!error) {
                NSLog(@"-----start success----");
                // 这里可以添加camerPreview
            } else {
                NSLog(@"startBroadcast:%@",error.localizedDescription);
            }
        }];
    }
    
    

    1 这个方法在 RPBroadcastController中的startBroadcastWithHandler函数调用后执行,也就是Broadcast Upload ExtensionupdateServiceInfo调用而更新

    // Watch for service info from broadcast service
    - (void)broadcastController:(RPBroadcastController *)broadcastController
           didUpdateServiceInfo:(NSDictionary <NSString *, NSObject <NSCoding> *> *)serviceInfo
    API_AVAILABLE(ios(10.0))
    {
        NSLog(@"didUpdateServiceInfo: %@", serviceInfo);
    }
    

    2 这个方法在 Broadcast Setup UI Extension中的处理流错误时调用

    - (void)broadcastController:(RPBroadcastController *)broadcastController
             didFinishWithError:(NSError *)error API_AVAILABLE(ios(10.0))
    {
        NSLog(@"didFinishWithError: %@", error);
    }
    

    界面如下图所示

    image.png
    这里的Mobcrush就是创建的Broadcast Setup UI Extension扩展
    当点击Mobcrush按钮时会执行Broadcast Setup UI Extension扩展里面的代码
    Broadcast Setup UI Extension该怎么做
    由于这个扩展是一个控制器,所以它有控制的声明周期。所以在被点击的时候会弹出这个控制器执行viewDidLoad方法,你可以在这里写业务相关的UI代码比如我们添加两个Button按钮一个是开始直播一个是取消,两个按钮分别对应的方法为userDidFinishSetupuserDidCancelSetup下面我说下这两个方法执行的时候都干了啥
    • 执行userDidCancelSetup的时候会调用RPBroadcastActivityViewControllerDelegate的代理方法
    • 执行userDidFinishSetup的时候也会调用RPBroadcastActivityViewControllerDelegate的代理方法
      就是上面我们说的标号为0的代码段

    RPBroadcastActivityViewControllerDelegate的代理方法没有错误的话,我们会调用下面的方法(完整方法是上面标号为0的代码段)

    [broadcastController startBroadcastWithHandler:^(NSError * _Nullable error) {
            if (!error) {
                NSLog(@"-----start success----");
                // 这里可以添加camerPreview
            } else {
                NSLog(@"startBroadcast:%@",error.localizedDescription);
            }
    }];
    

    这段代码执行成功后,就会调用到Broadcast Upload Extension里面的代码了

    Broadcast Upload Extension该怎么做
    这里的代码执行顺序为

    • - (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo
      你可以在这个方法中做一些初始化信息操作等等
    • - (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType
      然后就是我们的主要方法了,处理App屏幕录制的数据流,代码如下:
    - (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
        NSLog(@"%@", sampleBuffer);
        switch (sampleBufferType) {
            case RPSampleBufferTypeVideo:
                // Handle video sample buffer
          {
           
          }
                break;
            case RPSampleBufferTypeAudioApp:
                // Handle audio sample buffer for app audio
                
                break;
            case RPSampleBufferTypeAudioMic:
                // Handle audio sample buffer for mic audio
          {
           
          }
                break;
                
            default:
                break;
        }
    }
    

    iOS11

    到了WWDC17,经过了一年的沉淀苹果对ReplayKit2进行了升级,下面我们来对比下相比iOS10多了哪些功能。

    • iOS10的ReplayKit只能通过扩展区录制屏幕,好处是不仅可以录制自己的APP还可以录制其他APP
    • 但是只能通过扩展去处理录制的数据流,不能在App里面直接处理
    • iOS10只能录制APP屏幕,不能录制iOS系统屏幕
    • iOS11就可以直接在APP中启动屏幕录制,可以直接在APP中处理录制的APP屏幕数据
    • iOS11还可以录制iOS系统的屏幕数据,不过还是需要扩展才行,并且启动方法只能在系统的控制器中心长按录制屏幕按钮,然后选择要处理数据流的扩展程序
    启动APP屏幕录制
    [[RPScreenRecorder sharedRecorder] startCaptureWithHandler:^(CMSampleBufferRef  _Nonnull sampleBuffer, RPSampleBufferType bufferType, NSError * _Nullable error) {
        NSLog(@"%@", sampleBuffer);
    } completionHandler:^(NSError * _Nullable error) {
        NSLog(@"%@", error);
    }];
    
    停止APP屏幕录制
    [[RPScreenRecorder sharedRecorder] stopCaptureWithHandler:^(NSError * _Nullable error) {
    [self.assetWriter finishWritingWithCompletionHandler:^{
        
    }];
    }];
    

    这两接口接搞定了App屏幕录制了

    如果想要录制iOS系统屏幕的需要两个条件
    1、实现跟iOS一样的扩展程序
    2、开启(开启方式如下图)

    image.png image.png

    iOS12

    到了WWDC18,经过了一年的沉淀苹果对ReplayKit2进行了升级,下面我们来对比下相比iOS11多了哪些功能。

    我们发现iOS11 开启系统屏幕录制增加了复杂度,到了iOS12的时候苹果提供了一个接口,方便让我们能在APP中直接开启iOS系统屏幕录制代码如下

    if (@available(iOS 12.0, *)) {
            _broadPickerView = [[RPSystemBroadcastPickerView alloc] initWithFrame:CGRectMake(40, 60, 100, 100)];
            _broadPickerView.preferredExtension = @"com.example.xxxx"; // 这里是你扩展的bundleid
            [self.view addSubview:_broadPickerView];
        }
    

    这是一个系统提供的开启iOS屏幕录制的按钮,这样就不用去控制中心开启了。

    至此iOSReplayKit框架就介绍完毕了

    相关文章

      网友评论

        本文标题:iOSReplayKit实践

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