You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

替换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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 08:39:53