// // KBWebViewViewController.m // keyBoard // // Created by 张伟 on 2025/11/10. // #import "KBWebViewViewController.h" #import @interface KBWebViewViewController () @property(nonatomic, strong) WKWebView * webView; // 🟢 顶部加载进度条 @property(nonatomic, strong) UIProgressView *progressView; @property(nonatomic, assign) BOOL observingProgress; @end @implementation KBWebViewViewController - (void)viewDidLoad { [super viewDidLoad]; [self configUI]; } - (void)configUI { // 1. 配置 JS 交互 WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]; WKUserContentController *userContentController = [[WKUserContentController alloc] init]; [userContentController addScriptMessageHandler:self name:@"keyBoard"]; config.userContentController = userContentController; // 2. 创建 webView self.webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:config]; self.webView.navigationDelegate = self; self.webView.translatesAutoresizingMaskIntoConstraints = NO; self.webView.backgroundColor = UIColor.clearColor; self.webView.frame = self.view.bounds; [self.view addSubview:self.webView]; // 🟢 3. 顶部 2 像素进度条 self.progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault]; self.progressView.translatesAutoresizingMaskIntoConstraints = NO; self.progressView.trackTintColor = [UIColor clearColor]; // 背景透明 self.progressView.progressTintColor = [UIColor greenColor]; self.progressView.progress = 0.0f; self.progressView.hidden = YES; // 初始隐藏 [self.view addSubview:self.progressView]; // 约束:贴在最上面,高度 2 像素,左右撑满 [NSLayoutConstraint activateConstraints:@[ [self.progressView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor], [self.progressView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], [self.progressView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], [self.progressView.heightAnchor constraintEqualToConstant:2.0] ]]; // 🟢 4. 监听 WKWebView 加载进度(estimatedProgress) [self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil]; self.observingProgress = YES; // 5. 加载 URL NSURLRequest * req = [NSURLRequest requestWithURL:[NSURL URLWithString:self.url]]; [self.webView loadRequest:req]; } #pragma mark - KVO: 监听加载进度(estimatedProgress) 🟢 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (object == self.webView && [keyPath isEqualToString:@"estimatedProgress"]) { CGFloat progress = self.webView.estimatedProgress; // 0 ~ 1之间的进度 self.progressView.hidden = NO; [self.progressView setProgress:progress animated:YES]; if (progress >= 1.0f) { // 加载完成后延迟一点点再隐藏,顺滑一点 [UIView animateWithDuration:0.25 delay:0.25 options:UIViewAnimationOptionCurveEaseOut animations:^{ self.progressView.alpha = 0.0; } completion:^(BOOL finished) { self.progressView.progress = 0.0; self.progressView.hidden = YES; self.progressView.alpha = 1.0; }]; } } else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } #pragma mark - WKNavigationDelegate // 开始加载 - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation { NSLog(@"开始加载url"); // 开始加载时,确保进度条出现 self.progressView.hidden = NO; self.progressView.progress = 0.0; } // 加载完成 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { NSLog(@"页面加载成功"); self.title = webView.title; } // 加载失败 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error { NSLog(@"webView load error: %@", error); // 失败时也把进度条收一下 self.progressView.hidden = YES; self.progressView.progress = 0.0; } #pragma mark - WKScriptMessageHandler (JS 调原生) - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { if (![message.body isKindOfClass:NSDictionary.class]) { NSLog(@"Body参数不合法"); return; } [self handleJSMethodWithParams:message.body]; } - (void)handleJSMethodWithParams:(NSDictionary *)params { NSDictionary * body = [params copy]; NSLog(@"收到 JS 消息: %@", body); NSString * type = body[@"type"]; // 测试打印 if ([type isEqual:@"ONE_METHOD"]) { NSLog(@"come on baby js 调用你的方法了"); } // 修改title if ([type isEqual:@"changeTiele"]) { NSLog(@"%@", body); NSString * newTiele = body[@"payload"][@"data"]; self.title = newTiele; } } #pragma mark - Clean up 🟢 - (void)dealloc { if (self.observingProgress) { @try { [self.webView removeObserver:self forKeyPath:@"estimatedProgress"]; } @catch (NSException *exception) { NSLog(@"removeObserver estimatedProgress exception: %@", exception); } } // 顺便把 JS 通道也移除,避免潜在的循环引用 [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"keyBoard"]; } @end