替换UIWebView为WKWebView后键盘残留无响应问题求助
WKWebView 移除时键盘残留无响应问题
将原使用UIWebView的应用迁移到WKWebView后,遇到键盘残留且无响应的问题,复现步骤如下:
- 打开含输入框的URL并将WKWebView添加到父视图;
- 激活输入框,弹出键盘,可正常输入;
- 键盘显示时移除WKWebView,此时键盘正常消失;
- 再次打开含输入框的URL并添加WKWebView到父视图;
- 激活输入框,弹出键盘;
- 键盘显示时移除WKWebView,此时键盘无法消失且无响应。
预期每次移除WebView时键盘都能正常消失,目前使用以下销毁代码无效:
[webView stopLoading]; webView.navigationDelegate = nil; webView.scrollView.delegate = nil; [webView removeFromSuperview]; webView = nil;
完整测试代码:
- (void)viewDidLoad { [super viewDidLoad]; webView = nil; webViewIsActive = FALSE; tap2Recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)]; tap2Recognizer.numberOfTouchesRequired = 1; tap2Recognizer.numberOfTapsRequired = 2; tap2Recognizer.delegate = self; [self.view addGestureRecognizer:tap2Recognizer]; } - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { return YES; } - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES; } - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { return YES; } - (void)handleDoubleTap:(UITapGestureRecognizer *)gestureRecognizer { if (webViewIsActive) { if (keyboardIsVisible) [webView endEditing:true]; else [self removeWebView]; } else [self addWebView]; } - (void)addWebView { webView = [[WKWebView alloc] initWithFrame:self.view.frame]; webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; webView.allowsBackForwardNavigationGestures = false; webView.navigationDelegate = self; NSURL *url = [NSURL URLWithString:@"https://google.com"]; NSURLRequest *requestObj = [NSURLRequest requestWithURL:url]; [webView loadRequest:requestObj]; [self.view addSubview:webView]; webViewIsActive = TRUE; } - (void)removeWebView { if (webView) { [webView stopLoading]; webView.navigationDelegate = nil; webView.scrollView.delegate = nil; [webView removeFromSuperview]; webView = nil; } webViewIsActive = FALSE; }
补充尝试:已尝试跟踪键盘可见性但无效,甚至在手势代理中返回!self.keyboardIsVisible也没用。另有奇怪现象:弹出键盘后关闭,双击移除WebView,再双击添加并弹出键盘,键盘直接失效。
解决方案
这个问题源于WKWebView的跨进程特性,WebKit进程的键盘状态未与App主线程同步,直接销毁WebView会打断键盘回收流程,以下是可行的解决方法:
1. 移除前强制结束全局编辑状态
在销毁WKWebView前,调用视图控制器根视图的endEditing:方法,确保所有第一响应者(包括WebView内的输入框) resign,强制收起键盘:
- (void)removeWebView { if (webView) { // 先让整个视图结束编辑,确保键盘收起 [self.view endEditing:YES]; [webView stopLoading]; webView.navigationDelegate = nil; webView.scrollView.delegate = nil; [webView removeFromSuperview]; webView = nil; } webViewIsActive = FALSE; }
2. 延迟销毁WKWebView
给WebKit进程一点时间处理键盘回收逻辑,延迟释放WebView实例:
- (void)removeWebView { if (webView) { [self.view endEditing:YES]; [webView stopLoading]; webView.navigationDelegate = nil; webView.scrollView.delegate = nil; [webView removeFromSuperview]; // 延迟0.1秒释放,等待内部状态清理完成 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ webView = nil; }); } webViewIsActive = FALSE; }
3. 监听键盘通知精准管理状态
通过键盘通知实时跟踪键盘状态,在移除WebView时根据状态做针对性处理:
// 在viewDidLoad中注册通知 - (void)viewDidLoad { [super viewDidLoad]; // ... 原有代码 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; } // 实现通知回调 - (void)keyboardWillShow:(NSNotification *)notification { keyboardIsVisible = YES; } - (void)keyboardWillHide:(NSNotification *)notification { keyboardIsVisible = NO; } // 在dealloc中移除通知 - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; }
修改移除逻辑:
- (void)removeWebView { if (webView) { [webView stopLoading]; webView.navigationDelegate = nil; webView.scrollView.delegate = nil; if (keyboardIsVisible) { [self.view endEditing:YES]; // 等待键盘完全收起后再销毁 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [webView removeFromSuperview]; webView = nil; }); } else { [webView removeFromSuperview]; webView = nil; } } webViewIsActive = FALSE; }
内容的提问来源于stack exchange,提问作者Deron
相关产品推荐
相关产品推荐

