[iOS 10] WKWebViewのLink Preview APIについて

2016.10.25

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

WKWebViewのリンクをPeek、Pop時の挙動がカスタマイズできるようになった

iOS 9まではWWKWebViewallowsLinkPreviewプロパティでプレビューをするかしないかの制御ができるくらいで、リンクをPeekした時はプレビュー表示、Pop時にはSafariアプリでリンク先ページを開くという挙動をカスタマイズすることはできませんでしたが、iOS 10でカスタマイズできるようになりました。

カスタマイズで何ができるようになったのか

具体的には以下ができるようになりました。

  • リンクのURLに応じてプレビューするかしないかを制御できるようになった
  • peek時(プレビュー時)に表示する画面(UIViewController)が指定できるようになった
  • pop時のイベントがハンドリングできるようになった

上記はWKUIDelegateに追加された下記メソッドを実装することで可能となります。

optional public func webView(_ webView: WKWebView, shouldPreviewElement elementInfo: WKPreviewElementInfo) -> Bool

optional public func webView(_ webView: WKWebView, previewingViewControllerForElement elementInfo: WKPreviewElementInfo, defaultActions previewActions: [WKPreviewActionItem]) -> UIViewController?

optional public func webView(_ webView: WKWebView, commitPreviewingViewController previewingViewController: UIViewController)

リンクのURLに応じてプレビューするかしないかを制御するには

public func webView(_ webView: WKWebView, shouldPreviewElement elementInfo: WKPreviewElementInfo) -> Bool

を実装します。 パラメータのWKPreviewElementInfoはiOS 10で追加されたクラスでlinkURLプロパティ(リンク先のURL)を持ちます。 以下はリンク先URLがhttps://classmethod.jp/の時のみプレビューする実装となります。

public func webView(_ webView: WKWebView, shouldPreviewElement elementInfo: WKPreviewElementInfo) -> Bool {
    return elementInfo.linkURL?.absoluteString == "https://classmethod.jp/"
}

peek時(プレビュー時)に表示する画面(UIViewController)が指定するには

public func webView(_ webView: WKWebView, previewingViewControllerForElement elementInfo: WKPreviewElementInfo, defaultActions previewActions: [WKPreviewActionItem]) -> UIViewController?

を実装します。 任意のUIViewControllerを返すことができます。また、defaultActionsにはプレビュー時に上にスワイプした際に表示されるアクションのデフォルトが渡ってきます。デフォルトを使う場合もカスタムのアクションにする場合も、いずれにしても返すUIViewControllerpreviewActionItemsを実装すればそれが表示されます。 以下ではstoryboardからIDを指定して生成したUIViewControllerを返しています。

public func webView(_ webView: WKWebView, previewingViewControllerForElement elementInfo: WKPreviewElementInfo, defaultActions previewActions: [WKPreviewActionItem]) -> UIViewController? {
    let vc = storyboard?.instantiateViewController(withIdentifier: "PreviewingViewController")
    return vc
}

pop時のイベントがハンドリングするには

public func webView(_ webView: WKWebView, commitPreviewingViewController previewingViewController: UIViewController)

を実装します。 リファレンスにはYou must display the previewed view controller inside of your app.と書かれていますので、パラメータで渡されたUIViewControllerを表示しましょう。

public func webView(_ webView: WKWebView, commitPreviewingViewController previewingViewController: UIViewController) {
    present(previewingViewController, animated: true)
}

PreviewingViewControllerの実装サンプル

PreviewingViewControllerは以下のような実装としました。 pop時に当該ViewControllerが表示された後に閉じるボタンと、previewActionItemsでプレビュー時に上にスワイプした際に表示されるアクションを定義しています。(※ここでは、指定したアイテムの表示確認が目的であるため、タップ時の動作やアイテム名に特に意味はありません。)

class PreviewingViewController: UIViewController {

    @IBAction func didTapCloseButton(_ sender: AnyObject) {
        dismiss(animated: true)
    }

    override var previewActionItems: [UIPreviewActionItem] {
        get {
            let item1 = UIPreviewAction(title: "アイテム1", style: .default) { (_, _) in }
            let item2 = UIPreviewAction(title: "アイテム2", style: .destructive) { (_, _) in }
            let item3 = UIPreviewAction(title: "アイテム3", style: .selected) { (_, _) in }
            return [item1, item2, item3]
        }
    }
}

実行結果

link-preview-api-in-wkwebview

まとめ

今回はWKWebViewのLink Preview APIについてご紹介しました。
これまでpop時にはSafariが起動していましたが、アプリ内で完結することが可能となりました。 カスタマイズできることが増えることは何よりです。

参考