178 lines
6.0 KiB
Objective-C
178 lines
6.0 KiB
Objective-C
//
|
||
// KBWebViewViewController.m
|
||
// keyBoard
|
||
//
|
||
// Created by 张伟 on 2025/11/10.
|
||
//
|
||
|
||
#import "KBWebViewViewController.h"
|
||
#import <WebKit/WebKit.h>
|
||
|
||
@interface KBWebViewViewController () <WKNavigationDelegate, WKScriptMessageHandler>
|
||
|
||
@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<NSKeyValueChangeKey,id> *)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
|