.H typedef NS_ENUM(int, FromeType) { From_MainShop = 1, From_Category = 2 }; @interface WKWebVC : BaseVC @property (nonatomic, strong) NSString *url; @property (nonatomic, strong) NSString *titleText; @property (nonatomic, assign) BOOL isShippingStatus; @property (nonatomic, assign) FromeType fromType; @property (nonatomic, copy) void(^checkMySizeResult)(NSString *size); @property (nonatomic, assign) BOOL isTabVC; @end .M @interface WKWebVC () <WKNavigationDelegate, FBSDKSharingDelegate, LoginDelegate, UILoadingViewDelegate, WKScriptMessageHandler> @property (nonatomic, strong) UILoadingView *loadingView; @property (weak, nonatomic) IBOutlet UILabel *titleLb; @property (weak, nonatomic) IBOutlet UIImageView *titleDiliver; @property (weak, nonatomic) IBOutlet UIActivityIndicatorView *indicator; @property (nonatomic, strong) WKUserContentController *userContentController; @property (weak, nonatomic) IBOutlet UIButton *backBtn; @property (nonatomic, strong) WKWebView *webView; @end - (void)viewDidLoad { [super viewDidLoad]; [self.indicator setHidesWhenStopped:YES]; self.titleLb.text=self.titleText; //配置信息 WKWebViewConfiguration *config=[[WKWebViewConfiguration alloc] init]; config.preferences=[[WKPreferences alloc]init]; // config.preferences.minimumFontSize = 10; config.preferences.javaScriptEnabled = true; // 默認是不能經過JS自動打開窗口的,必須經過用戶交互才能打開 config.preferences.javaScriptCanOpenWindowsAutomatically =true; // 經過js與webview內容交互配置 self.userContentController = [[WKUserContentController alloc]init]; config.userContentController = self.userContentController; // 添加一個名稱,在JS經過這個名稱發送消息 [config.userContentController addScriptMessageHandler:self name:@"theyub"]; WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, ZKScreenW, ZKScreenH) configuration:config]; webView.navigationDelegate = self; [self.view addSubview:webView]; self.webView = webView; self.loadingView=[UILoadingView instanceViewWithSuperView:self.view delegate:self]; self.loadingView.delegate=self; [self.view bringSubviewToFront:self.indicator]; [webView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.titleDiliver.mas_bottom); make.leading.equalTo(self.view.mas_leading); make.trailing.equalTo(self.view.mas_trailing); if (self.isTabVC) { make.bottom.equalTo(self.view.mas_bottom).with.offset(-49); } else { make.bottom.equalTo(self.view.mas_bottom); } }]; // 獲取 url if (self.isTabVC) { [self getUrlRequest]; } else { HttpManager * httpManager = [HttpManager sharedManager]; id<GAITracker> tracker = [[GAI sharedInstance] trackerWithTrackingId:GAP_TRACKING_ID]; NSString *clientid = [tracker get:kGAIClientId]; self.url = [NSString stringWithFormat:@"%@?app_token=%@&userId=%d&cid=%@&app_equip=ios&language=%@&siteUID=%@¤cy=%@&device_type=ios",self.url,httpManager.meInfo.token,httpManager.meInfo.member_id,clientid,[PhoneUtil getCurrentLanguage], [httpManager getCurrentSiteUid], [FileUtil getCurrency].code]; // @"http://www.ifeng.com"; NSURL *url=[NSURL URLWithString:self.url]; [self.webView loadRequest:[self headForRequest:url]]; [self.loadingView setHidden:YES]; } if (self.titleText.length <= 0) { // 添加KVO監聽網頁Title 變化 [self.webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:@"WKWebVC"]; } } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context { if (self.titleText.length <=0 ) { // 若是 沒有標題 取網頁的標題 if ([keyPath isEqualToString:@"title"]) { self.titleLb.text = self.webView.title; } } } // 頁面已經消失的時候 移除KVO和命名空間 - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; if (!self.isTabVC) { NSArray *vcs = self.navigationController.viewControllers; if (vcs.count > 0) { UIViewController *lastVC = [vcs lastObject]; if ([lastVC isKindOfClass:[self class]]) { [self removeScriptAndObserver]; } } else { // 頁面已經消失 [self removeScriptAndObserver]; } } } - (void)removeScriptAndObserver { @try { [self.userContentController removeScriptMessageHandlerForName:@"theyub"]; [self.webView removeObserver:self forKeyPath:@"title" context:@"WKWebVC"]; } @catch (NSException *exception) { NSLog(@"========%@", exception); } @finally {} } - (IBAction)popVC:(id)sender { if (self.webView.canGoBack) { [self.webView goBack]; return; } [self.navigationController popViewControllerAnimated:YES]; } - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { NSLog(@"=============%@", message.body); NSString *jsonString = [NSString stringWithFormat:@"%@", message.body]; if (jsonString.length > 0) { NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; NSLog(@"=============%@", dict); NSString *method = parseStringFromDict(@"method", dict); // 根據方法名判斷須要執行的方法 if ([method isEqualToString:@"webToMobile"]) { [self webToMobile:jsonString]; } else if ([method isEqualToString:@"webToMobileAction"]) { [self webToMobileAction:jsonString]; } } } // 獲取URL - (void)getUrlRequest { ExclusiveHttpRequest *req = [[ExclusiveHttpRequest alloc] init]; [req getExclusiveRequstCallback:^(BOOL success, NSObject *result, NSString *errorMsg) { if (success) { self.url = (NSString *)result; if (self.url .length > 0) { HttpManager * httpManager = [HttpManager sharedManager]; id<GAITracker> tracker = [[GAI sharedInstance] trackerWithTrackingId:GAP_TRACKING_ID]; NSString *clientid = [tracker get:kGAIClientId]; self.url = [NSString stringWithFormat:@"%@?app_token=%@&userId=%d&cid=%@&app_equip=ios&language=%@&siteUID=%@¤cy=%@&device_type=ios",self.url,httpManager.meInfo.token,httpManager.meInfo.member_id,clientid,[PhoneUtil getCurrentLanguage], [httpManager getCurrentSiteUid], [FileUtil getCurrency].code]; NSURL *url=[NSURL URLWithString:self.url]; [self.webView loadRequest:[self headForRequest:url]]; [self.loadingView setHidden:YES]; } else { [self.loadingView showErrorView]; } } else { [self.loadingView showErrorView]; [UIToastUtil showToast:self.view message:errorMsg]; } }]; } //返回一個urlRequest 對象, - (NSMutableURLRequest*)headForRequest:(NSURL*)url{ NSMutableURLRequest *request=[[NSMutableURLRequest alloc] initWithURL:url]; NSString *preferredLang = [PhoneUtil getCurrentLanguage]; if([preferredLang hasPrefix:@"zh-Hant"]){ if([[[HttpManager sharedManager] getLocalCountry] isOrderedSameString:@"TW"]){ preferredLang=@"zh-tw"; }else if([[[HttpManager sharedManager] getLocalCountry] isOrderedSameString:@"HK"]){ preferredLang=@"zh-hk"; }else{ preferredLang=@"zh-tw"; } } HttpManager * httpManager = [HttpManager sharedManager]; [request addValue:[FileUtil getCurrency].code forHTTPHeaderField:@"Currency"]; [request addValue:preferredLang forHTTPHeaderField:@"Language"]; [request addValue:@"iPhone" forHTTPHeaderField:@"Devtype"]; [request addValue:[HttpManager sharedManager].UUID forHTTPHeaderField:@"dev_id"]; [request setValue:@"app" forHTTPHeaderField:@"SiteUID"]; if([httpManager getLocalCountry]){ [request setValue:[httpManager getLocalCountry] forHTTPHeaderField:@"LocalCountry"]; } if([HttpManager sharedManager].meInfo && [HttpManager sharedManager].meInfo.member_id){ [request setValue:[NSString stringWithFormat:@"%d",[HttpManager sharedManager].meInfo.member_id] forHTTPHeaderField:@"NewUid"]; } [request setValue:[NSString stringWithFormat:@"%@ %@%@",[[[PhoneUtil alloc] init] getDevice],@"ios",[[UIDevice currentDevice] systemVersion]] forHTTPHeaderField:@"Device"]; [request setValue:@"shein app" forHTTPHeaderField:@"AppName"]; [request setValue:@"shein" forHTTPHeaderField:@"AppType"]; [request setValue:[PhoneUtil getAppVersion] forHTTPHeaderField:@"AppVersion"]; [request setValue:[FileUtil getCurrency].code forHTTPHeaderField:@"AppCurrency"]; [request setValue:[PhoneUtil getCountry] forHTTPHeaderField:@"AppCountry"]; [request setValue:[PhoneUtil getNetWorkStates] forHTTPHeaderField:@"network-type"]; [request setValue:preferredLang forHTTPHeaderField:@"AppLanguage"]; if([HttpManager sharedManager].meInfo!=nil&&[HttpManager sharedManager].meInfo.token!=nil){ [request addValue:[HttpManager sharedManager].meInfo.token forHTTPHeaderField:@"token"]; } return request; } // 從新加載 - (void)didTryAgain { if (self.isTabVC) { [self getUrlRequest]; } else { [self.webView reload]; } } // 頁面開始加載時調用 - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation { [self.indicator startAnimating]; } // 內容開始加載. 等同於 UIWebViewDelegate: - webViewDidStartLoad: - (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation { // [self.indicator startAnimating]; } // 頁面加載完成。 等同於 UIWebViewDelegate: - webViewDidFinishLoad: - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation { [self.indicator stopAnimating]; [self.loadingView setHidden:YES]; } // 頁面加載失敗調用 ---- 好像是網絡緣由失敗 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error { if (self.isTabVC) { [self.loadingView showErrorView]; } [self.indicator stopAnimating]; } // 頁面加載失敗。 等同於 UIWebViewDelegate: - webView:didFailLoadWithError: - (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error { NSLog(@"===============withError"); [self.indicator stopAnimating]; } #pragma mark - 交互通用方法 ----------------------- - (void)webToMobile:(NSString *)json { NSData *data = [json dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; if(dict){ if (![NSThread isMainThread]) { return; } NSString *checkMySize = parseStringFromDict(@"checkMySize", dict); NSString *link = parseStringFromDict(@"shareLink", dict); NSString *popVC = parseStringFromDict(@"popVC", dict); if (checkMySize.length > 0) { // check my size if (self.checkMySizeResult) { self.checkMySizeResult(checkMySize); } [self.navigationController popViewControllerAnimated:YES]; } else if (link.length > 0) { // 分享 [[VAShareTool alloc ] shareInViewConroller:self withTitle:@"" description:@"" url:link imageUrl:link image:nil completionHandler:^(UIActivityType _Nullable activityType, BOOL completed, NSArray * _Nullable returnedItems, NSError * _Nullable activityError) { if (completed) { NSLog(@"completed"); } else { NSLog(@"cancel"); } }]; } else if ([popVC isEqualToString:@"1"]) { [self.navigationController popViewControllerAnimated:YES]; } } } #pragma mark - 交互新增行爲方法 ----------------------- - (void)webToMobileAction:(NSString *)json { NSData *data = [json dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; if(dict){ if ([NSThread isMainThread]) { [self pushActionWithDict:dict]; } else { dispatch_async(dispatch_get_main_queue(), ^{ [self pushActionWithDict:dict]; }); } } } //WKNavigationDelegate - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { NSString *actionType = navigationAction.request.URL.host; if([actionType isEqualToString:@"WebBlogVC.shareDownloadYub"]){//分享app [GaUtil addMe:@"BACK BLOGGER" label:nil]; NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://m.theyub.com"]]; NSArray *objectsToShare = @[url]; UIActivityViewController *controller = [[UIActivityViewController alloc] initWithActivityItems:objectsToShare applicationActivities:nil]; NSArray *excludedActivities = @[UIActivityTypePrint, UIActivityTypeCopyToPasteboard, UIActivityTypeSaveToCameraRoll, UIActivityTypeAddToReadingList]; controller.excludedActivityTypes = excludedActivities; [self presentViewController:controller animated:YES completion:nil]; } // if([request.URL.absoluteString isEqualToString:@"about:blank"]&&navigationType==2){//若是是返回,且是空白頁面,則重新刷新頁面 // dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // [self.webView reload]; // }); // } else if (self.isTabVC && navigationAction.navigationType == WKNavigationTypeLinkActivated) { if (navigationAction.request.URL.absoluteString && ![navigationAction.request.URL.absoluteString containsString:self.url]) { UIStoryboard *sb=[UIStoryboard storyboardWithName:@"Setting" bundle:[NSBundle mainBundle]]; WebViewVC *webVC = [sb instantiateViewControllerWithIdentifier:@"WebViewVC"]; webVC.url = navigationAction.request.URL.absoluteString; [self.navigationController pushViewController:webVC animated:YES]; decisionHandler(WKNavigationActionPolicyCancel); return; } } decisionHandler(WKNavigationActionPolicyAllow); } - (void)downloadImageWithUrl:(NSString *)urlStr { NSLog(@"回退----%@",urlStr); [[SDWebImageManager sharedManager] downloadImageWithURL:[NSURL URLWithString:[urlStr fixUrlSting]] options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize) { } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { if (finished && nil != image) { // PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { if (status == PHAuthorizationStatusRestricted || status == PHAuthorizationStatusDenied) { //無權限 dispatch_async(dispatch_get_main_queue(), ^{ [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; }); } else{ dispatch_async(dispatch_get_main_queue(), ^{ UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), (__bridge void *)self); }); } }]; } if (image == nil) { UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:[LocalizedUtil getStringByKey:@"string_key_1364"] preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:[LocalizedUtil getStringByKey:@"string_key_342"] style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { }]]; [self presentViewController:alert animated:YES completion:nil]; } }]; } - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo { if (error == nil) { UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:[LocalizedUtil getStringByKey:@"string_key_1365"] preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:[LocalizedUtil getStringByKey:@"string_key_342"] style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { }]]; [self presentViewController:alert animated:YES completion:nil]; } else{ UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:getStringByKey(@"string_key_1364") preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:[LocalizedUtil getStringByKey:@"string_key_342"] style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { }]]; [self presentViewController:alert animated:YES completion:nil]; } NSLog(@"image = %@, error = %@, contextInfo = %@", image, error, contextInfo); } - (void)sharer:(id<FBSDKSharing>)sharer didCompleteWithResults:(NSDictionary *)results{ NSLog(@"didCompleteWithResults"); } - (void)sharer:(id<FBSDKSharing>)sharer didFailWithError:(NSError *)error{ NSLog(@"didFailWithError,%@",error); if(error==nil||[[NSNull null] isEqual:error]){ [UIToastUtil showToast:self.view message:@"you have not install facebook app."]; } } - (void)sharerDidCancel:(id<FBSDKSharing>)sharer{ NSLog(@"share..."); } #pragma mark - 登陸 代理 -------------- - (void)loginSuccess:(MeInfo*)meInfo { } - (void)registSuccess:(MeInfo*)meInfo { } #pragma mark - 頁面跳轉 ------------------- - (void)pushActionWithDict:(NSDictionary *)dict { NSString *type_id = parseStringFromDict(@"type_id", dict); NSString *tid = parseStringFromDict(@"tid", dict); NSString *category_type = parseStringFromDict(@"category_type", dict); NSString *title = parseStringFromDict(@"title", dict); NSString *popVC = parseStringFromDict(@"popVC", dict); if (type_id.length > 0) { if ([type_id isEqualToString:@"1"]) { //虛擬分類 UIStoryboard *sb=[UIStoryboard storyboardWithName:@"Promotions" bundle:[NSBundle mainBundle]]; PromotionGoodsListVC *vc=[sb instantiateViewControllerWithIdentifier:@"PromotionGoodsListVC"]; vc.virtual_category_id = tid; vc.navTitle = title; // vc.siteFrom = @"shop "; vc.categoryType = 1; [self.navigationController pushViewController:vc animated:YES]; } else if ([type_id isEqualToString:@"2"]) { // 真實分類 if ([category_type isEqualToString:@"1"]) { // 一級分類 UIStoryboard *sb=[UIStoryboard storyboardWithName:@"Category" bundle:[NSBundle mainBundle]]; CategoryAllGoodsListVC *vc=[sb instantiateViewControllerWithIdentifier:@"CategoryAllGoodsListVC"]; vc.navTitle = title; vc.category = @""; vc.cat_id = tid; // vc.siteFrom = @"shop "; [self.navigationController pushViewController:vc animated:YES]; } else if ([category_type isEqualToString:@"2"]) { // 二級分類 UIStoryboard *sb=[UIStoryboard storyboardWithName:@"Category" bundle:[NSBundle mainBundle]]; CategoryGoodsListVC *vc=[sb instantiateViewControllerWithIdentifier:@"CategoryGoodsListVC"]; vc.navTitle = title; vc.category = @""; vc.cat_id = tid; // vc.siteFrom = @"shop "; [self.navigationController pushViewController:vc animated:YES]; } } else if ([type_id isEqualToString:@"11"]) { // 跳登陸 UIStoryboard *sb=[UIStoryboard storyboardWithName:@"Login" bundle:[NSBundle mainBundle]]; LoginVC *vc=[sb instantiateViewControllerWithIdentifier:@"LoginVC"]; vc.delegate=self; [self presentViewController:vc animated:YES completion:NULL]; if([tid isEqualToString:@"1101"]){ // 登陸 vc.doAction=1; } else{ // 註冊 vc.doAction=2; } [self presentViewController:vc animated:YES completion:NULL]; } else if ([type_id isEqualToString:@"12"]) { // 商品詳情 GoodsInfo *goodsInfo=[[GoodsInfo alloc] init]; goodsInfo.goods_id=[tid intValue]; UIStoryboard *sb=[UIStoryboard storyboardWithName:@"Goods" bundle:[NSBundle mainBundle]]; GoodsDetailVC *vc=[sb instantiateViewControllerWithIdentifier:@"GoodsDetailVC"]; vc.goodsInfo=goodsInfo; [self.navigationController pushViewController:vc animated:YES]; } } else if (popVC.length > 0) { [self.navigationController popViewControllerAnimated:YES]; } } // 設置 WKWebview 滾動速率 須要使用scroll 代理來作 webView.scrollView.delegate = self; - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { scrollView.decelerationRate = UIScrollViewDecelerationRateNormal; }
//請求以前,決定是否要跳轉:用戶點擊網頁上的連接,須要打開新頁面時,將先調用這個方法。 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler; //接收到相應數據後,決定是否跳轉 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler; //頁面開始加載時調用 - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation; // 主機地址被重定向時調用 - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation; // 頁面加載失敗時調用 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error; // 當內容開始返回時調用 - (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation; // 頁面加載完畢時調用 - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation; //跳轉失敗時調用 - (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error; // 若是須要證書驗證,與使用AFN進行HTTPS證書驗證是同樣的 - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *__nullable credential))completionHandler; //9.0才能使用,web內容處理中斷時會觸發 - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView NS_AVAILABLE(10_11, 9_0);