iOS ReplayKit

前言:

隨著上一篇 IJK 成功播放了視頻,又來了新的需求,那就是,要錄制直播中的一段視頻,保存到用戶相冊。

代碼地址: https://github.com/gityuency/ObjectiveCTools
類名:【RecordingViewController】

ReplayKit 出現(xiàn)在 iOS 9 ,所以低版本沒法玩。但是在 iOS 9 和 iOS 10上差了一個屬性。就是 movieURL。本篇示例代碼 在 iOS 9 上是彈出視圖讓用戶操作,在 iOS 10 上 錄制完成直接保存。 開始和結(jié)束,就兩句代碼。

第一步 寫代碼

YXReplayManager.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface YXReplayManager : NSObject

/// 單例對象
+ (instancetype)sharedManager;

/// 用于查看相冊和麥克風(fēng)權(quán)限是否已經(jīng)獲取;
+ (void)demandForAuthorization:(void(^)(void))authorizedResultBlock;

/// 開始記錄
- (void)startRecording;

/// 停止記錄
- (void)stopRecording;

@end

NS_ASSUME_NONNULL_END

YXReplayManager.m


#import "YXReplayManager.h"
#import <Photos/Photos.h>
#import <ReplayKit/ReplayKit.h>

@interface YXReplayManager() <RPPreviewViewControllerDelegate>

@end

@implementation YXReplayManager

/// 單例對象
static YXReplayManager *_instance;

/// 錄制對象
static RPScreenRecorder *recorder;


+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
        recorder = [RPScreenRecorder sharedRecorder];
        recorder.microphoneEnabled = YES;
    });
    return _instance;
}
+ (instancetype)sharedManager {
    return [[self alloc] init];
}
- (id)copyWithZone:(NSZone *)zone {
    return _instance;
}
- (id)mutableCopyWithZone:(NSZone *)zone {
    return _instance;
}


/// 申請權(quán)限
+ (void)demandForAuthorization:(void(^)(void))authorizedResultBlock {
    // 先去 info.plit 開啟相冊權(quán)限,否則真機(jī)崩潰
    PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
    if (status == PHAuthorizationStatusAuthorized) {
        if (authorizedResultBlock) {  //已經(jīng)授權(quán)
            authorizedResultBlock();
        }
        NSLog(@"相冊權(quán)限已經(jīng)存在");
    } else {
        [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
            if(status == PHAuthorizationStatusAuthorized) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    if (authorizedResultBlock) {  // 用戶點(diǎn)擊 "OK"
                        authorizedResultBlock();
                    }
                });
                NSLog(@"相冊權(quán)限已經(jīng)授權(quán) 用戶授權(quán)");
            } else {
                NSLog(@"玩你媽嗨");  // 用戶點(diǎn)擊 不允許訪問
            }
        }];
    }
}


#pragma mark - 開始錄制
/// 開始記錄
- (void)startRecording {
    
    [YXReplayManager demandForAuthorization:^{
        [_instance turnOnRecord];
    }];
}
/// 開始記錄
- (void)turnOnRecord {
    
    if (recorder.isRecording) { //已經(jīng)在錄制,就返回
        return;
    }
    
    if (@available(iOS 10.0, *)) {
        [recorder startRecordingWithHandler:^(NSError * _Nullable error) {
            if (!error) {
                NSLog(@"錄制開始... 10.0 系統(tǒng)");
            }
        }];
    } else if (@available(iOS 9.0, *)) {
        [recorder startRecordingWithMicrophoneEnabled:YES handler:^(NSError * _Nullable error) {
            if (!error) {
                NSLog(@"錄制開始... 9.0 系統(tǒng)");
            }
        }];
    } else {
        NSLog(@"系統(tǒng)版本太低,沒法玩.");
    }
}


#pragma mark - 停止錄制
/// 停止錄制
- (void)stopRecording {
    [_instance turnOffRecord];
}

/// 停止錄制
- (void)turnOffRecord {
    
    NSLog(@"結(jié)束錄制");
    
    dispatch_async(dispatch_get_main_queue(), ^{
        [[RPScreenRecorder sharedRecorder] stopRecordingWithHandler:^(RPPreviewViewController * _Nullable previewViewController, NSError * _Nullable error) {
            NSLog(@"結(jié)束回調(diào)");
            
            if (error) {  //出錯
                NSLog(@"出錯: %@", error);
            } else {  //成功回調(diào)
                
                if (@available(iOS 10.0, *)) {
                    
                    /*
                     iOS 10 這里我選擇直接保存到相冊,不使用 previewViewController 彈出來
                     */
                    [self handleiOS10:previewViewController];
                    
                } else if (@available(iOS 9.0, *)) {
                    
                    /*
                     在iOS9 里面取不到 movieURL 這個變量,程序會崩潰. 所以直接彈出這個 previewViewController 讓用戶來操作保存
                     */
                    [self handleiOS9:previewViewController];
                }
            }
        }];
    });
}

/// 處理 iOS 10
- (void)handleiOS10:(RPPreviewViewController *)previewViewController {
    
    NSURL *videoURL = [previewViewController valueForKey:@"movieURL"];
    
    if (videoURL) {
        BOOL compatible = UIVideoAtPathIsCompatibleWithSavedPhotosAlbum([videoURL path]);
        
        if (compatible) {
            UISaveVideoAtPathToSavedPhotosAlbum([videoURL path], self, @selector(savedPhotoImage:didFinishSavingWithError:contextInfo:), nil);
        }
        
    } else {
        NSLog(@"沒有找到 movieURL");
    }
}


/// 處理 iOS 9
- (void)handleiOS9:(RPPreviewViewController *)previewViewController {
    previewViewController.previewControllerDelegate = self;
    [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:previewViewController animated:YES completion:nil];
}

#pragma mark - RPPreviewViewController 代理,用于 iOS 9
- (void)previewControllerDidFinish:(RPPreviewViewController *)previewController {
    [previewController dismissViewControllerAnimated:YES completion:nil];
    NSLog(@"預(yù)覽控制器消失");
}

- (void)previewController:(RPPreviewViewController *)previewController didFinishWithActivityTypes:(NSSet <NSString *> *)activityTypes {
    NSLog(@"用戶已經(jīng)操作! %@", activityTypes);
}


#pragma mark - iOS 10 保存視頻的回調(diào)
/// 保存視頻之后的回調(diào),這個方法不能亂寫
- (void)savedPhotoImage:(UIImage*)image didFinishSavingWithError: (NSError *)error contextInfo: (void *)contextInfo {
    
    if (error) {
        NSLog(@"保存視頻失敗!!!");
    } else {
        NSLog(@"已經(jīng)成功保存了視頻!");
    }
}

@end

第二步 測試

#import "RecordingViewController.h"
#import "YXReplayManager.h"

@interface RecordingViewController ()

@end

@implementation RecordingViewController

- (void)viewDidLoad {
    [super viewDidLoad];

}

- (IBAction)start:(UIButton *)sender {

    sender.backgroundColor = [UIColor redColor];
    [[YXReplayManager sharedManager] startRecording];

}

- (IBAction)stop:(UIButton *)sender {

    sender.backgroundColor = [UIColor greenColor];
    [[YXReplayManager sharedManager] stopRecording];
}


@end

第三步 Command + R

1.jpeg
2.jpeg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容