// // WebViewController.m // tongxin // // Created by weichao on 2019/03/01. // Copyright © 2019年 weichao. All rights reserved. // #import "ActivityWebViewController.h" #import #import "Reachability.h" @interface ActivityWebViewController() { CGRect WebFrame; BOOL _locationAuthorization; // 用户是否授权使用定位 BOOL _isDidLoadWeb; } /** 隐藏导航栏时有的返回按钮 */ @property (nonatomic, strong) UIButton *backBtn; @property (nonatomic, strong) UIProgressView *progressView; @property (strong,nonatomic) CLLocationManager* locationManager; @property (nonatomic, strong) NSString *cityName; @property (nonatomic, strong) UIView *tempView; @end @implementation ActivityWebViewController - (WKWebView *)myWebView{ if (!_myWebView) { //创建 WKWebView 配置对象 WKWebViewConfiguration *config = [WKWebViewConfiguration new]; // config.userContentController = wkUController; WKPreferences *preferences = [WKPreferences new]; preferences.javaScriptCanOpenWindowsAutomatically = YES; // preferences.minimumFontSize = 40.0; config.preferences = preferences; CGFloat tabBarHeight = self.tabBarController.tabBar.height; CGRect tempViewFrame; if(getRectNavAndStatusHight > 64){ //X if(self.isShowBack){ WebFrame = CGRectMake(0, getRectNavAndStatusHight-44, ScreenWidth, ScreenHeight-tabBarHeight-getRectNavAndStatusHight+44 ); tempViewFrame = CGRectMake(0, 0, ScreenWidth, getRectNavAndStatusHight-44); }else{ CGFloat WebNacv = 55; //网页的导航栏高度 WebFrame = CGRectMake(0, getRectNavAndStatusHight-WebNacv, ScreenWidth, ScreenHeight-tabBarHeight-getRectNavAndStatusHight+WebNacv ); tempViewFrame = CGRectMake(0, 0, ScreenWidth, getRectNavAndStatusHight-WebNacv); } }else{ if(self.isShowBack){ WebFrame = CGRectMake(0, 0, ScreenWidth, ScreenHeight-tabBarHeight); tempViewFrame = CGRectMake(0, 0, ScreenWidth, 0); }else{ //不显示返回按钮的是首页 WebFrame = CGRectMake(0, 20, ScreenWidth, ScreenHeight-tabBarHeight-20); tempViewFrame = CGRectMake(0, 0, ScreenWidth, 20); } } _tempView = [[UIView alloc] initWithFrame:tempViewFrame]; _tempView.backgroundColor = mainColor; [self.view addSubview:_tempView]; _tempView.hidden = YES; _myWebView = [[WKWebView alloc] initWithFrame:WebFrame configuration:config]; if (@available(iOS 11.0, *)) { _myWebView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; } else { self.edgesForExtendedLayout = UIRectEdgeNone; } [self.view addSubview:_myWebView]; } return _myWebView; } -(void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; //隐藏导航栏 // [[UIApplication sharedApplication] setStatusBarHidden:YES]; [self.navigationController.navigationBar setHidden:YES]; // addScriptMessageHandler 很容易导致循环引用 // 控制器 强引用了WKWebView,WKWebView copy(强引用了)configuration, configuration copy (强引用了)userContentController // userContentController 强引用了 self (控制器) [self.myWebView.configuration.userContentController addScriptMessageHandler:self name:@"Location"]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loadURL) name:NoReachableRefreshNotification object:nil]; if(![self.url containsString:ActivityURLStr]){ xLog(@"不是首页:%@",self.url); [self setHiddenTabBottomBar:YES]; }else{ xLog(@"是首页:%@",self.url); [self setHiddenTabBottomBar:NO]; } } -(void)viewWillDisappear:(BOOL)animated{ [super viewWillDisappear:animated]; // 因此这里要记得移除handlers [self.myWebView.configuration.userContentController removeScriptMessageHandlerForName:@"Location"]; } -(void)viewDidDisappear:(BOOL)animated{ self.tabBarController.tabBar.hidden = NO; [[NSNotificationCenter defaultCenter] removeObserver:self name:NoReachableRefreshNotification object:nil]; } //-(BOOL)prefersStatusBarHidden{ // if(self.isHiddenNavigationBar){ // return YES; // }else{ // return NO; // } //} - (void)viewDidLoad{ self.view.backgroundColor = [UIColor whiteColor]; [super viewDidLoad]; if(!self.url){ self.url = ActivityURLStr; [UICommon MessageUpload:@"正在加载"]; } [self loadURL]; WEAKSELF self.myWebView.UIDelegate = self; self.myWebView.navigationDelegate = self; self.myWebView.scrollView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{ [weakSelf loadURL]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [weakSelf.myWebView.scrollView.mj_header endRefreshing]; }); }]; if(self.isShowBack){ UIButton *backBtn = [UIButton buttonWithType:UIButtonTypeSystem]; backBtn.frame = CGRectMake(14, 40, 30, 30); [backBtn setBackgroundImage:[UIImage imageNamed:@"icon_return_black"] forState:0]; [backBtn addTarget:self action:@selector(goBack:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:backBtn]; } [self initProgressView]; [self startLocation]; // [self.myWebView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil]; // if(self.isHiddenNavigationBar){ // //创建返回按钮 // _backBtn = [UIButton buttonWithType:UIButtonTypeSystem]; // _backBtn.frame = CGRectMake(5, 26, 30, 30); // [_backBtn setBackgroundImage:[UIImage imageNamed:@"icon_return_round"] forState:0]; // [_backBtn addTarget:self action:@selector(goBack:) forControlEvents:UIControlEventTouchUpInside]; // [self.view addSubview:_backBtn]; // } } - (void)loadURL{ [self.myWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:self.url]]]; if(!self.cityName && _locationAuthorization){ [self startLocation]; } } - (void)initProgressView { CGFloat kScreenWidth = [[UIScreen mainScreen] bounds].size.width; UIProgressView *progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, 2)]; progressView.tintColor = [UIColor redColor]; progressView.trackTintColor = [UIColor lightGrayColor]; [self.view addSubview:progressView]; self.progressView = progressView; } //开始定位 -(void)startLocation{ if(!self.locationManager){ self.locationManager = [[CLLocationManager alloc] init]; self.locationManager.delegate = self; self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer; // 位置变更距离 self.locationManager.distanceFilter = 1000.0f; if ([CurrentSystemVersion doubleValue] > 8.0){ if([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined){ [self.locationManager requestWhenInUseAuthorization]; } } // if ([CurrentSystemVersion doubleValue] >= 8.0) { // _locationManager.allowsBackgroundLocationUpdates =YES; // } // [self locationManager:self.locationManager didChangeAuthorizationStatus:[CLLocationManager authorizationStatus]]; } [self.locationManager startUpdatingLocation]; } //MARK: 协议 CLLocationManagerDelegate /** 权限改变 */ -(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{ switch (status) { case kCLAuthorizationStatusNotDetermined: if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]){ [self.locationManager requestWhenInUseAuthorization]; } break; case kCLAuthorizationStatusDenied: xLog(@"用户拒绝获取定位位置"); _locationAuthorization = NO; break; case kCLAuthorizationStatusAuthorizedAlways: case kCLAuthorizationStatusAuthorizedWhenInUse: xLog(@"用户同意获取定位位置"); if(!self.cityName){ [self.locationManager startUpdatingLocation]; } break; default: break; } } /** 位置更新 */ -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{ //此处locations存储了持续更新的位置坐标值,取最后一个值为最新位置,如果不想让其持续更新位置,则在此方法中获取到一个值之后让locationManager stopUpdatingLocation CLLocation *currentLocation = [locations lastObject]; // 获取当前所在的城市名 CLGeocoder *geocoder = [[CLGeocoder alloc] init]; //根据经纬度反向地理编译出地址信息 WEAKSELF [geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) { if (placemarks.count > 0){ CLPlacemark *placemark = [placemarks objectAtIndex:0]; //将获得的所有信息显示到label上 NSLog(@"%@",placemark.name); //获取城市 NSString *city = placemark.locality; self.cityName = city; if (!city) { //四大直辖市的城市信息无法通过locality获得,只能通过获取省份的方法来获得(如果city为空,则可知为直辖市) city = placemark.administrativeArea; weakSelf.cityName = city; //如果这个时候网页已经加载完成了,那就 重新加载一次 if(_isDidLoadWeb){ [weakSelf loadURL]; } }else if (error == nil && [placemarks count] == 0){ NSLog(@"No results were returned."); }else if (error != nil){ NSLog(@"An error occurred = %@", error); } } }]; //系统会一直更新数据,直到选择停止更新,因为我们只需要获得一次经纬度即可,所以获取之后就停止更新 [manager stopUpdatingLocation]; } - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { if (error.code == kCLErrorDenied) { // 提示用户出错原因,可按住Option键点击 KCLErrorDenied的查看更多出错信息,可打印error.code值查找原因所在 } } - (void)dealloc { NSLog(@"%s",__FUNCTION__); self.myWebView.UIDelegate = nil; self.myWebView.navigationDelegate = nil; [[NSNotificationCenter defaultCenter] removeObserver:self name:NoReachableRefreshNotification object:nil]; // [self.myWebView removeObserver:self forKeyPath:@"estimatedProgress"]; } #pragma mark - private method - (void)getLocation { if(!_locationAuthorization){ return; } // 获取位置信息 if(self.cityName){ // MARK: 原生 调用 JS NSString *city = [self.cityName stringByReplacingOccurrencesOfString:@"市" withString:@""]; NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')",city]; [self.myWebView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) { NSLog(@"%@----%@",result, error); }]; }else{ //如果定位还未成功那就2秒之后再调用一次 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self getLocation]; }); } } #pragma mark - KVO // 计算wkWebView进度条 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (object == self.myWebView && [keyPath isEqualToString:@"estimatedProgress"]) { CGFloat newprogress = [[change objectForKey:NSKeyValueChangeNewKey] doubleValue]; if (newprogress == 1) { [self.progressView setProgress:1.0 animated:YES]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.7 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.progressView.hidden = YES; [self.progressView setProgress:0 animated:NO]; }); }else { self.progressView.hidden = NO; [self.progressView setProgress:newprogress animated:YES]; } } } #pragma mark - WKUIDelegate - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler { UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提醒" message:message preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { completionHandler(); }]]; [self presentViewController:alert animated:YES completion:nil]; } //MARK: 协议 WKNavigationDelegate /** MARK: 页面加载完成之后调用 */ -(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{ _isDidLoadWeb = YES; Reachability *reach = [Reachability reachabilityForInternetConnection]; [UICommon HidenLoading]; if([reach currentReachabilityStatus] == NotReachable){ xLog(@"无网络"); _tempView.hidden = YES; self.myWebView.hidden = YES; [UICommon MessageErrorText:NSLocalizedStringFromTable(@"请检查您的网络设置", @"Localization", @"")]; }else{ xLog(@"有网络"); _tempView.hidden = NO; self.myWebView.hidden = NO; } } - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{ //如果是跳转一个新页面 if (navigationAction.targetFrame == nil) { WEAKSELF dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ ActivityWebViewController* vc = [ActivityWebViewController new]; vc.url = navigationAction.request.URL.absoluteString; vc.isShowBack = YES; vc.hidesBottomBarWhenPushed = YES; [weakSelf.navigationController pushViewController:vc animated:YES]; }); decisionHandler(WKNavigationActionPolicyCancel); return; } self.url = navigationAction.request.URL.absoluteString; if(![self.url containsString:ActivityURLStr]){ xLog(@"不是首页:%@",self.url); [self setHiddenTabBottomBar:YES]; }else{ xLog(@"是首页:%@",self.url); [self setHiddenTabBottomBar:NO]; } decisionHandler(WKNavigationActionPolicyAllow); } - (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error{ xLog(@"didFailNavigation error:%@",error.description); } - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error{ xLog(@"didFailProvisionalNavigation error:%@",error.description); [self webView:webView didFinishNavigation:navigation]; } /** 隐藏或者显示 TabBottomBar */ -(void)setHiddenTabBottomBar:(BOOL)hidden{ self.tabBarController.tabBar.hidden = hidden; if(hidden){ //隐藏 self.myWebView.height = WebFrame.size.height+self.tabBarController.tabBar.height; }else{ //显示 self.myWebView.frame = WebFrame; } } - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { scrollView.decelerationRate = UIScrollViewDecelerationRateNormal; } #pragma mark - WKScriptMessageHandler JS调用 原生会调用这里 - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { // message.body -- Allowed types are NSNumber, NSString, NSDate, NSArray,NSDictionary, and NSNull. NSLog(@"body:%@",message.body); if ([message.name isEqualToString:@"Location"]) { [self getLocation]; } // else if ([message.name isEqualToString:@"Share"]) { // [self shareWithParams:message.body]; // } else if ([message.name isEqualToString:@"Color"]) { // [self changeBGColor:message.body]; // } else if ([message.name isEqualToString:@"Pay"]) { // [self payWithParams:message.body]; // } else if ([message.name isEqualToString:@"Shake"]) { // [self shakeAction]; // } else if ([message.name isEqualToString:@"GoBack"]) { // [self goBack]; // } else if ([message.name isEqualToString:@"PlaySound"]) { // [self playSound:message.body]; // } } @end