前言:
隨著上一篇 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