iOSReplayKit实践

本文主要介绍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框架就介绍完毕了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335