// // YMWebArticleView.m // MSYOUPAI // // Created by YoMi on 2024/2/15. // Copyright © 2024 MS. All rights reserved. // #import "YMWebArticleView.h" #import "YMWebArticleViewModel.h" #import "YOUPAILZLiveAudienceVC.h" #import "YOUPAILCIMSessionVC.h" @interface YMWebArticleView() /// 网页文章VM @property (nonatomic, strong) YMWebArticleViewModel *viewModel; /// 浏览器配置 @property (nonatomic, strong) WKWebViewConfiguration *webConfig; /// 网页文章浏览器 @property (nonatomic, strong) WKWebView *webArticleView; /// 进度条 @property (nonatomic, strong) UIProgressView *progressView; /// 当前Url @property (nonatomic, strong) NSURL *currentUrl; @end @implementation YMWebArticleView - (void)ym_setupViews{ [self addSubview:self.progressView]; [self addSubview:self.webArticleView]; } - (void)updateConstraints{ [self.progressView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self); make.left.equalTo(self); make.right.equalTo(self); make.height.mas_equalTo(adapt(2)); }]; [self.webArticleView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.progressView.mas_bottom); make.left.equalTo(self); make.right.equalTo(self); make.bottom.equalTo(self); }]; [super updateConstraints]; } - (void)ym_bindViewModel:(YMWebArticleViewModel*)viewModel{ if (!viewModel) { return; } _viewModel = viewModel; @weakify(self) [[[[RACObserve(self.viewModel, webArticleUrl) distinctUntilChanged] deliverOnMainThread] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(NSString * webArticleUrl) { @strongify(self) [self web_loadURLString:webArticleUrl]; }]; [[self.viewModel.refreshUISubject takeUntil:self.rac_willDeallocSignal] subscribeNext:^(id result) { @strongify(self) [self.webArticleView reload]; }]; self.webArticleView.ba_web_didStartBlock = ^(WKWebView *webView, WKNavigation *navigation) { @strongify(self) NSLog(@"开始加载网页"); }; self.webArticleView.ba_web_didFinishBlock = ^(WKWebView *webView, WKNavigation *navigation) { @strongify(self) NSLog(@"加载网页结束"); // WKWebview 禁止长按(超链接、图片、文本...)弹出效果 [webView ba_web_stringByEvaluateJavaScript:@"document.documentElement.style.webkitTouchCallout='none'" completionHandler:nil]; [webView ba_web_stringByEvaluateJavaScript:@"document.body.offsetHeight" completionHandler:^(id _Nullable result, NSError * _Nullable error) { [self.webArticleView mas_updateConstraints:^(MASConstraintMaker *make) { make.height.mas_equalTo([result doubleValue]); }]; }]; }; self.webArticleView.ba_web_isLoadingBlock = ^(BOOL isLoading, CGFloat progress) { @strongify(self) [self web_progressShow]; self.progressView.progress = progress; if (self.progressView.progress == 1.0f){ [self web_progressHidden]; } }; self.webArticleView.ba_web_getCurrentUrlBlock = ^(NSURL * _Nonnull currentUrl) { @strongify(self) self.currentUrl = currentUrl; }; } - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { // if ([message.name isEqualToString:@"openUserDetail"]) { // //int userId,int type // 用户id // NSLog(@"openUserDetail-方法名:%@", message.name); // NSLog(@"openUserDetail-参数:%@", message.body); // if ([message.body isKindOfClass:[NSDictionary class]]) { // NSDictionary *dict = message.body; // NSNumber *type = dict[@"type"]; // NSNumber *userId = dict[@"userId"]; // if ([type isEqualToNumber:@1]) { // [self.viewModel.gotoPersonalPageSubject sendNext:@([userId intValue])]; // } // } // }else if ([message.name isEqualToString:@"openUserLive"]){ // // String roomId // 直播间id // NSLog(@"openUserLive-方法名:%@", message.name); // NSLog(@"openUserLive-参数:%@", message.body); // NSNumber *roomId = message.body; // WS(weakSelf) // [ZCHUDHelper showWithStatus:nil]; // [LCHttpHelper requestWithURLString:JoinLive parameters:@{@"room_id":[NSString stringWithFormat:@"%@",roomId]} needToken:YES type:HttpRequestTypePost success:^(id responseObject) { // NSDictionary* dict = (NSDictionary*)responseObject; // NSInteger code = [[dict objectForKey:@"code"] integerValue]; // if (code == 0) { // [ZCHUDHelper dismiss]; // [[YOUPAILZChatRoomManager shareManager] youpaifcloseChatRoom]; // YOUPAILZLiveModel *liveModel = [YOUPAILZLiveModel mj_objectWithKeyValues:[dict objectForKey:@"data"]]; // YOUPAILZLiveAudienceVC *audienceVC = [[YOUPAILZLiveAudienceVC alloc] initWithModel:liveModel]; // [[YMGlobalUtils getCurrentVC].navigationController pushViewController:audienceVC animated:YES]; // }else{ // [ZCHUDHelper showTitle:[dict objectForKey:@"message"]]; // } // } failure:^(NSError *error) { // [ZCHUDHelper showTitle:error.localizedDescription]; // }]; // // }else if ([message.name isEqualToString:@"openActivity"]){ // //int linkType,String linkUrl // // NSLog(@"openActivity-方法名:%@", message.name); // NSLog(@"openActivity-参数:%@", message.body); // // if ([message.body isKindOfClass:[NSDictionary class]]) { // NSDictionary *dict = message.body; // NSNumber *link_type = dict[@"linkType"]; // NSString *link_url = dict[@"linkUrl"]; // if ([link_type isEqualToNumber:@1]) { // ZCBaseWebVC* baseWeb = [[ZCBaseWebVC alloc]init]; // baseWeb.contentUrl = link_url; // [[YMGlobalUtils getCurrentVC].navigationController pushViewController:baseWeb animated:YES]; // }else if ([link_type isEqualToNumber:@2]||[link_type isEqualToNumber:@3]){ // [[LCTools getCurrentVC] youpaifpageToStr:link_url]; // } // } // }else if ([message.name isEqualToString:@"openMainActivity"]){ // NSLog(@"openMainActivity-方法名:%@", message.name); // NSLog(@"openMainActivity-参数:%@", message.body); // if ([message.body isKindOfClass:[NSDictionary class]]) { // NSDictionary *dict = message.body; // NSString *type = dict[@"type"]; // [[LCTools getCurrentVC] youpaifpageToStr:type]; // } // }else if ([message.name isEqualToString:@"showPay"]){ // NSLog(@"showPay-方法名:%@", message.name); // NSLog(@"showPay-参数:%@", message.body); // if ([message.body isKindOfClass:[NSDictionary class]]) { // NSDictionary *dict = message.body; // NSString *ios_product_id = [NSString stringWithFormat:@"%@",dict[@"ios_product_id"]]; // [self applePay:ios_product_id]; // // } // // }else if([message.name isEqualToString:@"showShareDialog"]){ // // if ([message.body isKindOfClass:[NSDictionary class]]) { // // NSDictionary *dict = message.body; // // NSString *imageUrl = [NSString stringWithFormat:@"%@",dict[@"imageUrl"]]; // // NSString *weChatUrl = [NSString stringWithFormat:@"%@",dict[@"weChatUrl"]]; // // [self shareWithQrcodeUrl:imageUrl Url:weChatUrl]; // // } // // // // } // }else if([message.name isEqualToString:@"copyInviteCode"]){ // NSLog(@"copyInviteCode-方法名:%@", message.name); // NSLog(@"copyInviteCode-参数:%@", message.body); // if ([message.body isKindOfClass:[NSDictionary class]]) { // NSDictionary *dict = message.body; // NSString *inviteCode = [NSString stringWithFormat:@"%@",dict[@"inviteCode"]]; // UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; // pasteboard.string = inviteCode; // [ZCHUDHelper showTitle:@"复制成功,快去粘贴吧!"]; // } // // }else if([message.name isEqualToString:@"showPosterDialog"]){ // NSLog(@"showPosterDialog-方法名:%@", message.name); // NSLog(@"showPosterDialog-参数:%@", message.body); // if ([message.body isKindOfClass:[NSDictionary class]]) { // NSDictionary *dict = message.body; // YOUPAILZShareApplicationModel *model = [YOUPAILZShareApplicationModel mj_objectWithKeyValues:dict]; // YOUPAILZShareApplicationWindow *vc = [[YOUPAILZShareApplicationWindow alloc] init]; // vc.youpaipmodel = model; // vc.isTouchDismiss = YES; // [[LCTools getCurrentVC] TFPresentVC:vc completion:^{}]; // } // // }else if([message.name isEqualToString:@"getUserId"]){ // if ([message.body isKindOfClass:[NSDictionary class]]) { // NSDictionary *dict = message.body; // NSString *methodName = [dict objectForKey:@"fn"]; // [self.wkwebView evaluateJavaScript:[NSString stringWithFormat:@"%@('%@')",methodName,[LCSaveModel getUserModel].youpaipuserinfo.youpaipuser_id] completionHandler:^(id _Nullable result, NSError * _Nullable error) { // NSLog(@"%@", error); // }]; // } // // }else if([message.name isEqualToString:@"startP2PSession"]){ // NSLog(@"startP2PSession方法名:%@", message.name); // NSLog(@"startP2PSession参数:%@", message.body); // NIMSession *session = [NIMSession session:[LCSaveData getServerId] type:NIMSessionTypeP2P]; // if (session) { // @weakify(self); // [ZCHUDHelper show]; // [[[NIMSDK sharedSDK] userManager] fetchUserInfos:@[session.sessionId] completion:^(NSArray * _Nullable users, NSError * _Nullable error) { // @strongify(self); // [ZCHUDHelper dismiss]; // YOUPAILCIMSessionVC *vc = [[YOUPAILCIMSessionVC alloc] initWithSession:session]; // [[LCTools getContainNavigationControllerCurrentVC].navigationController pushViewController:vc animated:YES]; // }]; // } // }else if ([message.name isEqualToString:@"showH5Dialog"]){ // //int linkType,String linkUrl // NSLog(@"showH5Dialog方法名:%@", message.name); // NSLog(@"showH5Dialog参数:%@", message.body); // // if ([message.body isKindOfClass:[NSDictionary class]]) { // NSDictionary *dict = message.body; // NSString *gravity = dict[@"gravity"]; // CGFloat width = [dict[@"width"] floatValue]; // CGFloat height = [dict[@"height"] floatValue]; // NSString *loadUrl = dict[@"loadUrl"]; // // YOUPAIHRWebWindow *window = [[YOUPAIHRWebWindow alloc] init]; // window.youpaipgravity = gravity; // window.youpaipwidth = width; // window.youpaipheight = height; // window.youpaipurl = loadUrl; // [[LCTools getCurrentVC] TFPresentVC:window completion:^{}]; // } // }else if ([message.name isEqualToString:@"closeWindow"]){ // [[LCTools getContainNavigationControllerCurrentVC].navigationController popViewControllerAnimated:YES]; // }else if([message.name isEqualToString:@"showNewShareDialog"]){ // if ([message.body isKindOfClass:[NSDictionary class]]) { // NSDictionary *dict = message.body; // NSString *title = [NSString stringWithFormat:@"%@",dict[@"title"]]; // NSString *linkUrl = [NSString stringWithFormat:@"%@",dict[@"linkUrl"]]; // NSString *thumbUrl = [NSString stringWithFormat:@"%@",dict[@"thumbUrl"]]; // NSString *des = [NSString stringWithFormat:@"%@",dict[@"des"]]; // [self shareWithTitle:title linkUrl:linkUrl thumbUrl:thumbUrl des:des]; // } // } // } //iOS9.0以上异常终止时调用 - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView{ [webView reload]; } - (void)web_progressShow{ // 开始加载网页时展示出progressView self.progressView.hidden = NO; // 开始加载网页的时候将progressView的Height恢复为1.5倍 self.progressView.transform = CGAffineTransformMakeScale(1.0f, 1.5f); // 防止progressView被网页挡住 [self bringSubviewToFront:self.progressView]; } - (void)web_progressHidden{ /* *添加一个简单的动画,将progressView的Height变为1.4倍,在开始加载网页的代理中会恢复为1.5倍 *动画时长0.25s,延时0.3s后开始动画 *动画结束后将progressView隐藏 */ [UIView animateWithDuration:0.25f delay:0.3f options:UIViewAnimationOptionCurveEaseOut animations:^{ self.progressView.transform = CGAffineTransformMakeScale(1.0f, 1.4f); } completion:^(BOOL finished) { self.progressView.hidden = YES; }]; } /** * 加载一个 webview * * @param request 请求的 NSURL URLRequest */ - (void)web_loadRequest:(NSURLRequest *)request{ [self.webArticleView ba_web_loadRequest:request]; } /** * 加载一个 webview * * @param URL 请求的 URL */ - (void)web_loadURL:(NSURL *)URL{ [self.webArticleView ba_web_loadURL:URL]; } /** * 加载一个 webview * * @param URLString 请求的 URLString */ - (void)web_loadURLString:(NSString *)URLString{ [self.webArticleView ba_web_loadURLString:URLString]; } /** * 加载本地网页 * * @param htmlName 请求的本地 HTML 文件名 */ - (void)web_loadHTMLFileName:(NSString *)htmlName{ [self.webArticleView ba_web_loadHTMLFileName:htmlName]; } /** * 加载本地 htmlString * * @param htmlString 请求的本地 htmlString */ - (void)web_loadHTMLString:(NSString *)htmlString{ [self.webArticleView ba_web_loadHTMLString:htmlString]; } /** * 加载 js 字符串,例如:高度自适应获取代码: // webView 高度自适应 [self web_stringByEvaluateJavaScript:@"document.body.offsetHeight" completionHandler:^(id _Nullable result, NSError * _Nullable error) { // 获取页面高度,并重置 webview 的 frame self.ba_web_currentHeight = [result doubleValue]; CGRect frame = webView.frame; frame.size.height = self.ba_web_currentHeight; webView.frame = frame; }]; * * @param javaScriptString js 字符串 */ - (void)web_stringByEvaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler{ [self.webArticleView ba_web_stringByEvaluateJavaScript:javaScriptString completionHandler:completionHandler]; } - (void)setWeb_progressTintColor:(UIColor *)web_progressTintColor{ _web_progressTintColor = web_progressTintColor; self.progressView.progressTintColor = web_progressTintColor; } - (void)setWeb_progressTrackTintColor:(UIColor *)web_progressTrackTintColor{ _web_progressTrackTintColor = web_progressTrackTintColor; self.progressView.trackTintColor = web_progressTrackTintColor; } - (UIProgressView *)progressView { if (!_progressView){ _progressView = [[UIProgressView alloc] initWithFrame:CGRectZero]; _progressView.tintColor = BAKit_Color_Green_pod; _progressView.trackTintColor = BAKit_Color_Gray_8_pod; _progressView.transform = CGAffineTransformMakeScale(1.0f, 1.5f); } return _progressView; } - (WKWebViewConfiguration *)webConfig{ if (!_webConfig) { // 创建并配置WKWebView的相关参数 // 1.WKWebViewConfiguration:是WKWebView初始化时的配置类,里面存放着初始化WK的一系列属性; // 2.WKUserContentController:为JS提供了一个发送消息的通道并且可以向页面注入JS的类,WKUserContentController对象可以添加多个scriptMessageHandler; // 3.addScriptMessageHandler:name:有两个参数,第一个参数是userContentController的代理对象,第二个参数是JS里发送postMessage的对象。添加一个脚本消息的处理器,同时需要在JS中添加,window.webkit.messageHandlers..postMessage()才能起作用。 _webConfig = [[WKWebViewConfiguration alloc] init]; _webConfig.allowsInlineMediaPlayback = YES; WKUserContentController *userContentController = [[WKUserContentController alloc] init]; ///js调用跳转至用户详情 [userContentController addScriptMessageHandler:self name:@"openUserDetail"]; /// js调用跳转至直播间 [userContentController addScriptMessageHandler:self name:@"openUserLive"]; ///js调用可跳转app指定内页 [userContentController addScriptMessageHandler:self name:@"openActivity"]; /// 支付 [userContentController addScriptMessageHandler:self name:@"showPay"]; // 分享 // [userContentController addScriptMessageHandler:self name:@"showShareDialog"]; /// 复制到剪切板 [userContentController addScriptMessageHandler:self name:@"copyInviteCode"]; /// 分享推广 [userContentController addScriptMessageHandler:self name:@"showPosterDialog"]; /// 把用户id传给H5 [userContentController addScriptMessageHandler:self name:@"getUserId"]; /// 客服 [userContentController addScriptMessageHandler:self name:@"startP2PSession"]; /// js调用Web窗口 [userContentController addScriptMessageHandler:self name:@"showH5Dialog"]; /// 关闭界面 [userContentController addScriptMessageHandler:self name:@"closeWindow"]; /// 第三方分享 [userContentController addScriptMessageHandler:self name:@"showNewShareDialog"]; /// js调用可跳转app指定内页 [userContentController addScriptMessageHandler:self name:@"openMainActivity"]; _webConfig.userContentController = userContentController; // 初始化偏好设置属性:preferences _webConfig.preferences = [WKPreferences new]; // The minimum font size in points default is 0; _webConfig.preferences.minimumFontSize = 15; // 是否支持 JavaScript _webConfig.preferences.javaScriptEnabled = YES; // 不通过用户交互,是否可以打开窗口 _webConfig.preferences.javaScriptCanOpenWindowsAutomatically = NO; } return _webConfig; } - (WKWebView *)webArticleView{ if (!_webArticleView) { _webArticleView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:self.webConfig]; [_webArticleView ba_web_initWithDelegate:self.webArticleView.navigationDelegate uIDelegate:self.webArticleView.UIDelegate]; _webArticleView.ba_web_isAutoHeight = NO; _webArticleView.multipleTouchEnabled = YES; _webArticleView.autoresizesSubviews = YES; _webArticleView.opaque = NO; _webArticleView.backgroundColor = HexColorFromRGB(0xFFFFFF); _webArticleView.scrollView.showsVerticalScrollIndicator = NO; } return _webArticleView; } @end