WKWebView: проблемы с открытием ссылок в Safari - PullRequest
0 голосов
/ 02 апреля 2020

Прежде чем я начну, следует отметить, что часть моего вопроса является дубликатом этой публикации, на которую нет принятого ответа. Кроме того, я прочитал несколько других сообщений SO, которые похожи на мой вопрос, но не точны, такие как this и this .

Вопрос:

Я использую WKWebView для отображения текста, отмеченного в HTML. Часть текста содержит ссылки, которые я хочу открыть в Safari при нажатии. Я продвинулся довольно далеко, но у меня все еще есть две основные проблемы.

1) WKWebView не отвечает на первое нажатие сеанса, т. Е. Нужно нажать на первую ссылку, которая была нажата дважды, чтобы открыть Safari. При последующем нажатии любой ссылки Safari немедленно открывается.

2) Safari открывается только по URL первой ссылки, которая была нажата. Допустим, отображаются 3 URL-адреса: A, B и C. Если сначала нажать A, то после нажатия любого из двух других URL-адресов Safari всегда будет открываться для A, пока WKWebView инициализируется. Если сначала нажать B, Safari будет открыт только для B, и т. Д. c.

Вот мой код Swift, который, я думаю, наиболее актуален для этого вопроса:

class CustomWebView: WKWebView, WKUIDelegate, WKNavigationDelegate {

    convenience init() {

        let config = WKWebViewConfiguration()
        config.dataDetectorTypes = [.all]

        self.init(frame: .zero, configuration: config)
        navigationDelegate = self
        uiDelegate = self
    }

    func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (_: WKNavigationResponsePolicy) -> Void) {
        decisionHandler(.allow)
    }

    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (_: WKNavigationActionPolicy) -> Void) {

        if let url = navigationAction.request.url {
        print("url: \(url)")

            let paths = url.absoluteString.components(separatedBy: ",")
            print("paths: \(paths)")

            for path in paths {

                if path.contains("link:") {

                    let link = path.replacingOccurrences(of: "link:", with: "").replacingOccurrences(of: "%22", with: "")
                    print("link: \(link)")

                    if let cleanedURL = URL(string: link) {
                    print("cleanedURL: \(cleanedURL)")

                        UIApplication.shared.open(cleanedURL, options: [:], completionHandler: nil)
                        decisionHandler(.cancel)
                        return
                    }
                }
            }
        }
        decisionHandler(.allow)
    }
}

Вот пример HTML, который я тестирую:

<a href="https://www.bbc.com/">https://www.bbc.com/</a>
<div>
    <br />
</div>
<div><a href="https://www.youtube.com/">https://www.youtube.com/</a>
    <br />
</div>
<div>
    <br />
</div>
<div><a href="https://stackoverflow.com/">https://stackoverflow.com/</a>
    <br />
</div>

Вот то, что показывают операторы печати:

Шаг 1

Нажмите ссылку A:

url: callback://0/underline,justifyLeft,textColor

пути: ["callback://0/underline", "justifyLeft", "textColor"]

Шаг 2

Нажмите на ссылку A на секунду время:

URL: callback://0/underline,justifyLeft,textColor,link:https://www.bbc.com/

пути: ["callback://0/underline", "justifyLeft", "textColor", "link:https://www.bbc.com/"]

ссылка: https://www.bbc.com/

cleanedURL: https://www.bbc.com/

Шаг 3

Нажатие на ссылку A, B или C после выполнения шага 2 дает те же операторы печати, что и шаг 2.

Другие примечания :

HTML происходит от ZSSRichTextEditor , который реализован в другой части приложения, чтобы пользовательский ввод был отмечен HTML. Иногда, когда пользователь вводит ссылку, HTML, которая выплевывается редактором, окружает ее %22, поэтому я включаю ее в приведенный выше код.

1 Ответ

0 голосов
/ 03 апреля 2020

Вы можете попробовать проверить тип действия.

  func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (_: WKNavigationActionPolicy) -> Void) {
    if navigationAction.navigationType == .linkActivated,
      let reqURL = navigationAction.request.url {
      UIApplication.shared.open(reqURL, options: [:], completionHandler: nil)
      decisionHandler(.cancel)

    } else {
      decisionHandler(.allow)
    }
  }

Но проблема в том, что многие веб-сайты перехватывают действия щелчка по элементам ссылки, чтобы вместо этого вызывать навигацию в JavaScript. В итоге они отправляются на decidePolicyFor как .other навигационные действия вместо .linkActivated.

...