『入る学科間違えた高専生』の日記

プログラミングのコードを書いたりする予定です。あとは日記等。あといつまで高専生やねん

Universal LinksをiOSアプリで回避する

はじめに

Amazonアプリとか食べログアプリとかTwitterアプリとかをiOSバイスに入れてると、iOSアプリ内のWebViewとかでUniversal Linksに引っかかって、
アプリ内で表示したいのに!! って言うことがあって、調べたらなんか面白いのを見つけてやってみたら上手く行ったのでそれ

環境

現状の動作

食べログアプリで検証していきます。
1度食べログアプリは開いたことがある前提で。

UIWebViewでGoogle検索(他のエンジンでも)すると動画のように食べログアプリに遷移します。SFSafariViewControllerでも再現できました。

また、SFSafariViewControllerは以下で普通に動作させています。

import UIKit
import SafariServices

class ViewController: UIViewController {
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        let url = URL(string: "https://google.com")!
        let safari = SFSafariViewController(url: url)
        present(safari, animated: true, completion: nil)
    }
}

対策

参考にした記事が以下です。

stackoverflow.com

WKWebViewを使って実装します。
Xcode9 かつ DevelopmentTargetがiOS11以上の場合はInterfaceBuilderで実装できますが、今回はiOS10もサポートしているということにしてソースコードでWKWebViewを作っていきます。

import UIKit
import WebKit

class ViewController: UIViewController {

    private var wkWebView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()
        wkWebView = WKWebView(frame: .zero)
        let url = URL(string: "https://google.com")!
        wkWebView.load(URLRequest(url: url))
        wkWebView.navigationDelegate = self
        view.addSubview(wkWebView)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    override func viewDidLayoutSubviews() {
        if #available(iOS 11.0, *) {
            wkWebView.frame = CGRect(x: 0,
                                     y: 0,
                                     width: view.bounds.size.width,
                                     height: view.bounds.size.height - view.safeAreaInsets.bottom)
        } else {
            wkWebView.frame = CGRect(x: 0,
                                     y: 0,
                                     width: view.bounds.size.width,
                                     height: view.bounds.size.height)
        }
        super.viewDidLayoutSubviews()
    }
}

// MARK: - WKNavigationDelegate

extension ViewController: WKNavigationDelegate {

    func webView(_ webView: WKWebView,
                 decidePolicyFor navigationAction: WKNavigationAction,
                 decisionHandler: @escaping (WKNavigationActionPolicy) -> Swift.Void) {
        UIApplication.shared.isNetworkActivityIndicatorVisible = true
        decisionHandler(WKNavigationActionPolicy(rawValue: WKNavigationActionPolicy.allow.rawValue + 2)!)
    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        UIApplication.shared.isNetworkActivityIndicatorVisible = false
    }

    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        UIApplication.shared.isNetworkActivityIndicatorVisible = false
    }
}

いきなりですが、全体的な簡単なコードを置いておきます。
iOS11をサポートするということは必然的にiPhoneXをサポートすることになるので、SafeAreaについての振り分けを viewDidLayoutSubviews() でしています。

一応、動作動画です。

なんで WKNavigationActionPolicy.allow.rawValue + 2 なの?

Apple Developer Documentation Apple Developer Documentation

上記、ドキュメントにも書かれている通り WKNavigationActionPolicy は、 cancelallow しかない状態です。
誰かがどこぞから見つけてきた抜け穴のようですね。調べても一切情報がでてきません。出てきたとしても出処によってはNDA的な意味で紹介できませんが。
ちなみに + 1+ 3 をしてみたのですがやはり動きません。なんなんでしょうね、全然わからん

最後に

はい。なんか微妙な締めくくりですが、 WKWebView ですごく不思議な裏技を使ってUniversal Linksを回避するという内容でした。
多分今年の技術記事はこれが最後かなと。
明日明後日多分、今年の振り返り記事を書くかな?