WKWebView操作表在被解除后解除呈现的视图控制器

7

我有一个视图控制器(WKWebViewController),它嵌入在导航控制器中。此视图控制器显示了一个 WKWebView,在导航到任何网页后,长按包括电话号码或链接等检测到的内容时,将显示一个操作表,其中包含复制、共享等选项。问题在于当这个操作表被解除时,WKWebViewController 也随之消失,并显示根视图控制器!无论选择是复制、取消,还是在屏幕上任何地方点击。

我尝试重写“present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil)”和“dismiss(animated flag: Bool, completion: (() -> Void)?)”,以尝试了解发生了什么,但然后意识到操作表既没有由其父视图控制器(WKWebViewController)呈现,也没有被其父视图控制器解除。事实上,我在根视图控制器上做了同样的事情,并发现它也没有被展示在根视图控制器上。

我进行了大量搜索,试图理解是什么原因导致了这种行为,我甚至建立了一个只有简单 WKWebView 的新项目,结果总是遇到同样的问题。

这是代码:

import UIKit; import WebKit
class WKWebViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {

var destinationUrlString: String?
var myWebView: WKWebView!

override func viewDidLoad() {
    super.viewDidLoad()

    let webConfiguration = WKWebViewConfiguration()
    webConfiguration.dataDetectorTypes = []
    let origin = CGPoint(x: 0, y: 0)
    let size  = CGSize(width: view.frame.size.width, height: view.frame.size.height)
    myWebView = WKWebView(frame: .init(origin: origin, size: size), configuration: webConfiguration)
    myWebView.uiDelegate = self
    myWebView.navigationDelegate = self
    myWebView.allowsLinkPreview = false
    view = myWebView

    destinationUrlString = "https://www.stackoverflow.com"
    guard let url = URL(string: destinationUrlString!) else {return}
    print(url)
    let request = URLRequest(url: url)
    myWebView.load(request)
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
    //show progress indicator
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    //dismiss progress indicator
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
    //show error
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
    //show error
}
}

我还附上了一个GIF显示问题:

enter image description here

我使用的是Xcode 9.3(9E145)和Swift 4.1。

我错过了什么吗? 如何修复? 非常感谢您的任何帮助。


你尝试过这个吗?https://dev59.com/iZffa4cB1Zd3GeqP507S - Vinaykrishnan
是的,但它不起作用。正如我所解释的,呈现行动表“吹出”菜单的并不是父视图控制器,因此覆盖“present”和“dismiss”无效。 - ferasfa
你应该展示一下你的操作表代码。你设置了一个.cancel样式的操作吗? - thorb65
1
我并没有自己编写操作表单的代码,因此无法展示任何代码。我正在使用默认的操作表单,当检测到任何_dataDetectorTypes_时会弹出。例如:如果检测到电话号码,长按它将弹出选项表单,如:分享、复制、呼叫等。 - ferasfa
@ferasfa 你解决了吗? - el3ankaboot
3个回答

10

我曾经遇到过同样的问题。

为了解决这个问题,在 UIViewController 的层次结构的根视图控制器中(在你的情况下,这将是“根视图控制器”-注意,在许多情况下,它可能是一个 UINavigationController,然后你需要子类化它),重写 dismissViewControllerAnimated:completion: 来处理 WKWebView 多次调用 dismiss 的问题。

Objective-C

@property (weak) UIViewController *lastPresentedController;

- (void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion
{
    // WKWebView actions sheets workaround
    if (self.presentedViewController && self.lastPresentedController != self.presentedViewController ) {
        self.lastPresentedController = self.presentedViewController;
        [self.presentedViewController dismissViewControllerAnimated:YES completion:^{
            if( completion ) {
                completion();
            }
            self.lastPresentedController = nil;
        }];
    } else if( !self.lastPresentedController) {
        [super dismissViewControllerAnimated:flag completion:completion];
    }
}

Swift

private weak var lastPresentedController : UIViewController?

override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
    // WKWebView actions sheets workaround
    if presentedViewController != nil && lastPresentedController != presentedViewController  {
        lastPresentedController = presentedViewController;
        presentedViewController?.dismiss(animated: flag, completion: {
            completion?();
            self.lastPresentedController = nil;
        });

    } else if lastPresentedController == nil {
        super.dismiss(animated: flag, completion: completion);
    }
}

3
这对我有用。但是,我将这段代码片段添加到 NavigationController 代码中,而不是 UIViewController 中。 - Jeremy Bell
我不得不将代码放在包含WKWebView的视图控制器中,因为它是被呈现出来的。(iOS 11.4.1) - Daniel T.

1
这一定是一个bug。如果你在包含网页视图的viewController中覆盖了“dismiss”方法,当用户从操作表中选择任何操作时,该方法将被调用。如果您在dismiss覆盖中设置断点,您可以看到presentedViewController的类型是WKActionSheet,这是一个内部类。他们可能会调用dismiss来关闭操作表,然后向上传递并关闭我们包含网页视图的视图控制器。您可以从该函数中返回以防止关闭,但是他们选择的操作也不会发生。
如果您不想提交radar,请告诉我。

我认为这是一个漏洞。我已经向苹果报告了,但说实话,我不指望他们很快会回复我。我在这里还发现了一个关于这个问题的雷达:http://www.openradar.me/34547298。如果需要,请随时提交新的报告。 - ferasfa
几周前报告了这个问题,被标记为34960698的重复问题(该问题没有开放的雷达)。 - shim
2
@shim,重复的票据已列在:https://webkit.googlesource.com/WebKit/+/master/Source/WebKit/ChangeLog 它说已经修复了?哦。我也遇到了同样的问题。 - JackyW
甚至不知道WebKit是开源的。是的,看起来他们声称这个问题在三月份得到解决,但自那以后已经有新的iOS版本发布了,他们仍然存在这个问题。 - shim

0
- (void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion{
    if (@available(iOS 11, *)) {
        [super dismissViewControllerAnimated:flag completion:completion];
    }
    else{
        if ([self.topViewController isKindOfClass:[RTContainerController class]]){
            RTContainerController *topVC = (RTContainerController *)self.topViewController;
            if (![topVC.contentViewController isKindOfClass:NSClassFromString(@"MyWebViewController")]) {
                //让非 web 页面可以正常消失
                [self.topViewController dismissViewControllerAnimated:flag completion:completion];
            }else{
                //防止 web 页面消失
                if (self.presentedViewController) {
                    [self.presentedViewController dismissViewControllerAnimated:flag completion:completion];
                }
            }
        }else{
            if (self.presentedViewController) {
                [self.presentedViewController dismissViewControllerAnimated:flag completion:completion];
            }
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接