videoPlayViewController.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. //
  2. // videoPlayViewController.m
  3. // 双子星云手机
  4. //
  5. // Created by xd h on 2024/5/21.
  6. //
  7. #import "videoPlayViewController.h"
  8. #import <WebKit/WebKit.h>
  9. #import <AVFoundation/AVFoundation.h>
  10. #import "TBPlayer.h"
  11. @interface videoPlayViewController ()<WKUIDelegate,WKNavigationDelegate,WKScriptMessageHandler>
  12. @property (nonatomic, strong) WKWebView *curWKWebView;
  13. @property (nonatomic, strong)AVPlayer*player;
  14. @end
  15. @implementation videoPlayViewController
  16. - (void)viewDidLoad {
  17. [super viewDidLoad];
  18. // Do any additional setup after loading the view.
  19. [self.toolBar setHidden:YES];
  20. [self.navigationBar setHidden:YES];
  21. [self.navBarBGView setHidden:NO];
  22. //self.navBarBGView.backgroundColor = [UIColor whiteColor];
  23. [self.view setBackgroundColor:[UIColor whiteColor]];
  24. //[self setUpVideoPlayer];
  25. }
  26. #pragma mark ---播放器
  27. - (void)setUpVideoPlayer {
  28. //创建网页配置对象
  29. WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
  30. // 是使用h5的视频播放器在线播放, 还是使用原生播放器全屏播放
  31. //config.allowsInlineMediaPlayback = YES;
  32. //设置视频是否需要用户手动播放 设置为NO则会允许自动播放
  33. config.mediaTypesRequiringUserActionForPlayback = NO;
  34. //设置是否允许画中画技术 在特定设备上有效
  35. config.allowsPictureInPictureMediaPlayback = NO;
  36. //设置请求的User-Agent信息中应用程序名称 iOS9后可用
  37. //config.applicationNameForUserAgent = @"ChinaDailyForiPad";
  38. //自定义的WKScriptMessageHandler 是为了解决内存不释放的问题
  39. // WeakWebViewScriptMessageDelegate *weakScriptMessageDelegate = [[WeakWebViewScriptMessageDelegate alloc] initWithDelegate:self];
  40. //这个类主要用来做native与JavaScript的交互管理
  41. // 注入js 解决进入播放就横屏问题
  42. WKUserContentController *content = [[WKUserContentController alloc]init];
  43. //1解决解决进入播放就横屏问题
  44. NSString *jSString = @"document.getElementsByTagName('video')[0].setAttribute('playsinline','playsinline');";
  45. WKUserScript *wkUserScript = [[WKUserScript alloc] initWithSource:jSString injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
  46. [content addUserScript:wkUserScript];
  47. //2,暂停播放监听
  48. NSString *PausePlayListenerjSString = @"document.getElementsByTagName('video')[0].addEventListener('pause', function(e) {window.webkit.messageHandlers.pause.postMessage(\"pause\");})";
  49. WKUserScript *PausePlayListenerwkUScript = [[WKUserScript alloc] initWithSource:PausePlayListenerjSString injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
  50. [content addUserScript:PausePlayListenerwkUScript];
  51. //3,继续播放监听
  52. NSString *ContinuePlayingListenerjSString = @"document.getElementsByTagName('video')[0].addEventListener('play', function(e) {window.webkit.messageHandlers.play.postMessage(\"play\");})";
  53. WKUserScript *ContinuePlayingListenerwkUScript = [[WKUserScript alloc] initWithSource:ContinuePlayingListenerjSString injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
  54. [content addUserScript:ContinuePlayingListenerwkUScript];
  55. //4,播放结束监听
  56. NSString *EndOfPlayListenerjSString = @"document.getElementsByTagName('video')[0].addEventListener('ended', function(e) {window.webkit.messageHandlers.ended.postMessage(\"ended\");})";
  57. WKUserScript *EndOfPlayListenerwkUScript = [[WKUserScript alloc] initWithSource:EndOfPlayListenerjSString injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
  58. [content addUserScript:EndOfPlayListenerwkUScript];
  59. //添加一个协议
  60. [content addScriptMessageHandler:self name:@"play"];
  61. [content addScriptMessageHandler:self name:@"pause"];
  62. [content addScriptMessageHandler:self name:@"ended"];
  63. //5,暂停播放播放
  64. NSString *pauseJS = @"var videos = document.getElementsByTagName(\"video\");\
  65. function pauseVideo(){videos[0].pause();}\
  66. function playVideo(){videos[0].play();}";
  67. WKUserScript *PausePlaywkUScript = [[WKUserScript alloc] initWithSource:pauseJS injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
  68. [content addUserScript:PausePlaywkUScript];
  69. config.userContentController= content;
  70. _curWKWebView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_W, SCREEN_H) configuration:config];
  71. // UI代理
  72. _curWKWebView.UIDelegate = self;
  73. // 导航代理
  74. _curWKWebView.navigationDelegate = self;
  75. [self.view addSubview:_curWKWebView];
  76. }
  77. - (void)viewWillAppear:(BOOL)animated
  78. {
  79. [super viewWillAppear:animated];
  80. [self beginPlayVideoFun];
  81. }
  82. - (void)beginPlayVideoFun
  83. {
  84. NSString *filePath = _VideoDataMode.path;
  85. NSString *urlStr = ksharedAppDelegate.NASFileService;
  86. NSString *fileUrl = [[NSString alloc] initWithFormat:@"%@getFile?path=%@",urlStr,filePath];
  87. fileUrl = [fileUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
  88. NSURL * sourceMovieURL= [NSURL URLWithString:fileUrl];
  89. // 根据URL创建请求
  90. // NSURLRequest *request = [NSURLRequest requestWithURL:sourceMovieURL];
  91. // [_curWKWebView loadRequest:request];
  92. //111111111
  93. NSURL *videoUrl = sourceMovieURL;
  94. AVAsset *asset = [AVAsset assetWithURL:videoUrl];
  95. AVPlayerItem*videoItem = [AVPlayerItem playerItemWithAsset:asset]; // 视频资源信息 M
  96. _player = [AVPlayer playerWithPlayerItem:videoItem]; // 视频控制播放层 C
  97. AVPlayerLayer*playerLayer = [[AVPlayerLayer alloc]init]; // 视频展示层 V
  98. playerLayer.player = _player;
  99. playerLayer.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height);
  100. [self.view.layer addSublayer:playerLayer]; // 添加到父视图的layer层
  101. // 监听视频状态
  102. [videoItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:@"item.status"];
  103. // 监听缓冲进度
  104. [videoItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:@"item.loaded"];
  105. //获取播放进度
  106. [_player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
  107. float startSeconds = CMTimeGetSeconds(time); // 已经播放的秒数
  108. HLog(@"22222 %f",startSeconds);
  109. }];
  110. // 接收播放完成通知
  111. //[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handlePlayEnd) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
  112. }
  113. #pragma mark 事件代理
  114. // 页面开始加载时调用
  115. -(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
  116. }
  117. // 当内容开始返回时调用
  118. - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{
  119. }
  120. // 页面加载完成之后调用
  121. - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{//这里修改导航栏的标题,动态改变
  122. }
  123. // 页面加载失败时调用
  124. - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation{
  125. }
  126. // 接收到服务器跳转请求之后再执行
  127. - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{
  128. }
  129. // 在收到响应后,决定是否跳转
  130. - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
  131. HLog(@"%@",webView);
  132. HLog(@"%@",navigationResponse);
  133. WKNavigationResponsePolicy actionPolicy = WKNavigationResponsePolicyAllow;
  134. //这句是必须加上的,不然会异常
  135. decisionHandler(actionPolicy);
  136. }
  137. // 在发送请求之前,决定是否跳转
  138. - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
  139. HLog(@"URL=======%@", navigationAction.request.URL);
  140. HLog(@"URL.scheme=======%@", navigationAction.request.URL.scheme);
  141. WKNavigationActionPolicy actionPolicy = WKNavigationActionPolicyAllow;
  142. if (navigationAction.targetFrame == nil) {
  143. [webView loadRequest:navigationAction.request];
  144. }
  145. if (navigationAction.navigationType==WKNavigationTypeBackForward) {//判断是返回类型
  146. }
  147. //这句是必须加上的,不然会异常
  148. decisionHandler(actionPolicy);
  149. //NSString *url = navigationAction.request.URL.absoluteString;
  150. }
  151. #pragma mark - WKScriptMessageHandler
  152. - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
  153. HLog(@"%@",NSStringFromSelector(_cmd));
  154. HLog(@"%@",message);
  155. HLog(@"%@",message.body);
  156. HLog(@"%@",message.name);
  157. NSString *jsonStr = message.body; //
  158. HLog(@"%@",jsonStr);
  159. KWeakSelf
  160. if ([message.name caseInsensitiveCompare:@"play"] == NSOrderedSame) {
  161. NSLog(@"video is play");
  162. }
  163. else if ([message.name caseInsensitiveCompare:@"pause"] == NSOrderedSame) {
  164. NSLog(@"video is pause");
  165. }
  166. else if ([message.name caseInsensitiveCompare:@"ended"] == NSOrderedSame) {
  167. NSLog(@"video is ended");
  168. [weakSelf playVideo];
  169. }
  170. }
  171. #pragma mark 原生调用JS暂停
  172. - (void)pausePlay
  173. {
  174. [_curWKWebView evaluateJavaScript:@"pauseVideo()" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
  175. NSLog(@"response:%@,error:%@",response,error);
  176. }];
  177. }
  178. - (void)playVideo
  179. {
  180. [_curWKWebView evaluateJavaScript:@"playVideo()" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
  181. NSLog(@"response:%@,error:%@",response,error);
  182. }];
  183. }
  184. //通过KVO来观察status属性的变化,来获得播放之前的错误信息
  185. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
  186. {
  187. if ([keyPath isEqualToString:@"status"]) {
  188. AVPlayerStatus status = [change[NSKeyValueChangeNewKey] intValue];
  189. switch (status) {
  190. case AVPlayerStatusFailed:
  191. {
  192. NSError *error = self.player.currentItem.error;
  193. NSLog(@"url有误:%@",error);
  194. }
  195. break;
  196. case AVPlayerStatusReadyToPlay:
  197. {
  198. NSLog(@"准备好播放了");
  199. }
  200. break;
  201. case AVPlayerStatusUnknown:
  202. {
  203. NSLog(@"视频资源出现未知错误");
  204. }
  205. break;
  206. default:
  207. break;
  208. }
  209. }
  210. }
  211. @end