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