uni-app原生插件(2)--录屏

上一篇文章记录了截图插件,这篇文章记录以下录屏插件,这两个功能都是最近工作上遇到的,在这里做个记录。

创建录屏拓展Extension File->New->target 搜索broadcast Setup UI Extension

1.png.png

3335bc2c7152ff367f08a36074969b6.png

创建拓展成功后生成两个文件如图所示

d0dccd9fb2a36fba64811c9d0daea72.png

录屏插件录屏后保存到本地,通过APP Group共享空间与工程代码交互 设置APPGroup过程,苹果开发者网站boundID绑定APPGroup,主程序与录屏拓展全部选择target->添加capabili AppGroup,然后选择appgroupID

b0cc013531167f05bacd73733448930.png

![99d1ccf336404d7236eb04d8b5c03dd.png](https://upload-images.jianshu.io/upload_images/1421910-d7c4cebfb8c86021.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

f4a0dc65b5d310ba82eefc0a8e9d849.jpg

99d1ccf336404d7236eb04d8b5c03dd.png

接下来主要是录屏代码

 - (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {
     // User has requested to start the broadcast. Setup info from the UI extension can be supplied but optional.
     NSLog(@"开始录屏");
     [self sendNotificationForMessageWithIdentifier:@"start" userInfo:nil];
     [self initData];
 }

 - (void)broadcastPaused {
     // User has requested to pause the broadcast. Samples will stop being delivered.
 }

 - (void)broadcastResumed {
     // User has requested to resume the broadcast. Samples delivery will resume.
 }

 - (void)broadcastFinished {
     // User has requested to finish the broadcast.
     NSLog(@"结束录屏");
     [self.assetWriter finishWritingWithCompletionHandler:^{
         NSLog(@"结束写入数据");
     }];
     //获取到对应的空间路径就可以在该路径下读写文件
     NSString *time = @"output";
     NSString *fileName = [time stringByAppendingPathExtension:@"mp4"];
     NSString *fullPath = [[self getDocumentPath] stringByAppendingPathComponent:fileName];
     NSURL *pathURL = [[NSFileManager alloc] containerURLForSecurityApplicationGroupIdentifier:@"group.com.iallchain.replaykit-demo"];
     pathURL = [pathURL URLByAppendingPathComponent:@"Library/Documents/output.mp4"];
     NSLog(@"%@==",pathURL);
     [self sendNotificationForMessageWithIdentifier:@"broadcastFinished" userInfo:nil];
 }
 //录屏状态
 - (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
     
     switch (sampleBufferType) {
         case RPSampleBufferTypeVideo:
             // Handle video sample buffer
             NSLog(@"视频流");
             AVAssetWriterStatus status = self.assetWriter.status;
             if (status == AVAssetWriterStatusFailed || status == AVAssetWriterStatusCompleted || status == AVAssetWriterStatusCancelled) {
                 return;
             }
             if (status == AVAssetWriterStatusUnknown) {
                 [self.assetWriter startWriting];
                 CMTime time = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
                 [self.assetWriter startSessionAtSourceTime:time];
                 NSLog(@"写入视频");
             }
             if (status == AVAssetWriterStatusWriting ) {
                 if (self.videoInput.isReadyForMoreMediaData) {
                     BOOL success = [self.videoInput appendSampleBuffer:sampleBuffer];
                     if (!success) {
                         [self stopRecording];
                     }
                 }
             }
             break;
         case RPSampleBufferTypeAudioApp:
             // Handle audio sample buffer for app audio
             break;
         case RPSampleBufferTypeAudioMic:
             // Handle audio sample buffer for mic audio
             if (self.audioInput.isReadyForMoreMediaData) {
                 BOOL success = [self.audioInput appendSampleBuffer:sampleBuffer];
                 if (!success) {
                     [self stopRecording];
                 }
             }
             break;
             
         default:
             break;
     }
 }
 
 - (void)sendNotificationForMessageWithIdentifier:(nullable NSString *)identifier userInfo:(NSDictionary *)info {
     CFNotificationCenterRef const center = CFNotificationCenterGetDarwinNotifyCenter();
     CFDictionaryRef userInfo = (__bridge CFDictionaryRef)info;
     BOOL const deliverImmediately = YES;
     CFStringRef identifierRef = (__bridge CFStringRef)identifier;
     CFNotificationCenterPostNotification(center, identifierRef, NULL, userInfo, deliverImmediately);
 }

 - (AVAssetWriter *)assetWriter{
     if (!_assetWriter) {
         NSError *error = nil;
         NSArray *pathDocuments = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
         NSString *outputURL = pathDocuments[0];
         self.videoOutPath = [[outputURL stringByAppendingPathComponent:@"demo"] stringByAppendingPathExtension:@"mp4"];
         NSLog(@"self.videoOutPath=%@",self.videoOutPath);
         _assetWriter = [[AVAssetWriter alloc] initWithURL:[self getFilePathUrl] fileType:(AVFileTypeMPEG4) error:&error];
         NSLog(@"%@",_assetWriter);
         NSAssert(!error, @"_assetWriter 初始化失败");
     }
     return _assetWriter;
 }

 -(AVAssetWriterInput *)audioInput{
     if (!_audioInput) {
         // 音频参数
         NSDictionary *audioCompressionSettings = @{
             AVEncoderBitRatePerChannelKey:@(28000),
             AVFormatIDKey:@(kAudioFormatMPEG4AAC),
             AVNumberOfChannelsKey:@(1),
             AVSampleRateKey:@(22050)
         };
         _audioInput  = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:audioCompressionSettings];
     }
     return _audioInput;
 }

 -(AVAssetWriterInput *)videoInput{
     if (!_videoInput) {

         CGSize size = [UIScreen mainScreen].bounds.size;
         // 视频大小
         NSInteger numPixels = size.width * size.height;
         // 像素比
         CGFloat bitsPerPixel = 7.5;
         NSInteger bitsPerSecond = numPixels * bitsPerPixel;
         // 码率和帧率设置
         NSDictionary *videoCompressionSettings = @{
             AVVideoAverageBitRateKey:@(bitsPerSecond),//码率
             AVVideoExpectedSourceFrameRateKey:@(25),// 帧率
             AVVideoMaxKeyFrameIntervalKey:@(15),// 关键帧最大间隔
             AVVideoProfileLevelKey:AVVideoProfileLevelH264BaselineAutoLevel,
             AVVideoPixelAspectRatioKey:@{
                     AVVideoPixelAspectRatioVerticalSpacingKey:@(1),
                     AVVideoPixelAspectRatioHorizontalSpacingKey:@(1)
             }
         };
         CGFloat scale = [UIScreen mainScreen].scale;

         // 视频参数
         NSDictionary *videoOutputSettings = @{
             AVVideoCodecKey:AVVideoCodecTypeH264,
             AVVideoScalingModeKey:AVVideoScalingModeResizeAspectFill,
             AVVideoWidthKey:@(size.width*scale),
             AVVideoHeightKey:@(size.height*scale),
             AVVideoCompressionPropertiesKey:videoCompressionSettings
         };

         _videoInput  = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoOutputSettings];
         _videoInput.expectsMediaDataInRealTime = true;
     }
     return _videoInput;
 }

 - (void)stopRecording {
     [self.assetWriter finishWritingWithCompletionHandler:^{
         NSLog(@"结束写入数据");
     }];
 }

 - (NSURL *)getFilePathUrl {
     //NSString *time = [NSDate timestamp];
     //NSString *time = @"replays";
     NSString *time = @"output";
     NSString *fileName = [time stringByAppendingPathExtension:@"mp4"];
     NSString *fullPath = [[self getDocumentPath] stringByAppendingPathComponent:fileName];
     NSLog(@"初始化本地路径%@",fullPath);
     return [NSURL fileURLWithPath:fullPath];
 }

 //这个方法是重点 保存的路径名字要确定好,Library/Documents 后期主程序获取appGroup空间的内容需要用到,关于APPGroup共享空间的使用,可以使用NSFileManager或者NSUserDefaults,这里使用的NSFileManager,关于NSUserDefaults之后再单独写一篇文章记录
 - (NSString *)getDocumentPath {

     static NSString *replaysPath;
     if (!replaysPath) {
         NSFileManager *fileManager = [NSFileManager defaultManager];
         NSURL *documentRootPath = [fileManager containerURLForSecurityApplicationGroupIdentifier:@"group.com.iallchain.replaykit-demo"];
         //replaysPath = [documentRootPath.path stringByAppendingPathComponent:@"Replays"];
         replaysPath = [documentRootPath.path stringByAppendingPathComponent:@"Library/Documents"];
         if (![fileManager fileExistsAtPath:replaysPath]) {
             NSError *error_createPath = nil;
             BOOL success_createPath = [fileManager createDirectoryAtPath:replaysPath withIntermediateDirectories:true attributes:@{} error:&error_createPath];
             if (success_createPath && !error_createPath) {
                 NSLog(@"%@路径创建成功!", replaysPath);
             } else {
                 NSLog(@"%@路径创建失败:%@", replaysPath, error_createPath);
             }
         }else{
             BOOL blDele= [fileManager removeItemAtPath:replaysPath error:nil];
             if (blDele) {
             NSLog(@"dele success");
             }else {
             NSLog(@"dele fail");
             }
             NSLog(@"%@路径已存在!", replaysPath);
             NSError *error_createPath = nil;
             BOOL success_createPath = [fileManager createDirectoryAtPath:replaysPath withIntermediateDirectories:true attributes:@{} error:&error_createPath];
             if (success_createPath && !error_createPath) {
                 NSLog(@"%@路径创建成功!", replaysPath);
             } else {
                 NSLog(@"%@路径创建失败:%@", replaysPath, error_createPath);
             }
         }
         
     }
     return replaysPath;
 }

 - (NSArray <NSURL *> *)fetechAllResource {
     NSFileManager *fileManager = [NSFileManager defaultManager];

     NSString *documentPath = [self getDocumentPath];
     NSURL *documentURL = [NSURL fileURLWithPath:documentPath];
     NSError *error = nil;
     NSArray<NSURL *> *allResource  =  [fileManager contentsOfDirectoryAtURL:documentURL includingPropertiesForKeys:@[] options:(NSDirectoryEnumerationSkipsSubdirectoryDescendants) error:&error];
     return allResource;

 }
 - (void)initData {
     if ([self.assetWriter canAddInput:self.videoInput]) {
         [self.assetWriter addInput:self.videoInput];
     }else{
         NSLog(@"添加input失败");
     }
 }

 - (NSString *) folderSizeAtPath:(NSString*) folderPath{

     NSLog(@"视频路径%@",folderPath);
     NSFileManager* manager = [NSFileManager defaultManager];
     if (![manager fileExistsAtPath:folderPath]) return 0;
     NSEnumerator *childFilesEnumerator = [[manager subpathsAtPath:folderPath] objectEnumerator];
     NSString* fileName;
     long long folderSize = 0;
     NSLog(@"%@==%@",[childFilesEnumerator allObjects],folderPath);
     while ((fileName = [childFilesEnumerator nextObject]) != nil){
         NSString* fileAbsolutePath = [folderPath stringByAppendingPathComponent:fileName];
         NSLog(@"+++%@++++",fileAbsolutePath);
         folderSize += [self fileSizeAtPath:fileAbsolutePath];
     }
     NSLog(@"文件大小%lld",folderSize);
     if (folderSize < 1024.0) {
         return  [NSString stringWithFormat:@"%.2fB",folderSize * 1.0];
     }else if (folderSize >= 1024.0 && folderSize < (1024.0*1024.0)){
         return  [NSString stringWithFormat:@"%.2fKB",folderSize/1024.0];
     }if (folderSize >= (1024.0*1024.0) && folderSize < (1024.0*1024.0*1024.0)) {
         return [NSString stringWithFormat:@"%.2fMB", folderSize/(1024.0*1024.0)];
     }else{
         return [NSString stringWithFormat:@"%.2fGB", folderSize/(1024.0*1024.0*1024.0)];
     }
 }

 - (long long) fileSizeAtPath:(NSString*) filePath{
     NSFileManager* manager = [NSFileManager defaultManager];
     if ([manager fileExistsAtPath:filePath]){
         return [[manager attributesOfItemAtPath:filePath error:nil] fileSize];
     }
     return 0;
 }

接下来是主插件获取录屏插件保存在共享空间内部的视频,并与uni-app进行交互,创建插件上一篇文章具体讲解过,这里就不再详细描述,直接上获取APPGroup空间内容并传给uni-app代码

iOS12以上 使用RPSystemBroadcastPickerView调用系统的录屏功能

 //创建拉起系统录屏分类
 - (instancetype)initWithFrame:(CGRect)frame
 {
     self = [super initWithFrame:frame];
     if (self) {
         if (@available(iOS 12.0, *)) {
             self.broadcastPickerView = [[RPSystemBroadcastPickerView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
             self.broadcastPickerView.preferredExtension = @"com.iallchain.platform.replay.1";
             self.broadcastPickerView.showsMicrophoneButton = YES;
             [self addSubview:self.broadcastPickerView];
         }
     }
     return self;
 }
 //uni-app使用本地按钮执行拉起操作
 //UNI_EXPORT_METHOD方法为与uni-app交互方法,这里不具体描述
 UNI_EXPORT_METHOD(@selector(screenRecording:))
 - (void)screenRecording:(NSDictionary *)options {
     for (UIView *subView in [self getReplayView].broadcastPickerView.subviews) {
         if ([subView isMemberOfClass:[UIButton class]]) {
             UIButton *button = (UIButton *)subView;
             [button sendActionsForControlEvents:UIControlEventAllEvents];
         }
     }
 }

 - (ReplayView *)getReplayView {
     return (ReplayView *)self.view;
 }
 
 #pragma mark - 宿主与extension之间的通知
 - (void)registerForNotificationsWithIdentifier:(nullable NSString *)identifier {
     [self unregisterForNotificationsWithIdentifier:identifier];
     CFNotificationCenterRef const center = CFNotificationCenterGetDarwinNotifyCenter();
     CFStringRef str = (__bridge CFStringRef)identifier;
     CFNotificationCenterAddObserver(center,
                                     (__bridge const void *)(self),
                                     MyHoleNotificationCallback,
                                     str,
                                     NULL,
                                     CFNotificationSuspensionBehaviorDeliverImmediately);
 }

 - (void)unregisterForNotificationsWithIdentifier:(nullable NSString *)identifier {
     CFNotificationCenterRef const center = CFNotificationCenterGetDarwinNotifyCenter();
     CFStringRef str = (__bridge CFStringRef)identifier;
     CFNotificationCenterRemoveObserver(center,
                                        (__bridge const void *)(self),
                                        str,
                                        NULL);
 }
 
 #pragma mark - 接收来自extension的消息
 - (void)addUploaderEventMonitor {
     
     [self registerForNotificationsWithIdentifier:@"broadcastFinished"];
     [self registerForNotificationsWithIdentifier:@"start"];
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(broadcastInfo:) name:ScreenHoleNotificationName object:nil];
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(broadcastInfo:) name:@"start" object:nil];
 }
 
 #pragma mark - 移除Observer
 - (void)removeUploaderEventMonitor {
     
     [self unregisterForNotificationsWithIdentifier:@"broadcastFinished"];
     [self unregisterForNotificationsWithIdentifier:@"start"];
     [[NSNotificationCenter defaultCenter] removeObserver:self name:ScreenHoleNotificationName object:nil];

 }
 

附上uni-app方法

 <view class="container">
         //这个是与插件录屏交互方法声明
         <view class="top-view">
             <dc-replay class="page-container" ref='mycomponent'
             @startVideo="startVideo" @finishVideo="finishVideo" @loadHTMLURL="loadHTMLURL"></dc-replay>
         </view>
         <view class="bottom-view">
             <view class="button-group">
                 <button class="button-view" @click="onScreenRecording">开始录制11111</button>
                 <button class="button-view" @click="getVideoURL">获取视频URL</button>
                 <button class="button-view" @click="deleteVideoFromURL">删除视频</button>
                 <button class="button-view" @click="onGetFile">获取视频文件2222</button>
                 <button class="button-view" @click="playVideo">播放</button>
             </view>
         </view>
         <!-- <video class="videoView"  width="100%" height="200px" :src="fileurl" show-play-btn="true"></video> -->
     </view>
 
 <script>
 import { computed } from "vue";
     export default {
         data() {
             return {
             fileurl: '',
             }
         },
         methods: {
             loadHTMLURL(e) {
                 console.log("loadHTMLURL网页地址传值====",e);
             },
             //这里screenRecording为交互方法
             onScreenRecording: function() {
                 console.log('点击了 开始录制 按钮');
                 this.$refs.mycomponent.screenRecording({});
             }
             
         }
     }
 </script>

接下来是获取appGroup共享空间内容代码

 //获取录屏监听信息
 static NSString * const ScreenHoleNotificationName = @"ScreenHoleNotificationName";

 void MyHoleNotificationCallback(CFNotificationCenterRef center,
                                    void * observer,
                                    CFStringRef name,
                                    void const * object,
                                    CFDictionaryRef userInfo) {
     NSString *identifier = (__bridge NSString *)name;
     NSObject *sender = (__bridge NSObject *)observer;
     //NSDictionary *info = (__bridge NSDictionary *)userInfo;
     NSDictionary *info = CFBridgingRelease(userInfo);
     
     NSLog(@"userInfo %@  %@",userInfo,info);

     NSDictionary *notiUserInfo = @{@"identifier":identifier};
     
     if ([identifier isEqualToString:@"broadcastFinished"]) {
         [[NSNotificationCenter defaultCenter] postNotificationName:ScreenHoleNotificationName
                                                             object:sender
                                                           userInfo:notiUserInfo];
     } else {
         [[NSNotificationCenter defaultCenter] postNotificationName:@"start"
                                                             object:sender
                                                           userInfo:notiUserInfo];
     }
 }
 
 //通过监听录屏状态获取共享空间录屏内容
 - (void)broadcastInfo:(NSNotification *)noti {
     
     NSDictionary *userInfo = noti.userInfo;
     NSString *identifier = userInfo[@"identifier"];
     
     if ([identifier isEqualToString:@"broadcastFinished"]) {
         //reload数据
         NSFileManager *fileManager = [NSFileManager defaultManager];
         NSURL *pathURL = [fileManager containerURLForSecurityApplicationGroupIdentifier:@"group.com.iallchain.replaykit-demo"];
         NSString *databasePath =  [pathURL URLByAppendingPathComponent:@"Library/Documents/output.mp4"].path;
         NSData *data = [NSData dataWithContentsOfFile:databasePath];
         _iscopySuccess = @"1";
         if(data.length != 0){
             [self writeFile2:databasePath];
             _iscopySuccess = @"2";
             //这是模拟播放器,测试录屏视频保存本地后是否可以正常播放,self.videoPath为保存本地路径
             AVPlayer *avPlayer = [[AVPlayer alloc] initWithURL:[NSURL fileURLWithPath:self.videoPath]];
             self.moviePlayer.player = avPlayer;
             [avPlayer play];
         }
         _videoDic = [[NSMutableDictionary alloc] init];
         //这里做了贡献空间视频保存本地相册操作
         if (self.videoPath.length > 0) {
             [self saveVideoWithUrl:[NSURL fileURLWithPath:self.videoPath]];
         } else {
             [self saveVideoWithUrl:pathURL];
         }
         
         NSLog(@"文件大小%@",[self folderSizeAtPath:pathURL.path]);
         
     } else if ([identifier isEqualToString:@"start"])  {
         //与uni-app交互方法 给uni-app传递开始录屏状态
         [self fireEvent:@"startVideo" params:@{} domChanges:nil];
     }
     
 }
 //保存相册操作
 - (void)saveVideoWithUrl:(NSURL *)url {
     PHPhotoLibrary *photoLibrary = [PHPhotoLibrary sharedPhotoLibrary];
     [photoLibrary performChanges:^{
         [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:url];

     } completionHandler:^(BOOL success, NSError * _Nullable error) {
         if (success) {
             NSLog(@"已将视频保存至相册");
             self->_photoalbum = @"2";
         } else {
             NSLog(@"未能保存视频到相册%@",error);
             self->_photoalbum = @"1";
         }
         [self->_videoDic setValue:self->_photoalbum forKey:@"photoalbum"];
         //这个测试使用 给uni-app传值验证是否保存成功
         if ([error isEqual:[NSNull null]] || error == nil) {} else {
             [self->_videoDic setValue:error forKey:@"error"];
         }
         NSLog(@"%@",self->_videoDic);
         //与uni-app交互方法 给uni-app传递结束录屏状态
         [self fireEvent:@"finishVideo" params:@{@"detail":@{@"mapLoaded":self->_videoDic}} domChanges:nil];
     }];
 }
 
 //从共享空间写入本地沙盒文件,这里有个问题,与uni-app交互 选用temp目录保存文件,其他目录不是到是什么原因,获取不到视频文件
 - (void)writeFile2:(NSString* )d {
     //1.初始化一个NSFileManager对象(使用单例)
     NSFileManager *manager = [NSFileManager defaultManager];
     //2.获取根路径
     NSString *rootPath = NSTemporaryDirectory();
     //3.创建文件
     rootPath = [rootPath stringByAppendingPathComponent:@"/Pandora/documents"];
     //4.创建目录
     //createDirectoryAtPath:文件路径
     //********withIntermediateDirectories:是否在当前路径下创建/text/myApp
     [manager createDirectoryAtPath:rootPath withIntermediateDirectories:YES attributes:nil error:nil];
     //添加并写入
     rootPath = [rootPath stringByAppendingPathComponent:@"/output.mp4"];
     NSString *error;
     BOOL isSuccess = [d writeToFile:rootPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
     if (isSuccess) {
         NSLog(@"write success%@",rootPath);
         _writeSuccess = @"1";
     } else {
         NSLog(@"write fail,please record first%@",error);
         _writeSuccess = @"2";
     }
 }

 - (BOOL)clearCacheWithFilePath:(NSString *)path{
     //拿到path路径的下一级目录的子文件夹
     NSArray *subPathArr = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
     NSLog(@"%@",subPathArr);
     NSString *filePath = nil;
     NSError *error = nil;
     for (NSString *subPath in subPathArr)
     {
         filePath = [path stringByAppendingPathComponent:subPath];
         //删除子文件夹
         [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
         if (error) {
             return NO;
         }
     }
     return YES;
 }
 //获取本地沙盒路径
 -(NSString* )videoPath{
     if (!_videoPath) {
         NSString *documentsDirectory = NSTemporaryDirectory();
         NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"/Pandora/documents/output.mp4"];
         NSData *data = [NSData dataWithContentsOfFile:filePath];
         _videoPath = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
         NSLog(@"视频播放地址====%@==",_videoPath);
     }
     return _videoPath;
 }
 
 //测试录屏视频播放
 -(AVPlayerViewController *)moviePlayer{

    if (!_moviePlayer) {
        AVPlayer *avPlayer = [[AVPlayer alloc] initWithURL:[NSURL fileURLWithPath:@""]];
        _moviePlayer=[[AVPlayerViewController alloc]init];
        _moviePlayer.player = avPlayer;
        _moviePlayer.view.frame=CGRectMake(0, 100, self.view.frame.size.width, 200);
        _moviePlayer.view.autoresizingMask=UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
        _moviePlayer.showsPlaybackControls = YES;
    }
     return _moviePlayer;
     
 }

接下来是uni-app获取沙盒文件视频代码

 finishVideo: function(e) {
                 console.log('完成录屏');
                 // 原生端传递的数据保存在 e.detail 中
                 console.log(e)
                 console.log(e.detail['mapLoaded']['videopath'])
                 var copyPath = plus.io.convertLocalFileSystemURL("_doc/vv-work");
                 var copyPathName = copyPath + "/output.mp4";
                 const p = this.copyPathToSandboxPath(copyPath, copyPathName, e.detail.mapLoaded.videopath);
                 uni.showModal({
                     title: '提示',
                     content: "完成录屏",
                     showCancel: false
                 })
             },
             //直接获取的路径不能使用,需要uin-app转换一下可以使用的路径
             copyPathToSandboxPath(copyPath, copyPathName, filePath) {
                     return new Promise((resolve, reject) => {
                         console.log("copy -> copyPath:" + copyPath);
                         console.log("copy -> copyPathName:" + copyPathName);
                         console.log("copy -> filePath:" + filePath);
                         filePath = filePath.replace("file://", "");
                         console.log("filePath-->" + filePath);
             
                         var NSFileManager = plus.ios.importClass("NSFileManager");
                         var fileManager = NSFileManager.defaultManager();
             
                         var isFileExist_Path = plus.ios.invoke(fileManager, "fileExistsAtPath:", copyPath);
                         console.log("isFileExist_Path:" + isFileExist_Path);
                         if (isFileExist_Path == false) {
                             var isCreateDirectory = plus.ios.invoke(fileManager,
                                 "createDirectoryAtPath:withIntermediateDirectories:attributes:error:", copyPath,
                                 true, null, null);
                             console.log("isCreateDirectory:" + isCreateDirectory);
                         }
             
                         var isFileExist_PathName = plus.ios.invoke(fileManager, "fileExistsAtPath:", copyPathName);
                         console.log("isFileExist_PathName:" + isFileExist_PathName);
                         if (isFileExist_PathName == true) {
                             // 如果存在 删除
                             var isRemove = plus.ios.invoke(fileManager, "removeItemAtPath:error:", copyPathName, null);
                             console.log("isRemove:" + isRemove);
                         }
             
                         var isCopy = plus.ios.invoke(fileManager, "copyItemAtPath:toPath:error:", filePath,
                             copyPathName, null);
                         if (isCopy) {
                             console.log("FFFFFF isCopy true :" + copyPathName);
                             this.fileurl = copyPathName
                             // resolve("success")
                         } else {
                             console.log("FFFFFF copyItem failed")
                             reject("failed")
                         }
                     })
                 },
             
             startVideo: function(e) {
                 console.log('开始录屏');
                 uni.showModal({
                     title: '提示',
                     content: "开始录屏",
                     showCancel: false
                 })
             },

录屏插件打包 导入uni-app对应的文件夹 如下图 然后commond+b

88a2413c8e32b662e8993e794b0a967.png

然后选择products 选择录屏插件show in finder找到.appex结尾的文件 拖入到uni-app文件夹中

357c254ecb1f2040da7f594ae36ce5f.png

然后在uni-app配置文件写一下录屏配置信息,这些内容官网都有具体,这里附上测试代码截图

15c4001828fb1e93d8251aecc30a937.png

1d3df14adc921fd5ae338979d619a51.png

最后附上运行效果图

3c0c71a342dafd715ad698f3abe1895.png

c81aac249a2b645282cc5f1ddd7776d.png

dd949969a1fc0dd0be66c94d67f7bf9.png

关于录屏的文章就记录到这里了

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

推荐阅读更多精彩内容