前言:
随着上一篇 IJK 成功播放了视频,又来了新的需求,那就是,要录制直播中的一段视频,保存到用户相册。
代码地址: https://github.com/gityuency/ObjectiveCTools
类名:【RecordingViewController】
ReplayKit 出现在 iOS 9 ,所以低版本没法玩。但是在 iOS 9 和 iOS 10上差了一个属性。就是 movieURL。本篇示例代码 在 iOS 9 上是弹出视图让用户操作,在 iOS 10 上 录制完成直接保存。 开始和结束,就两句代码。
第一步 写代码
YXReplayManager.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface YXReplayManager : NSObject
/// 单例对象
+ (instancetype)sharedManager;
/// 用于查看相册和麦克风权限是否已经获取;
+ (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;
}
/// 申请权限
+ (void)demandForAuthorization:(void(^)(void))authorizedResultBlock {
// 先去 info.plit 开启相册权限,否则真机崩溃
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
if (status == PHAuthorizationStatusAuthorized) {
if (authorizedResultBlock) { //已经授权
authorizedResultBlock();
}
NSLog(@"相册权限已经存在");
} else {
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
if(status == PHAuthorizationStatusAuthorized) {
dispatch_async(dispatch_get_main_queue(), ^{
if (authorizedResultBlock) { // 用户点击 "OK"
authorizedResultBlock();
}
});
NSLog(@"相册权限已经授权 用户授权");
} else {
NSLog(@"玩你妈嗨"); // 用户点击 不允许访问
}
}];
}
}
#pragma mark - 开始录制
/// 开始记录
- (void)startRecording {
[YXReplayManager demandForAuthorization:^{
[_instance turnOnRecord];
}];
}
/// 开始记录
- (void)turnOnRecord {
if (recorder.isRecording) { //已经在录制,就返回
return;
}
if (@available(iOS 10.0, *)) {
[recorder startRecordingWithHandler:^(NSError * _Nullable error) {
if (!error) {
NSLog(@"录制开始... 10.0 系统");
}
}];
} else if (@available(iOS 9.0, *)) {
[recorder startRecordingWithMicrophoneEnabled:YES handler:^(NSError * _Nullable error) {
if (!error) {
NSLog(@"录制开始... 9.0 系统");
}
}];
} else {
NSLog(@"系统版本太低,没法玩.");
}
}
#pragma mark - 停止录制
/// 停止录制
- (void)stopRecording {
[_instance turnOffRecord];
}
/// 停止录制
- (void)turnOffRecord {
NSLog(@"结束录制");
dispatch_async(dispatch_get_main_queue(), ^{
[[RPScreenRecorder sharedRecorder] stopRecordingWithHandler:^(RPPreviewViewController * _Nullable previewViewController, NSError * _Nullable error) {
NSLog(@"结束回调");
if (error) { //出错
NSLog(@"出错: %@", error);
} else { //成功回调
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(@"预览控制器消失");
}
- (void)previewController:(RPPreviewViewController *)previewController didFinishWithActivityTypes:(NSSet <NSString *> *)activityTypes {
NSLog(@"用户已经操作! %@", activityTypes);
}
#pragma mark - iOS 10 保存视频的回调
/// 保存视频之后的回调,这个方法不能乱写
- (void)savedPhotoImage:(UIImage*)image didFinishSavingWithError: (NSError *)error contextInfo: (void *)contextInfo {
if (error) {
NSLog(@"保存视频失败!!!");
} else {
NSLog(@"已经成功保存了视频!");
}
}
@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