// // WebViewController.m // AIIM // // Created by on 2025/10/23. // #import "WebViewController.h" #import @interface WebViewController () @property (nonatomic, strong) WKWebView *webView; @property (nonatomic, strong) UIProgressView *progressView; @property (nonatomic, strong) UIButton *backButton; @property (nonatomic, strong) UILabel *titleLabel; @end @implementation WebViewController #pragma mark - Lifecycle - (instancetype)initWithURL:(NSURL *)url { return [self initWithURL:url title:nil]; } - (instancetype)initWithURL:(NSURL *)url title:(NSString *)title { self = [super init]; if (self) { _url = url; self.title = title; self.hidesBottomBarWhenPushed = YES; } return self; } - (void)viewDidLoad { [super viewDidLoad]; [self setupUI]; [self setupNavigationBar]; [self setupWebView]; if (self.url) { [self loadURL:self.url]; } } - (void)dealloc { [self.webView removeObserver:self forKeyPath:@"estimatedProgress"]; [self.webView removeObserver:self forKeyPath:@"title"]; [self.webView removeObserver:self forKeyPath:@"canGoBack"]; [self.webView removeObserver:self forKeyPath:@"canGoForward"]; } #pragma mark - UI Setup - (void)setupUI { self.view.backgroundColor = [UIColor blackColor]; } - (void)setupWebView { // 配置 WKWebView WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init]; configuration.allowsInlineMediaPlayback = YES; configuration.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone; // 创建 WKWebView self.webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]; self.webView.navigationDelegate = self; self.webView.UIDelegate = self; self.webView.allowsBackForwardNavigationGestures = YES; [self.view addSubview:self.webView]; [self.webView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.bottom.equalTo(self.view); make.top.equalTo(self.titleLabel.mas_bottom).mas_offset(0); }]; // 添加 KVO 监听 [self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil]; [self.webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:nil]; [self.webView addObserver:self forKeyPath:@"canGoBack" options:NSKeyValueObservingOptionNew context:nil]; [self.webView addObserver:self forKeyPath:@"canGoForward" options:NSKeyValueObservingOptionNew context:nil]; } - (void)setupNavigationBar { self.titleLabel = [UILabel new]; self.titleLabel.text = self.title; self.titleLabel.textColor = [UIColor whiteColor]; self.titleLabel.font = SYSBFONT(18); [self.view addSubview:self.titleLabel]; [self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self.view); make.width.mas_lessThanOrEqualTo(200); make.top.equalTo(self.view).mas_offset(STATUS_Height); make.height.mas_equalTo(44); }]; self.backButton = [UIButton buttonWithType:UIButtonTypeCustom]; [self.backButton setImage:kImageMake(@"fanhui") forState:UIControlStateNormal]; [self.backButton addTarget:self action:@selector(goBack) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:self.backButton]; [self.backButton mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(self.view).mas_offset(10); make.centerY.equalTo(self.titleLabel); make.size.mas_equalTo(CGSizeMake(32, 32)); }]; // 进度条 self.progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault]; self.progressView.progressTintColor = globalColor(GCTypeGreen); self.progressView.trackTintColor = [UIColor clearColor]; self.progressView.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:self.progressView]; [self.progressView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self.view); make.top.equalTo(self.titleLabel.mas_bottom).mas_offset(0); make.height.mas_equalTo(2); }]; } #pragma mark - Actions - (void)closeButtonTapped { [self dismissViewControllerAnimated:YES completion:nil]; } - (void)goBack { if ([self.webView canGoBack]) { [self.webView goBack]; } else { [self.navigationController popViewControllerAnimated:YES]; } } #pragma mark - Private Methods - (void)loadURL:(NSURL *)url { NSURLRequest *request = [NSURLRequest requestWithURL:url]; [self.webView loadRequest:request]; } #pragma mark - KVO - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"estimatedProgress"]) { // 更新进度条 float progress = [[change objectForKey:NSKeyValueChangeNewKey] floatValue]; [self.progressView setProgress:progress animated:YES]; // 进度完成时隐藏进度条 if (progress >= 1.0) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.progressView.hidden = YES; }); } else { self.progressView.hidden = NO; } } else if ([keyPath isEqualToString:@"title"]) { NSString *title = [change objectForKey:NSKeyValueChangeNewKey]; self.title = title.length > 0 ? title : @"网页"; self.titleLabel.text = self.title; } else if ([keyPath isEqualToString:@"canGoBack"] || [keyPath isEqualToString:@"canGoForward"]) { // 更新导航按钮状态 } } #pragma mark - WKNavigationDelegate - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation { self.progressView.hidden = NO; } - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { } - (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error { if (error.code != NSURLErrorCancelled) { UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"加载失败" message:error.localizedDescription preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]; [alert addAction:okAction]; [self presentViewController:alert animated:YES completion:nil]; } } - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { NSURL *url = navigationAction.request.URL; // 处理特殊 URL scheme if (![url.scheme isEqualToString:@"http"] && ![url.scheme isEqualToString:@"https"]) { // 尝试打开外部应用 if ([[UIApplication sharedApplication] canOpenURL:url]) { [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil]; } decisionHandler(WKNavigationActionPolicyCancel); return; } decisionHandler(WKNavigationActionPolicyAllow); } @end