diff --git a/Pods/Pods.xcodeproj/xcuserdata/zhangwei.xcuserdatad/xcschemes/xcschememanagement.plist b/Pods/Pods.xcodeproj/xcuserdata/zhangwei.xcuserdatad/xcschemes/xcschememanagement.plist index de03d1d..4b5efaf 100644 --- a/Pods/Pods.xcodeproj/xcuserdata/zhangwei.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Pods/Pods.xcodeproj/xcuserdata/zhangwei.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,73 +7,118 @@ AFNetworking.xcscheme_^#shared#^_ orderHint - 15 + 9 Bugly.xcscheme_^#shared#^_ orderHint - 4 + 16 DZNEmptyDataSet.xcscheme_^#shared#^_ orderHint - 9 + 12 - LookinServer.xcscheme_^#shared#^_ + FLAnimatedImage.xcscheme_^#shared#^_ orderHint - 6 + 15 - MBProgressHUD.xcscheme_^#shared#^_ + HWPanModal.xcscheme_^#shared#^_ orderHint 5 - MJExtension-MJExtension.xcscheme_^#shared#^_ - - orderHint - 3 - - MJExtension.xcscheme_^#shared#^_ - - orderHint - 13 - - MJRefresh-MJRefresh.Privacy.xcscheme_^#shared#^_ - - orderHint - 10 - - MJRefresh.xcscheme_^#shared#^_ - - orderHint - 7 - - Masonry.xcscheme_^#shared#^_ - - orderHint - 11 - - Pods-CustomKeyboard.xcscheme_^#shared#^_ - - orderHint - 12 - - Pods-keyBoard.xcscheme_^#shared#^_ + JXCategoryView-JXCategoryView.xcscheme_^#shared#^_ orderHint 2 - SDWebImage-SDWebImage.xcscheme_^#shared#^_ + JXCategoryView.xcscheme_^#shared#^_ orderHint - 14 + 21 - SDWebImage.xcscheme_^#shared#^_ + JXPagingView-JXPagerView.xcscheme_^#shared#^_ + + orderHint + 11 + + JXPagingView.xcscheme_^#shared#^_ + + orderHint + 17 + + LSTPopView.xcscheme_^#shared#^_ orderHint 8 + LSTTimer.xcscheme_^#shared#^_ + + orderHint + 13 + + LYEmptyView.xcscheme_^#shared#^_ + + orderHint + 6 + + LookinServer.xcscheme_^#shared#^_ + + orderHint + 7 + + MBProgressHUD.xcscheme_^#shared#^_ + + orderHint + 19 + + MJExtension-MJExtension.xcscheme_^#shared#^_ + + orderHint + 4 + + MJExtension.xcscheme_^#shared#^_ + + orderHint + 23 + + MJRefresh-MJRefresh.Privacy.xcscheme_^#shared#^_ + + orderHint + 14 + + MJRefresh.xcscheme_^#shared#^_ + + orderHint + 18 + + Masonry.xcscheme_^#shared#^_ + + orderHint + 22 + + Pods-CustomKeyboard.xcscheme_^#shared#^_ + + orderHint + 3 + + Pods-keyBoard.xcscheme_^#shared#^_ + + orderHint + 10 + + SDWebImage-SDWebImage.xcscheme_^#shared#^_ + + orderHint + 24 + + SDWebImage.xcscheme_^#shared#^_ + + orderHint + 20 + diff --git a/keyBoard.xcodeproj/project.pbxproj b/keyBoard.xcodeproj/project.pbxproj index 3a4de1b..322d1bb 100644 --- a/keyBoard.xcodeproj/project.pbxproj +++ b/keyBoard.xcodeproj/project.pbxproj @@ -117,6 +117,7 @@ 04FC97092EB31B14007BD342 /* KBHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC97082EB31B14007BD342 /* KBHUD.m */; }; 04FC970E2EB334F8007BD342 /* UIImageView+KBWebImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC970B2EB334F8007BD342 /* UIImageView+KBWebImage.m */; }; 04FC970F2EB334F8007BD342 /* KBWebImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC970D2EB334F8007BD342 /* KBWebImageManager.m */; }; + 7276DDA82EC1B28300804C36 /* KBWebViewViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7276DDA72EC1B28300804C36 /* KBWebViewViewController.m */; }; 7A36414DFDA5BEC9B7D2E318 /* Pods_CustomKeyboard.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C1092FB2B452F95B15D4263 /* Pods_CustomKeyboard.framework */; }; A1B2C3D42EB0A0A100000001 /* KBFunctionTagCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D32EB0A0A100000001 /* KBFunctionTagCell.m */; }; A1B2C3E22EB0C0A100000001 /* KBNetworkManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3E12EB0C0A100000001 /* KBNetworkManager.m */; }; @@ -347,6 +348,8 @@ 04FC98012EB36AAB007BD342 /* KBConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBConfig.h; sourceTree = ""; }; 2C1092FB2B452F95B15D4263 /* Pods_CustomKeyboard.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CustomKeyboard.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 51FE7C4C42C2255B3C1C4128 /* Pods-keyBoard.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-keyBoard.release.xcconfig"; path = "Target Support Files/Pods-keyBoard/Pods-keyBoard.release.xcconfig"; sourceTree = ""; }; + 7276DDA62EC1B28300804C36 /* KBWebViewViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBWebViewViewController.h; sourceTree = ""; }; + 7276DDA72EC1B28300804C36 /* KBWebViewViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBWebViewViewController.m; sourceTree = ""; }; 727EC7532EAF848B00B36487 /* keyBoard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = keyBoard.app; sourceTree = BUILT_PRODUCTS_DIR; }; 967065BB5230E43F293B3AF9 /* Pods_keyBoard.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_keyBoard.framework; sourceTree = BUILT_PRODUCTS_DIR; }; A1B2C3D22EB0A0A100000001 /* KBFunctionTagCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBFunctionTagCell.h; sourceTree = ""; }; @@ -853,6 +856,7 @@ 04FC95BF2EB1E3B1007BD342 /* Class */ = { isa = PBXGroup; children = ( + 7276DDA22EC1B22500804C36 /* WebView */, 048908D32EBF618E00FABA60 /* Vender */, 048908C02EBE329D00FABA60 /* Search */, 048908B92EBDC11200FABA60 /* Common */, @@ -1065,6 +1069,15 @@ name = Frameworks; sourceTree = ""; }; + 7276DDA22EC1B22500804C36 /* WebView */ = { + isa = PBXGroup; + children = ( + 7276DDA62EC1B28300804C36 /* KBWebViewViewController.h */, + 7276DDA72EC1B28300804C36 /* KBWebViewViewController.m */, + ); + path = WebView; + sourceTree = ""; + }; 727EC74A2EAF848B00B36487 = { isa = PBXGroup; children = ( @@ -1352,6 +1365,7 @@ 047C65102EBCA8DD0035E841 /* HomeRankContentVC.m in Sources */, 047C655C2EBCD0F80035E841 /* UIView+KBShadow.m in Sources */, 048908C32EBE32B800FABA60 /* KBSearchVC.m in Sources */, + 7276DDA82EC1B28300804C36 /* KBWebViewViewController.m in Sources */, 047C655E2EBCD5B20035E841 /* UIImage+KBColor.m in Sources */, 04FC95DD2EB202A3007BD342 /* KBGuideVC.m in Sources */, 04FC95E52EB220B5007BD342 /* UIColor+Extension.m in Sources */, diff --git a/keyBoard.xcworkspace/xcuserdata/zhangwei.xcuserdatad/UserInterfaceState.xcuserstate b/keyBoard.xcworkspace/xcuserdata/zhangwei.xcuserdatad/UserInterfaceState.xcuserstate index 0b4c054..db97225 100644 Binary files a/keyBoard.xcworkspace/xcuserdata/zhangwei.xcuserdatad/UserInterfaceState.xcuserstate and b/keyBoard.xcworkspace/xcuserdata/zhangwei.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/keyBoard/Class/Shop/VC/KBShopVC.m b/keyBoard/Class/Shop/VC/KBShopVC.m index 526cd1e..e6d6dac 100644 --- a/keyBoard/Class/Shop/VC/KBShopVC.m +++ b/keyBoard/Class/Shop/VC/KBShopVC.m @@ -14,6 +14,8 @@ #import #import "KBShopItemVC.h" +#import "KBWebViewViewController.h" + static const CGFloat JXTableHeaderViewHeight = (323); static const CGFloat JXheightForHeaderInSection = 50; diff --git a/keyBoard/Class/WebView/KBWebViewViewController.h b/keyBoard/Class/WebView/KBWebViewViewController.h new file mode 100644 index 0000000..4d74711 --- /dev/null +++ b/keyBoard/Class/WebView/KBWebViewViewController.h @@ -0,0 +1,18 @@ +// +// KBWebViewViewController.h +// keyBoard +// +// Created by 张伟 on 2025/11/10. +// + +#import "BaseViewController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface KBWebViewViewController : BaseViewController + +@property(nonatomic,copy) NSString * url; + +@end + +NS_ASSUME_NONNULL_END diff --git a/keyBoard/Class/WebView/KBWebViewViewController.m b/keyBoard/Class/WebView/KBWebViewViewController.m new file mode 100644 index 0000000..d93e321 --- /dev/null +++ b/keyBoard/Class/WebView/KBWebViewViewController.m @@ -0,0 +1,177 @@ +// +// 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