0
0

More than 3 years have passed since last update.

WKWebView 遇到 target="_blank" 的處理

Last updated at Posted at 2020-01-08

如果有發現程式碼有問題歡迎留言告訴我!

前言

因為點了 WKWebView 中網頁的超連結發現他沒有反應,才發現這需要另外處理。

環境

Xcode 11.3, Swift 5, Storyboard

一些些前導知識

普通的超連結不需要手動處理, WKWebView 就會自己幫我們導到下一個頁面了。

target="_blank"

是 HTML 裡面 a (錨點, anchor) 標籤中,用來指定這個超連結應該要開一個新的視窗。

如果不加這個屬性,如下,就會在同一個頁面導向下個頁面。

<a href="https://apple.com">Apple</a>

如果加了該屬性,原先的頁面就不會有任何動作,在一般的瀏覽器就會幫你開一個新的視窗。

<a href="https://apple.com" target="_blank">Apple</a>

參照

_blank
Opens the linked document in a new window or tab

範例

在 Xcode 開一個新專案來試試看,在 Storyboard 裡面放一個 WKWebView 進去,並把他設定 IBOutlet 到所屬的 view controller 。

這裡就略過 Storyboard 裡面放了什麼,直接放初始化的程式碼。

import UIKit
import WebKit

class ViewController: UIViewController {

    @IBOutlet weak var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        webView.navigationDelegate = self
        webView.loadHTMLString(htmlString, baseURL: nil)
    }
}

extension ViewController: WKNavigationDelegate {
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        // 在這裡先讓他執行預設的行為
        decisionHandler(.allow)
    }
}

extension ViewController {
    /// 實際內容
    var htmlString: String {
        return """
            <h1><a href="https://apple.com" target="_blank">Apple</a></h1>
            <h1><a href="https://apple.com">Apple</a></h1>
        """
    }
}

實際的內容很簡單,就是兩個 Apple 的超連結,一個是有指定要新開頁面,另一個則是直接在原先的頁面跳轉。放 h1 的原因是 web view 中預設的字級會超小,直接用 h1 讓他成為大標變大字。

<h1><a href="https://apple.com" target="_blank">Apple</a></h1>
<h1><a href="https://apple.com">Apple</a></h1>

在 WKWebView 中的行為

到這裡先執行看看,
就會發現第一個超連結點下去之後他不會進行任何的跳轉, console 中還會出現像是這樣的錯誤訊息。
這個就是我們在這邊要解決的問題。

Unknown result for URL 0x2832bc0e0 (https)

而第二個超連結點下去則會順利的導向 Apple 的首頁。

得知按了一個連結和操作

在上面初始化的程式碼裡面也有寫出來,WKNavigationDelegate 中,有方法可以監聽,並作出對應的處理。在這邊就是使用這個方法。

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

在這個方法裡面,可以對 decisionHandler 傳入不同的值來告訴他該不該繼續跳轉或者是說進行預設的行為。 .allow 則是預設的行為。

decisionHandler(.allow)

取得這個超連結的內容並處理

我們可以透過第二個參數來取得超連結的內容,而在這邊我們想要看的就是和 target 屬性有相關的參數,也就是 targetFrame

navigationAction.targetFrame

如文件裡面的敘述:

The target frame, or nil if this is a new window navigation.

就可以知道,如果是超連結本身指定要開新視窗的話,這個屬性的值就會是 nil 。

檢查 targetFrame

因此這個方法的內容就可以改成這樣:

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

        // 為求範例單純化這邊只檢查 targetFrame ,
        // 實務上還是需要加上檢查 url 是不是合法可以開啟等等處理
        if navigationAction.targetFrame == nil {
            // 傳入 .cancel 停止 navigation 預設的行為
            decisionHandler(.cancel)

            // 這裡就是開始做想做的事情, webView.load 可以直接讓當前的 webView 導向目標頁面
            // 當然也可以開啟 SFSafariViewController 或是開啟 Mobile Safari / Mobile Chrome
            webView.load(navigationAction.request)

            // 呼叫過之後 devisionHandler 之後就在這邊讓這個方法結束
            return
        }

        decisionHandler(.allow)
    }
}

注意點

decisionHandler 呼叫第二次(及以上)會 crash

最後的程式碼

import UIKit
import WebKit

class ViewController: UIViewController {

    @IBOutlet weak var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        webView.navigationDelegate = self
        webView.loadHTMLString(htmlString, baseURL: nil)
    }
}

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

        if navigationAction.targetFrame == nil {
            decisionHandler(.cancel)
            webView.load(navigationAction.request)
            return
        }

        decisionHandler(.allow)
    }
}

extension ViewController {
    var htmlString: String {
        return """
            <h1><a href="https://apple.com" target="_blank">Apple</a></h1>
            <h1><a href="https://apple.com">Apple</a></h1>
        """
    }
}

參考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0