// // videoPlayViewController.m // Private-X // // Created by xd h on 2024/5/21. // #import "videoPlayViewController.h" #import #import @interface videoPlayViewController () @property (nonatomic, strong) WKWebView *curWKWebView; @property (nonatomic, strong)AVPlayer*player; @end @implementation videoPlayViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. [self.toolBar setHidden:YES]; [self.navigationBar setHidden:YES]; [self.navBarBGView setHidden:NO]; //self.navBarBGView.backgroundColor = [UIColor whiteColor]; [self.view setBackgroundColor:[UIColor whiteColor]]; //[self setUpVideoPlayer]; } #pragma mark ---播放器 - (void)setUpVideoPlayer { //创建网页配置对象 WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]; // 是使用h5的视频播放器在线播放, 还是使用原生播放器全屏播放 //config.allowsInlineMediaPlayback = YES; //设置视频是否需要用户手动播放 设置为NO则会允许自动播放 config.mediaTypesRequiringUserActionForPlayback = NO; //设置是否允许画中画技术 在特定设备上有效 config.allowsPictureInPictureMediaPlayback = NO; //设置请求的User-Agent信息中应用程序名称 iOS9后可用 //config.applicationNameForUserAgent = @"ChinaDailyForiPad"; //自定义的WKScriptMessageHandler 是为了解决内存不释放的问题 // WeakWebViewScriptMessageDelegate *weakScriptMessageDelegate = [[WeakWebViewScriptMessageDelegate alloc] initWithDelegate:self]; //这个类主要用来做native与JavaScript的交互管理 // 注入js 解决进入播放就横屏问题 WKUserContentController *content = [[WKUserContentController alloc]init]; //1解决解决进入播放就横屏问题 NSString *jSString = @"document.getElementsByTagName('video')[0].setAttribute('playsinline','playsinline');"; WKUserScript *wkUserScript = [[WKUserScript alloc] initWithSource:jSString injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES]; [content addUserScript:wkUserScript]; //2,暂停播放监听 NSString *PausePlayListenerjSString = @"document.getElementsByTagName('video')[0].addEventListener('pause', function(e) {window.webkit.messageHandlers.pause.postMessage(\"pause\");})"; WKUserScript *PausePlayListenerwkUScript = [[WKUserScript alloc] initWithSource:PausePlayListenerjSString injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES]; [content addUserScript:PausePlayListenerwkUScript]; //3,继续播放监听 NSString *ContinuePlayingListenerjSString = @"document.getElementsByTagName('video')[0].addEventListener('play', function(e) {window.webkit.messageHandlers.play.postMessage(\"play\");})"; WKUserScript *ContinuePlayingListenerwkUScript = [[WKUserScript alloc] initWithSource:ContinuePlayingListenerjSString injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES]; [content addUserScript:ContinuePlayingListenerwkUScript]; //4,播放结束监听 NSString *EndOfPlayListenerjSString = @"document.getElementsByTagName('video')[0].addEventListener('ended', function(e) {window.webkit.messageHandlers.ended.postMessage(\"ended\");})"; WKUserScript *EndOfPlayListenerwkUScript = [[WKUserScript alloc] initWithSource:EndOfPlayListenerjSString injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES]; [content addUserScript:EndOfPlayListenerwkUScript]; //添加一个协议 [content addScriptMessageHandler:self name:@"play"]; [content addScriptMessageHandler:self name:@"pause"]; [content addScriptMessageHandler:self name:@"ended"]; //5,暂停播放播放 NSString *pauseJS = @"var videos = document.getElementsByTagName(\"video\");\ function pauseVideo(){videos[0].pause();}\ function playVideo(){videos[0].play();}"; WKUserScript *PausePlaywkUScript = [[WKUserScript alloc] initWithSource:pauseJS injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES]; [content addUserScript:PausePlaywkUScript]; config.userContentController= content; _curWKWebView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_W, SCREEN_H) configuration:config]; // UI代理 _curWKWebView.UIDelegate = self; // 导航代理 _curWKWebView.navigationDelegate = self; [self.view addSubview:_curWKWebView]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self beginPlayVideoFun]; } - (void)beginPlayVideoFun { NSString *filePath = _VideoDataMode.path; NSString *urlStr = ksharedAppDelegate.NASFileByBoxService; NSString *fileUrl = [[NSString alloc] initWithFormat:@"%@getFile?path=%@",urlStr,filePath]; fileUrl = [fileUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; //fileUrl = @"http://transfer.armclouding.com:10010/getFile?path=/storage/006A-A69C/bf0308/Screenrecording_20231101_163026.mp4"; fileUrl = @"http://transfertest.armclouding.com:10010/getFile?path=/sdcard/bb.mp4"; NSURL * sourceMovieURL= [NSURL URLWithString:fileUrl]; // 根据URL创建请求 // NSURLRequest *request = [NSURLRequest requestWithURL:sourceMovieURL]; // [_curWKWebView loadRequest:request]; //111111111 NSURL *videoUrl = sourceMovieURL; AVAsset *asset = [AVAsset assetWithURL:videoUrl]; AVPlayerItem*videoItem = [AVPlayerItem playerItemWithAsset:asset]; // 视频资源信息 M _player = [AVPlayer playerWithPlayerItem:videoItem]; // 视频控制播放层 C AVPlayerLayer*playerLayer = [[AVPlayerLayer alloc]init]; // 视频展示层 V playerLayer.player = _player; playerLayer.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height); [self.view.layer addSublayer:playerLayer]; // 添加到父视图的layer层 // 监听视频状态 [videoItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:@"item.status"]; // 监听缓冲进度 [videoItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:@"item.loaded"]; //获取播放进度 [_player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) { float startSeconds = CMTimeGetSeconds(time); // 已经播放的秒数 HLog(@"22222 %f",startSeconds); }]; // 接收播放完成通知 //[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handlePlayEnd) name:AVPlayerItemDidPlayToEndTimeNotification object:nil]; } #pragma mark 事件代理 // 页面开始加载时调用 -(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{ } // 当内容开始返回时调用 - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{ } // 页面加载完成之后调用 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{//这里修改导航栏的标题,动态改变 } // 页面加载失败时调用 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation{ } // 接收到服务器跳转请求之后再执行 - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{ } // 在收到响应后,决定是否跳转 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{ HLog(@"%@",webView); HLog(@"%@",navigationResponse); WKNavigationResponsePolicy actionPolicy = WKNavigationResponsePolicyAllow; //这句是必须加上的,不然会异常 decisionHandler(actionPolicy); } // 在发送请求之前,决定是否跳转 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{ HLog(@"URL=======%@", navigationAction.request.URL); HLog(@"URL.scheme=======%@", navigationAction.request.URL.scheme); WKNavigationActionPolicy actionPolicy = WKNavigationActionPolicyAllow; if (navigationAction.targetFrame == nil) { [webView loadRequest:navigationAction.request]; } if (navigationAction.navigationType==WKNavigationTypeBackForward) {//判断是返回类型 } //这句是必须加上的,不然会异常 decisionHandler(actionPolicy); //NSString *url = navigationAction.request.URL.absoluteString; } #pragma mark - WKScriptMessageHandler - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { HLog(@"%@",NSStringFromSelector(_cmd)); HLog(@"%@",message); HLog(@"%@",message.body); HLog(@"%@",message.name); NSString *jsonStr = message.body; // HLog(@"%@",jsonStr); KWeakSelf if ([message.name caseInsensitiveCompare:@"play"] == NSOrderedSame) { NSLog(@"video is play"); } else if ([message.name caseInsensitiveCompare:@"pause"] == NSOrderedSame) { NSLog(@"video is pause"); } else if ([message.name caseInsensitiveCompare:@"ended"] == NSOrderedSame) { NSLog(@"video is ended"); [weakSelf playVideo]; } } #pragma mark 原生调用JS暂停 - (void)pausePlay { [_curWKWebView evaluateJavaScript:@"pauseVideo()" completionHandler:^(id _Nullable response, NSError * _Nullable error) { NSLog(@"response:%@,error:%@",response,error); }]; } - (void)playVideo { [_curWKWebView evaluateJavaScript:@"playVideo()" completionHandler:^(id _Nullable response, NSError * _Nullable error) { NSLog(@"response:%@,error:%@",response,error); }]; } //通过KVO来观察status属性的变化,来获得播放之前的错误信息 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"status"]) { AVPlayerStatus status = [change[NSKeyValueChangeNewKey] intValue]; switch (status) { case AVPlayerStatusFailed: { NSError *error = self.player.currentItem.error; NSLog(@"url有误:%@",error); } break; case AVPlayerStatusReadyToPlay: { NSLog(@"准备好播放了"); } break; case AVPlayerStatusUnknown: { NSLog(@"视频资源出现未知错误"); } break; default: break; } } } @end