// // XPWebViewController.m // xplan-ios // // Created by zu on 2021/9/16. // #import "XPWebViewController.h" #import "AccountInfoStorage.h" #import "ThemeColor.h" #import "ApiHost.h" #import "YYUtility.h" #import "HttpRequestHelper.h" #import #import #import @interface WeakWebViewScriptMessageDelegate : NSObject //WKScriptMessageHandler 这个协议类专门用来处理JavaScript调用原生OC的方法 @property (nonatomic, weak) id scriptDelegate; - (instancetype)initWithDelegate:(id)scriptDelegate; @end @implementation WeakWebViewScriptMessageDelegate - (instancetype)initWithDelegate:(id)scriptDelegate { self = [super init]; if (self) { _scriptDelegate = scriptDelegate; } return self; } //遵循WKScriptMessageHandler协议,必须实现如下方法,然后把方法向外传递 //通过接收JS传出消息的name进行捕捉的回调方法 - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { if ([self.scriptDelegate respondsToSelector:@selector(userContentController:didReceiveScriptMessage:)]) { [self.scriptDelegate userContentController:userContentController didReceiveScriptMessage:message]; } } @end @interface XPWebViewController () @property (strong, nonatomic) WKWebView *webview; @property (strong, nonatomic) UIProgressView *progressView; @property (nonatomic, strong) WKUserContentController *userContentController; @end NSString * const kJSOpenPurse = @"openPurse"; NSString * const kJSOpenChargePage = @"openChargePage"; NSString * const kJSOpenSharePage = @"openSharePage"; NSString * const kJSGetUid = @"getUid"; NSString * const kJSGetDeviceId = @"getDeviceId"; NSString * const kJSGetTicket = @"getTicket"; NSString * const kJSGetDeviceInfo = @"getDeviceInfo"; NSString * const kJSOpenFaceLiveness = @"openFaceLiveness"; @implementation XPWebViewController - (void)viewDidLoad { [super viewDidLoad]; [self initView]; } - (void)initView { if (self.navigationController.viewControllers.count > 1){ UIBarButtonItem *leftBarButtonItem = [[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:@"common_nav_back"] style:UIBarButtonItemStylePlain target:self action:@selector(backButtonClick)]; leftBarButtonItem.tintColor = UIColor.whiteColor; self.navigationItem.leftBarButtonItem = leftBarButtonItem; } self.automaticallyAdjustsScrollViewInsets = NO; [self.view addSubview:self.webview]; [self.webview mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.top.bottom.mas_equalTo(self.view); }]; [self.view addSubview:self.progressView]; } - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { if ([message.name isEqualToString:kJSOpenSharePage]) { [self showSuccessToast:@"打开分享面板,尚未实现"]; } else if ([message.name isEqualToString:kJSGetUid]) { NSString *uid = [[AccountInfoStorage instance] getUid]; NSString *js = [NSString stringWithFormat:@"getMessage(\"uid\",%@)", uid]; [self.webview evaluateJavaScript:js completionHandler:^(id _Nullable other, NSError * _Nullable error) { NSLog(@"%@",error); }]; } else if ([message.name isEqualToString:kJSGetTicket]) { NSString *ticket = [[AccountInfoStorage instance] getTicket]; NSString *js = [NSString stringWithFormat:@"getMessage(\"ticket\",\"%@\")",ticket]; [self.webview evaluateJavaScript:js completionHandler:^(id _Nullable other, NSError * _Nullable error) { NSLog(@"%@",error); }]; } else if ([message.name isEqualToString:kJSGetDeviceId]) { NSString *js = [NSString stringWithFormat:@"getMessage(\"deviceId\",\"%@\")",[YYUtility deviceUniqueIdentification]]; [self.webview evaluateJavaScript:js completionHandler:^(id _Nullable other, NSError * _Nullable error) { NSLog(@"%@",error); }]; } else if ([message.name isEqualToString:kJSGetDeviceInfo]) { NSDictionary *basicParmars = [HttpRequestHelper configBaseParmars:[[NSDictionary alloc] init]]; NSString *json = [basicParmars mj_JSONString]; NSString *js = [NSString stringWithFormat:@"getMessage(\"deviceInfo\",%@)", json]; [self.webview evaluateJavaScript:js completionHandler:^(id _Nullable ohter, NSError * _Nullable error) { NSLog(@"%@", error); }]; } else if ([message.name isEqualToString:kJSOpenPurse]) { } else if ([message.name isEqualToString:kJSOpenChargePage]) { } else if ([message.name isEqualToString:kJSOpenFaceLiveness]) { NSString *verifyToken = message.body; #if TARGET_OS_IPHONE [RPSDK startWithVerifyToken:verifyToken viewController:self.navigationController completion:^(RPResult * _Nonnull auditState) { NSString *jsStrUrl; switch (auditState.state) { case RPStatePass: jsStrUrl = [NSString stringWithFormat:@"renderByStatus(\"%d\")", 2]; break; case RPStateFail: jsStrUrl = [NSString stringWithFormat:@"renderByStatus(\"%d\")", 1]; break; case RPStateNotVerify: jsStrUrl = [NSString stringWithFormat:@"renderByStatus(\"%d\")", -1]; break; } [self.webview evaluateJavaScript:jsStrUrl completionHandler:^(id _Nullable other, NSError * _Nullable error) { NSLog(@"%@",error); }]; }]; #endif } } - (void)setUrl:(NSString *)urlString{ _url = urlString; if (_url == nil) { return; } if (![_url hasPrefix:@"http"] && ![_url hasPrefix:@"https"]){ _url = [NSString stringWithFormat:@"%@/%@", API_HOST_URL, _url]; } if (![_url containsString:@"?"]) { _url = [NSString stringWithFormat:@"%@?platform=%@", _url, [YYUtility appName]]; } else { _url = [NSString stringWithFormat:@"%@&platform=%@", _url, [YYUtility appName]]; } // 去掉 urlString 中的空格。 NSString *noSpaceTextUrl = [_url stringByReplacingOccurrencesOfString:@" " withString:@""]; NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:noSpaceTextUrl]]; [self.webview loadRequest:request]; } - (void)backButtonClick { BOOL canGoBack = YES; if (self.webview.backForwardList.backList.count <= 1) { canGoBack = NO; } if ([self.webview canGoBack]) { [self.webview goBack]; } else { [self.navigationController popViewControllerAnimated:YES]; [self.userContentController removeAllUserScripts]; } } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"estimatedProgress"]) { self.progressView.progress = self.webview.estimatedProgress; if (self.progressView.progress == 1) { __weak typeof (self)weakSelf = self; [UIView animateWithDuration:0.25f delay:0.3f options:UIViewAnimationOptionCurveEaseOut animations:^{ weakSelf.progressView.transform = CGAffineTransformMakeScale(1.0f, 1.0f); } completion:^(BOOL finished) { weakSelf.progressView.hidden = YES; }]; } } else if ([keyPath isEqualToString:@"title"]) { if (object == self.webview) { self.navigationItem.title = self.webview.title; }else{ [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } - (void)dealloc { [self.webview removeObserver:self forKeyPath:@"estimatedProgress"]; [self.webview removeObserver:self forKeyPath:@"title"]; } - (WKWebView *)webview { if (_webview == nil) { WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc]init]; if (@available(iOS 10.0, *)) { configuration.mediaTypesRequiringUserActionForPlayback = NO; } else { // Fallback on earlier versions } configuration.allowsInlineMediaPlayback = YES; NSString *uid = [[AccountInfoStorage instance] getUid]; NSString *realCookie = [NSString stringWithFormat:@"%@=%@",@"uid",uid]; WKUserScript *cookieScript = [[WKUserScript alloc] initWithSource: [NSString stringWithFormat:@"document.cookie = '%@';", realCookie] injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]; [self.userContentController addUserScript:cookieScript]; //根据生成的WKUserScript对象,初始化WKWebViewConfiguration configuration.preferences.javaScriptEnabled = YES; configuration.preferences.javaScriptCanOpenWindowsAutomatically = YES; configuration.preferences.minimumFontSize = 10; configuration.selectionGranularity = WKSelectionGranularityCharacter; configuration.userContentController = self.userContentController; CGSize size = [UIScreen mainScreen].bounds.size; _webview = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, size.width,size.height) configuration:configuration]; _webview.navigationDelegate = self; //添加KVO,WKWebView有一个属性estimatedProgress,就是当前网页加载的进度,所以监听这个属性 [_webview addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil]; //添加KVO,监听title属性 [_webview addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL]; UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(backButtonClick)]; [_webview addGestureRecognizer:swipeGesture]; [_webview.scrollView setShowsVerticalScrollIndicator:NO]; [_webview.scrollView setShowsHorizontalScrollIndicator:NO]; //set useragent __weak typeof(self) weakSelf = self; [_webview evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id result, NSError *error) { NSString *userAgent = result; if (![userAgent containsString:@"tutuAppIos erbanAppIos"]){ NSString *newUserAgent = [userAgent stringByAppendingString:@" tutuAppIos erbanAppIos"]; NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:newUserAgent, @"UserAgent", nil]; [[NSUserDefaults standardUserDefaults] registerDefaults:dictionary]; [[NSUserDefaults standardUserDefaults] synchronize]; [weakSelf.webview setCustomUserAgent:newUserAgent]; } }]; } return _webview; } - (UIProgressView *)progressView{ if (!_progressView) { _progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, 1)]; _progressView.progressTintColor = [ThemeColor appMainColor]; _progressView.trackTintColor = [UIColor clearColor]; _progressView.transform = CGAffineTransformMakeScale(1.0f, 1.0f); } return _progressView; } - (WKUserContentController *)userContentController{ if (!_userContentController) { //自定义的WKScriptMessageHandler 是为了解决内存不释放的问题 WeakWebViewScriptMessageDelegate *weakScriptMessageDelegate = [[WeakWebViewScriptMessageDelegate alloc] initWithDelegate:self]; _userContentController = [[WKUserContentController alloc] init]; // 分享面板 [_userContentController addScriptMessageHandler:weakScriptMessageDelegate name:kJSOpenSharePage]; // 钱包页面 [_userContentController addScriptMessageHandler:weakScriptMessageDelegate name:kJSOpenPurse]; // 充值页面 [_userContentController addScriptMessageHandler:weakScriptMessageDelegate name:kJSOpenChargePage]; // 获取uid [_userContentController addScriptMessageHandler:weakScriptMessageDelegate name:kJSGetUid]; // 获取设备id [_userContentController addScriptMessageHandler:weakScriptMessageDelegate name:kJSGetDeviceId]; // 获取Ticket [_userContentController addScriptMessageHandler:weakScriptMessageDelegate name:kJSGetTicket]; // 获取设备info [_userContentController addScriptMessageHandler:weakScriptMessageDelegate name:kJSGetDeviceInfo]; // 实人认证: 打开原生人脸认证 [_userContentController addScriptMessageHandler:weakScriptMessageDelegate name:kJSOpenFaceLiveness]; } return _userContentController; } @end