zoukankan      html  css  js  c++  java
  • 【原创】苹果内置录屏SDK-ReplayKit库的使用说明

    1 iOS ReplayKit 录屏SDK 说明 (按照苹果官方的说法是App端加入这些苹果的新特性新SDK更容易被苹果推荐 )

    ReplayKit是苹果在iOS9上面提供的一个库组件,可以让玩家在游戏中录制游戏视频,并且可以添加语音评论,然后通过社交网络分享出去。

    2库的特性说明

    • 要使用ReplayKit需要在工程的Build Phase的Link binary with libraries中加入ReplayKit.framework.

    • 目前这个库只支持真机允许,不支持模拟器。

    • 系统版本如果低于iOS9也不支持。

    • 还有这个库支持游戏录屏,但不支持录avplayer播放的视频,这个可能是为了保护视频的版权,避免影视资源被复制拷贝。

    视频录制完成之后可以调用ReplayKit的接口显示视频预览页面,对应的接口是返回一个页面的ViewController,至于如何显示这个页面,各个客户端可以自由处理,Demo中只是给了其中一种实现方法。

    3库的潜在问题

    经过实验,发现ReplayKit有如下情况:

    • 录制的启动初始化有时很慢,有见过几十秒才初始化完成的,也碰见过初始化没有成功的。

    • 录制调用了停止接口后系统还会继续录制多几秒的视频。

    • 出现过录制结果为黑屏的情况。

    • 还有这个录屏SDK支付使用麦克风,即是可以一边录制游戏,一边用麦克风讲解。

    4Demo说明

    附件是Demo的工程,使用Xcode7编译之后可以运行起来(不支持Xcode6,Xcode6没有ReplayKit这个库)

    连接iPhone或者iPad之后可以编译并运行这个工程,在真机上运行后可以看到如下界面。

    参见附件图片

    1. 点击 开始按钮 后就会调用开始录屏的接口,但这个时候不是马上进行录屏,ReplayKit需要初始化完成开自动开始录屏,所以Demo加了一个Loading提示“初始化”

    2. 初始化完成后 结束 按钮变为可以点击的状态,并提示 “正在录制”

    3. 等要结束时点击 结束按钮,会调用ReplayKit的停止接口,停止接口给了回调后可以显示录屏视频的预览页面,至于要不要显示和如何显示,由各个游戏的前端确定,Demo只是给了个参考的例子。

    4. 在视频预览页面可以选择保存到系统相册或者分享到社交网络,还可以拷贝到剪切板,这些操作都可以在回调中获取到,游戏前端可以根据这些回调的信息给用户提示(比如“视频成功保存到系统相册”)

      >> 系统默认的分享暂时是看到Facebook Youtube这些,并没有看到有微信微博分享。不过这些视频保存到系统相册之后可以上传到优酷,后续生成链接并分享出去的还没有测试过。

    5. Demo中的时间和进度条只是模拟了游戏中的动画,不然只有静止画面,看不出视频的效果。

    其他:Demo中的函数都附带了注释说明,可以自由修改并自由分发。

    5官网说明

    ReplayKit的官网使用说明 https://developer.apple.com/library/ios/documentation/ReplayKit/Reference/ReplayKit_Collection/index.html#//apple_ref/doc/uid/TP40016260;

    Demo代码:

      1 #import "ViewController.h"
      2 #import <ReplayKit/ReplayKit.h>
      3 
      4 static NSString *StartRecord = @"开始";
      5 static NSString *StopRecord = @"结束";
      6 
      7 #if TARGET_IPHONE_SIMULATOR
      8 #define SIMULATOR 1
      9 #elif TARGET_OS_IPHONE
     10 #define SIMULATOR 0
     11 #endif
     12 
     13 #define AnimationDuration (0.3)
     14 
     15 
     16 @interface ViewController () <RPPreviewViewControllerDelegate>
     17 {
     18     
     19 }
     20 @property (nonatomic, strong)UIButton *btnStart;
     21 @property (nonatomic, strong)UIButton *btnStop;
     22 @property (nonatomic, strong)NSTimer *progressTimer;
     23 @property (nonatomic, strong)UIProgressView *progressView;
     24 @property (nonatomic, strong)UIActivityIndicatorView *activity;
     25 @property (nonatomic, strong)UIView *tipView;
     26 @property (nonatomic, strong)UILabel *lbTip;
     27 @property (nonatomic, strong)UILabel *lbTime;
     28 
     29 @end
     30 
     31 @implementation ViewController
     32 
     33 - (void)viewDidLoad {
     34     [super viewDidLoad];
     35     // Do any additional setup after loading the view, typically from a nib.
     36     
     37 }
     38 
     39 - (void)viewDidAppear:(BOOL)animated {
     40     BOOL isVersionOk = [self isSystemVersionOk];
     41     
     42     if (!isVersionOk) {
     43         NSLog(@"系统版本需要是iOS9.0及以上才支持ReplayKit");
     44         return;
     45     }
     46     if (SIMULATOR) {
     47         [self showSimulatorWarning];
     48         return;
     49     }
     50     
     51     UILabel *lb = nil;
     52     CGSize screenSize = [UIScreen mainScreen].bounds.size;
     53     
     54     
     55     //标题
     56     lb = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 140)];
     57     lb.font = [UIFont boldSystemFontOfSize:32];
     58     lb.backgroundColor = [UIColor clearColor];
     59     lb.textColor = [UIColor blackColor];
     60     lb.textAlignment = NSTextAlignmentCenter;
     61     lb.numberOfLines = 3;
     62     lb.text = @"苹果ReplayKit Demo";
     63     lb.center =  CGPointMake(screenSize.width/2, 80);
     64     [self.view addSubview:lb];
     65     
     66     //创建按钮
     67     UIButton *btn = [self createButtonWithTitle:StartRecord andCenter:CGPointMake(screenSize.width/2 - 100, 200)];
     68     [self.view addSubview:btn];
     69     self.btnStart = btn;
     70     
     71     btn = [self createButtonWithTitle:StopRecord andCenter:CGPointMake(screenSize.width/2 + 100, 200)];
     72     [self.view addSubview:btn];
     73     self.btnStop = btn;
     74     [self setButton:btn enabled:NO];
     75     
     76     //loading指示
     77     UIActivityIndicatorView *activity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
     78     UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 280, 80)];
     79     [self.view addSubview:view];
     80     view.backgroundColor = [UIColor redColor];
     81     view.layer.cornerRadius = 8.0f;
     82     view.center = CGPointMake(screenSize.width/2, 300);
     83     activity.center = CGPointMake(30, view.frame.size.height/2);
     84     [view addSubview:activity];
     85     [activity startAnimating];
     86     self.activity = activity;
     87     lb = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 280, 80)];
     88     lb.font = [UIFont boldSystemFontOfSize:20];
     89     lb.backgroundColor = [UIColor clearColor];
     90     lb.textColor = [UIColor blackColor];
     91     lb.layer.cornerRadius = 4.0;
     92     lb.textAlignment = NSTextAlignmentCenter;
     93     [view addSubview:lb];
     94     self.lbTip = lb;
     95     self.tipView = view;
     96     [self hideTip];
     97     
     98     
     99     //显示时间(用于看录制结果时能知道时间)
    100     lb = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 40)];
    101     lb.font = [UIFont boldSystemFontOfSize:20];
    102     lb.backgroundColor = [UIColor redColor];
    103     lb.textColor = [UIColor blackColor];
    104     lb.layer.cornerRadius = 4.0;
    105     NSDateFormatter * dateFormat = [[NSDateFormatter alloc] init] ;
    106     [dateFormat setDateFormat: @"HH:mm:ss"];
    107     NSString *dateString = [dateFormat stringFromDate:[NSDate date]];
    108     lb.text =  dateString;
    109     lb.center = CGPointMake(screenSize.width/2, screenSize.height/2 + 100);
    110     lb.textAlignment = NSTextAlignmentCenter;
    111     [self.view addSubview:lb];
    112     self.lbTime = lb;
    113     
    114     //进度条 (显示动画,不然看不出画面的变化)
    115     UIProgressView *progress = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 0, screenSize.width*0.8, 10)];
    116     progress.center = CGPointMake(screenSize.width/2, screenSize.height/2 + 150);
    117     progress.progressViewStyle = UIProgressViewStyleDefault;
    118     progress.progress = 0.0;
    119     [self.view addSubview:progress];
    120     self.progressView = progress;
    121     
    122     //计时器
    123     //更新时间
    124     [NSTimer scheduledTimerWithTimeInterval:1.0f
    125                                      target:self
    126                                    selector:@selector(updateTimeString)
    127                                    userInfo:nil
    128                                     repeats:YES];
    129 }
    130 
    131 #pragma mark - UI控件
    132 //显示 提示信息
    133 - (void)showTipWithText:(NSString *)tip activity:(BOOL)activity{
    134     [self.activity startAnimating];
    135     self.lbTip.text = tip;
    136     self.tipView.hidden = NO;
    137     if (activity) {
    138         self.activity.hidden = NO;
    139         [self.activity startAnimating];
    140     } else {
    141         [self.activity stopAnimating];
    142         self.activity.hidden = YES;
    143     }
    144 }
    145 //隐藏 提示信息
    146 - (void)hideTip {
    147     self.tipView.hidden = YES;
    148     [self.activity stopAnimating];
    149 }
    150 
    151 //创建按钮
    152 - (UIButton *)createButtonWithTitle:(NSString *)title andCenter:(CGPoint)center {
    153 
    154     CGRect rect = CGRectMake(0, 0, 160, 60);
    155     UIButton *btn = [[UIButton alloc] initWithFrame:rect];
    156     btn.layer.cornerRadius = 5.0;
    157     btn.layer.borderWidth = 2.0;
    158     btn.layer.borderColor = [[UIColor blackColor] CGColor];
    159     btn.backgroundColor = [UIColor lightGrayColor];
    160     btn.center = center;
    161     [btn setTitle:title forState:UIControlStateNormal];
    162     [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    163     [btn addTarget:self action:@selector(onBtnPressed:) forControlEvents:UIControlEventTouchDown];
    164     return btn;
    165     
    166 }
    167 
    168 //设置按钮是否可点击
    169 - (void)setButton:(UIButton *)button enabled:(BOOL)enabled {
    170     if (enabled) {
    171         button.alpha = 1.0;
    172     } else {
    173         button.alpha = 0.2;
    174     }
    175     button.enabled = enabled;
    176 }
    177 
    178 //提示不支持模拟器
    179 - (void)showSimulatorWarning {
    180     UIAlertAction *actionOK = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){
    181         
    182     }];
    183     UIAlertAction *actionCancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action){
    184         
    185     }];
    186     UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"ReplayKit不支持模拟器" message:@"请使用真机运行这个Demo工程" preferredStyle:UIAlertControllerStyleAlert];
    187     [alert addAction:actionCancel];
    188     [alert addAction:actionOK];
    189     
    190     [self presentViewController:alert animated:NO completion:nil];
    191 }
    192 
    193 //显示弹框提示
    194 - (void)showAlert:(NSString *)title andMessage:(NSString *)message {
    195     if (!title) {
    196         title = @"";
    197     }
    198     if (!message) {
    199         message = @"";
    200     }
    201     UIAlertAction *actionCancel = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleCancel handler:nil];
    202     UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
    203     [alert addAction:actionCancel];
    204     [self presentViewController:alert animated:NO completion:nil];
    205 }
    206 
    207 //显示视频预览页面,animation=是否要动画显示
    208 - (void)showVideoPreviewController:(RPPreviewViewController *)previewController withAnimation:(BOOL)animation {
    209     
    210     __weak ViewController *weakSelf = self;
    211     
    212     //UI需要放到主线程
    213     dispatch_async(dispatch_get_main_queue(), ^{
    214         
    215         CGRect rect = [UIScreen mainScreen].bounds;
    216         
    217         if (animation) {
    218             
    219             rect.origin.x += rect.size.width;
    220             previewController.view.frame = rect;
    221             rect.origin.x -= rect.size.width;
    222             [UIView animateWithDuration:AnimationDuration animations:^(){
    223                 previewController.view.frame = rect;
    224             } completion:^(BOOL finished){
    225                 
    226             }];
    227             
    228         } else {
    229             previewController.view.frame = rect;
    230         }
    231         
    232         [weakSelf.view addSubview:previewController.view];
    233         [weakSelf addChildViewController:previewController];
    234         
    235         
    236     });
    237     
    238 }
    239 
    240 //关闭视频预览页面,animation=是否要动画显示
    241 - (void)hideVideoPreviewController:(RPPreviewViewController *)previewController withAnimation:(BOOL)animation {
    242     
    243     //UI需要放到主线程
    244     dispatch_async(dispatch_get_main_queue(), ^{
    245         
    246         CGRect rect = previewController.view.frame;
    247         
    248         if (animation) {
    249             
    250             rect.origin.x += rect.size.width;
    251             [UIView animateWithDuration:AnimationDuration animations:^(){
    252                 previewController.view.frame = rect;
    253             } completion:^(BOOL finished){
    254                 //移除页面
    255                 [previewController.view removeFromSuperview];
    256                 [previewController removeFromParentViewController];
    257             }];
    258             
    259         } else {
    260             //移除页面
    261             [previewController.view removeFromSuperview];
    262             [previewController removeFromParentViewController];
    263         }
    264     });
    265 }
    266 
    267 #pragma mark - 按钮 回调
    268 //按钮事件
    269 - (void)onBtnPressed:(UIButton *)sender {
    270     
    271     //点击效果
    272     sender.transform = CGAffineTransformMakeScale(0.8, 0.8);
    273     float duration = 0.3;
    274     [UIView animateWithDuration:duration
    275                      animations:^{
    276                          sender.transform = CGAffineTransformMakeScale(1.1, 1.1);
    277                      }completion:^(BOOL finish){
    278                          [UIView animateWithDuration:duration
    279                                           animations:^{
    280                                               sender.transform = CGAffineTransformMakeScale(1.0, 1.0);
    281                                           }completion:^(BOOL finish){ }];
    282                      }];
    283     
    284     NSString *function = sender.titleLabel.text;
    285     if ([function isEqualToString:StartRecord]) {
    286         [self startRecord];
    287     }
    288     else if ([function isEqualToString:StopRecord]) {
    289         [self stopRecord];
    290     }
    291 }
    292 
    293 
    294 - (void)startRecord {
    295     
    296     //    [self setButton:self.btnStart enabled:NO];
    297     
    298     NSLog(@"ReplayKit只支持真机录屏,支持游戏录屏,不支持录avplayer播放的视频");
    299     NSLog(@"检查机器和版本是否支持ReplayKit录制...");
    300     if ([[RPScreenRecorder sharedRecorder] isAvailable]) {
    301         NSLog(@"支持ReplayKit录制");
    302     } else {
    303         NSLog(@"!!不支持支持ReplayKit录制!!");
    304         return;
    305     }
    306     
    307     __weak ViewController *weakSelf = self;
    308     
    309     NSLog(@"%@ 录制", StartRecord);
    310     [self showTipWithText:@"录制初始化" activity:YES];
    311 
    312     //在此可以设置是否允许麦克风(传YES即是使用麦克风,传NO则不是用麦克风)
    313     [[RPScreenRecorder sharedRecorder] startRecordingWithMicrophoneEnabled:NO handler:^(NSError *error){
    314         NSLog(@"录制开始...");
    315         [weakSelf hideTip];
    316         if (error) {
    317             NSLog(@"错误信息 %@", error);
    318             [weakSelf showTipWithText:error.description activity:NO];
    319         } else {
    320             //其他处理
    321             [weakSelf setButton:self.btnStop enabled:YES];
    322             [weakSelf setButton:self.btnStart enabled:NO];
    323             
    324             [weakSelf showTipWithText:@"正在录制" activity:NO];
    325             //更新进度条
    326             weakSelf.progressTimer = [NSTimer scheduledTimerWithTimeInterval:0.05f
    327                                                                       target:self
    328                                                                     selector:@selector(changeProgressValue)
    329                                                                     userInfo:nil
    330                                                                      repeats:YES];
    331         }
    332     }];
    333 }
    334 
    335 - (void)stopRecord {
    336     NSLog(@"%@ 录制", StopRecord);
    337     
    338     [self setButton:self.btnStart enabled:YES];
    339     [self setButton:self.btnStop enabled:NO];
    340     
    341     __weak ViewController *weakSelf = self;
    342     [[RPScreenRecorder sharedRecorder] stopRecordingWithHandler:^(RPPreviewViewController *previewViewController, NSError *  error){
    343         
    344         
    345         if (error) {
    346             NSLog(@"失败消息:%@", error);
    347             [weakSelf showTipWithText:error.description activity:NO];
    348         } else {
    349             
    350             [weakSelf showTipWithText:@"录制完成" activity:NO];
    351             
    352             //显示录制到的视频的预览页
    353             NSLog(@"显示预览页面");
    354             previewViewController.previewControllerDelegate = weakSelf;
    355             
    356             //去除计时器
    357             [weakSelf.progressTimer invalidate];
    358             weakSelf.progressTimer = nil;
    359             
    360             [self showVideoPreviewController:previewViewController withAnimation:YES];
    361         }
    362     }];
    363 }
    364 
    365 #pragma mark - 视频预览页面 回调
    366 //关闭的回调
    367 - (void)previewControllerDidFinish:(RPPreviewViewController *)previewController {
    368     [self hideVideoPreviewController:previewController withAnimation:YES];
    369 }
    370 
    371 //选择了某些功能的回调(如分享和保存)
    372 - (void)previewController:(RPPreviewViewController *)previewController didFinishWithActivityTypes:(NSSet <NSString *> *)activityTypes {
    373     
    374     __weak ViewController *weakSelf = self;
    375     if ([activityTypes containsObject:@"com.apple.UIKit.activity.SaveToCameraRoll"]) {
    376         
    377         dispatch_async(dispatch_get_main_queue(), ^{
    378             [weakSelf showAlert:@"保存成功" andMessage:@"已经保存到系统相册"];
    379         });
    380     }
    381     if ([activityTypes containsObject:@"com.apple.UIKit.activity.CopyToPasteboard"]) {
    382         dispatch_async(dispatch_get_main_queue(), ^{
    383             [weakSelf showAlert:@"复制成功" andMessage:@"已经复制到粘贴板"];
    384         });
    385     }
    386 }
    387 
    388 #pragma mark - 计时器 回调
    389 
    390 //改变进度条的显示的进度
    391 - (void)changeProgressValue {
    392     float progress = self.progressView.progress + 0.01;
    393     [self.progressView setProgress:progress animated:NO];
    394     if (progress >= 1.0) {
    395         self.progressView.progress = 0.0;
    396     }
    397 }
    398 //更新显示的时间
    399 - (void)updateTimeString {
    400     NSDateFormatter * dateFormat = [[NSDateFormatter alloc] init] ;
    401     [dateFormat setDateFormat: @"HH:mm:ss"];
    402     NSString *dateString = [dateFormat stringFromDate:[NSDate date]];
    403     self.lbTime.text =  dateString;
    404 }
    405 
    406 #pragma mark - 其他
    407 - (void)didReceiveMemoryWarning {
    408     [super didReceiveMemoryWarning];
    409     // Dispose of any resources that can be recreated.
    410 }
    411 
    412 //判断对应系统版本是否支持ReplayKit
    413 - (BOOL)isSystemVersionOk {
    414     if ([[UIDevice currentDevice].systemVersion floatValue] < 9.0) {
    415         return NO;
    416     } else {
    417         return YES;
    418     }
    419 }
    420 
    421 @end
  • 相关阅读:
    AcWing 1027. 方格取数 dp
    AcWing 1014. 登山 dp
    acwing 482. 合唱队形 dp
    LeetCode 1463. 摘樱桃II dp
    LeetCode 100. 相同的树 树的遍历
    LeetCode 336. 回文对 哈希
    LeetCode 815. 公交路线 最短路 哈希
    算法问题实战策略 DARPA大挑战 二分
    算法问题实战策略 LUNCHBOX 贪心
    AcWing 1100. 抓住那头牛 BFS
  • 原文地址:https://www.cnblogs.com/huangzizhu/p/5073389.html
Copyright © 2011-2022 走看看