SwiftでWKWebViewを使いこなすたった10の方法

Swift言語を使用したWKWebViewの詳細ガイドSwift
この記事は約27分で読めます。

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

Web技術の進化とともに、モバイルアプリの中でWebコンテンツを表示するニーズは高まってきました。

特にiOSアプリを開発する上で、ウェブコンテンツを取り込む方法として「WKWebView」が注目されています。

この記事では、Swiftを使用してWKWebViewを効果的に利用する方法について、基本的な説明から応用例までを深く掘り下げています。

Swift言語を使用したWKWebViewの詳細ガイドとして、WKWebViewの使い方やカスタマイズ、注意点などを学ぶことができます。

●WKWebViewとは

WKWebViewは、Appleが提供するWebKitフレームワークの一部として存在するコンポーネントであり、iOSやmacOSのアプリケーションでWebコンテンツを表示するためのものです。

具体的には、HTMLやCSS、JavaScriptを使ったWebページをアプリ内で表示できる機能を持っています。

WKWebViewは、旧来のUIWebViewとは異なり、パフォーマンスの向上や新しい機能が追加されており、現在のiOSアプリ開発においては、UIWebViewよりもWKWebViewの使用が推奨されています。

これは、WKWebViewがモダンなWeb技術をサポートしており、高速なJavaScriptエンジンを搭載しているためです。

○SwiftにおけるWKWebViewの位置づけ

SwiftはAppleが開発したプログラミング言語であり、iOSやmacOSのアプリを開発するための主要な言語として位置づけられています。

WKWebViewはSwiftを用いて簡単に組み込むことができ、ネイティブのコードとWebコンテンツの間の連携もスムーズに行えます。

例えば、Swiftでアプリを開発する際に、外部のWebサイトのコンテンツを表示したい場合や、ローカルに保存されたHTMLファイルをアプリ内で表示したい場合など、さまざまなケースでWKWebViewが役立ちます。

そのため、Swiftのアプリ開発者にとって、WKWebViewの扱いを理解しておくことは非常に重要となります。

また、WKWebViewはSwiftだけでなくObjective-Cなど他の言語でも利用することが可能ですが、現代のアプリ開発においてはSwiftが主流となっているため、Swiftを用いたWKWebViewの使用方法が注目されています。

●WKWebViewの基本的な使い方

WKWebViewは、iOSおよびmacOSのWebコンテンツを表示するための主要なAPIとして使用されます。

Swift言語と共に、これを効果的に活用することで、アプリ内に綺麗なWebページを表示できます。

○サンプルコード1:WKWebViewの初期設定と表示

まず、WKWebViewをSwiftのプロジェクトに追加して使用する基本的な方法を確認しましょう。

このコードでは、Swiftを使用してWKWebViewを初期設定し、アプリに表示する方法を説明しています。

この例では、WKWebViewのインスタンスを作成し、画面全体に表示する設定を行っています。

import UIKit
import WebKit

class ViewController: UIViewController {

    var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // WKWebViewのインスタンスを作成
        webView = WKWebView(frame: self.view.bounds)
        self.view.addSubview(webView)

        // WebViewを画面全体に表示
        webView.translatesAutoresizingMaskIntoConstraints = false
        webView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
        webView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
        webView.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
        webView.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
    }
}

このコードを実装すると、アプリを起動した際に空のWKWebViewが画面全体に表示されます。

次に、具体的なWebコンテンツをロードして表示する方法を見てみましょう。

○サンプルコード2:特定のURLをロードする

WKWebViewを使って、特定のURLのWebページを表示する方法を解説します。

このコードでは、Swiftを使ってWKWebViewに特定のURLをロードする方法を表しています。

この例では、”https://www.example.com”というURLのWebページをロードしてWKWebViewに表示しています。

override func viewDidLoad() {
    super.viewDidLoad()

    // 以前のWKWebViewの設定は省略...

    // 特定のURLをロード
    let url = URL(string: "https://www.example.com")!
    let request = URLRequest(url: url)
    webView.load(request)
}

このコードを実装すると、アプリを起動すると”https://www.example.com”のWebページがWKWebViewに表示されます。

ただし、実際にアプリを使用する際には、使用するURLを適切に設定することをおすすめします。

●WKWebViewでのJavaScriptの取り扱い

WKWebViewは、Webコンテンツの表示を可能にするためのUIコンポーネントとしてSwiftに組み込まれていますが、それだけではなくJavaScriptとの相互作用もサポートしています。

JavaScriptは、動的なWebコンテンツや高度なユーザーインタラクションを実現するためのプログラミング言語として広く利用されています。

そのため、WKWebViewを活用する際にはJavaScriptとの連携が避けられない場面が多く存在します。

○サンプルコード3:JavaScriptの評価と実行

下記のコードでは、WKWebView内でJavaScriptを評価し、その結果をSwiftのコード側で取得する方法を表しています。

この例では、JavaScriptで現在のWebページのタイトルを取得し、Swiftのコード側でそのタイトルをログに表示しています。

import UIKit
import WebKit

class ViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {

    var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        webView = WKWebView(frame: self.view.frame)
        webView.uiDelegate = self
        webView.navigationDelegate = self
        self.view.addSubview(webView)

        let url = URL(string: "https://example.com")!
        webView.load(URLRequest(url: url))
    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        webView.evaluateJavaScript("document.title") { (result, error) in
            if let title = result as? String {
                print("Webページのタイトルは「\(title)」です。")
            }
        }
    }
}

このコードでは、evaluateJavaScriptメソッドを使用してJavaScriptのコードを評価しています。

そして、このメソッドのコールバック関数内で、JavaScriptの評価結果を取得しています。

この例では、document.titleを評価して、取得したWebページのタイトルをログに出力しています。

このコードを実行すると、Webページのタイトルがコンソールに出力されます。

例えば、対象のWebページのタイトルが「Example Domain」という場合、コンソールには「Webページのタイトルは「Example Domain」です。」と表示されます。

○サンプルコード4:JavaScriptとSwiftの相互連携

JavaScriptとSwiftの相互連携は、Webページ内のJavaScriptからSwiftのコードを呼び出す場面や、SwiftのコードからJavaScriptの関数を実行する場面など、さまざまな場面で役立ちます。

下記のコードは、Webページ内のボタンをクリックするとSwiftのコードが実行される例を表しています。

import UIKit
import WebKit

class ViewController: UIViewController, WKScriptMessageHandler {

    var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let webConfiguration = WKWebViewConfiguration()
        let contentController = WKUserContentController()
        contentController.add(self, name: "buttonClicked")
        webConfiguration.userContentController = contentController

        webView = WKWebView(frame: self.view.frame, configuration: webConfiguration)
        self.view.addSubview(webView)

        let htmlString = """
            <html>
                <body>
                    <button onclick="window.webkit.messageHandlers.buttonClicked.postMessage(null)">Click Me!</button>
                </body>
            </html>
        """
        webView.loadHTMLString(htmlString, baseURL: nil)
    }

    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if message.name == "buttonClicked" {
            print("Webページのボタンがクリックされました。")
        }
    }
}

このコードでは、初めにWKUserContentControllerを設定しています。

そして、add(self, name: "buttonClicked")で、SwiftのコードとWebページ内のJavaScriptを連携させる設定を行っています。

Webページ内のボタンがクリックされると、window.webkit.messageHandlers.buttonClicked.postMessage(null)が実行され、Swift側のuserContentControllerメソッドが呼び出されます。

このコードを実行すると、表示されるWebページのボタンをクリックすると、コンソールに「Webページのボタンがクリックされました。」と表示されます。

●WKWebViewのカスタマイズ方法

WKWebViewを利用すると、単にWebページを表示するだけでなく、多くのカスタマイズが可能となります。

アプリケーションに組み込むことで、ユーザー体験を向上させるための様々な機能やデザインの調整が行えます。

○サンプルコード5:ナビゲーションバーのカスタマイズ

このコードではWKWebView上にナビゲーションバーを追加し、そのデザインや動作をカスタマイズするコードを表しています。

この例では、ナビゲーションバーに戻るボタンと進むボタンを追加し、それぞれのボタンの挙動をカスタマイズしています。

import UIKit
import WebKit

class ViewController: UIViewController, WKNavigationDelegate {
    var webView: WKWebView!

    override func loadView() {
        webView = WKWebView()
        webView.navigationDelegate = self
        view = webView
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // ナビゲーションバーのボタンの設定
        let backButton = UIBarButtonItem(title: "戻る", style: .plain, target: self, action: #selector(backButtonTapped))
        let forwardButton = UIBarButtonItem(title: "進む", style: .plain, target: self, action: #selector(forwardButtonTapped))

        navigationItem.leftBarButtonItems = [backButton, forwardButton]

        // URLのロード
        let url = URL(string: "https://www.example.com")!
        webView.load(URLRequest(url: url))
    }

    // 戻るボタンの動作
    @objc func backButtonTapped() {
        webView.goBack()
    }

    // 進むボタンの動作
    @objc func forwardButtonTapped() {
        webView.goForward()
    }
}

上記のコードを実行すると、WKWebView上でWebページが表示され、上部に「戻る」と「進む」というボタンが配置されたナビゲーションバーが表示されます。

それぞれのボタンを押すと、WebView内のページ履歴を基に前後のページに移動します。

○サンプルコード6:表示ページのカスタマイズ

このコードではWKWebView内で表示するWebページのコンテンツをカスタマイズするコードを表しています。

この例では、特定の要素の背景色を変更するJavaScriptを実行してページの見た目を変更しています。

import UIKit
import WebKit

class ViewController: UIViewController, WKNavigationDelegate {
    var webView: WKWebView!

    override func loadView() {
        webView = WKWebView()
        webView.navigationDelegate = self
        view = webView
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // URLのロード
        let url = URL(string: "https://www.example.com")!
        webView.load(URLRequest(url: url))
    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        // JavaScriptの実行
        let script = "document.querySelector('body').style.backgroundColor = 'lightblue';"
        webView.evaluateJavaScript(script, completionHandler: nil)
    }
}

このコードを実行すると、指定されたURLのページがWKWebView上に表示されます。

ページのロードが完了すると、body要素の背景色が薄い青色に変わるのを確認できます。

●WKWebViewの応用例

WKWebViewは非常に柔軟で、多くの応用例が考えられます。

ここでは、WKWebViewをより高度に活用するための方法をいくつか取り上げ、サンプルコードとともに説明していきます。

○サンプルコード7:ローカルのHTMLファイルを読み込む

多くのアプリケーションでは、ローカルに保存されているHTMLファイルをWebViewで表示したい場合があります。

WKWebViewを使用すると、このようなローカルファイルの読み込みも簡単に行うことができます。

このコードでは、ローカルのHTMLファイルを読み込んで表示しています。

この例では、Bundleを使ってアプリケーションのリソースからHTMLファイルのパスを取得し、それをWKWebViewで読み込んでいます。

import UIKit
import WebKit

class ViewController: UIViewController {
    var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        webView = WKWebView(frame: self.view.frame)
        self.view.addSubview(webView)

        if let path = Bundle.main.path(forResource: "sample", ofType: "html") {
            let url = URL(fileURLWithPath: path)
            let request = URLRequest(url: url)
            webView.load(request)
        }
    }
}

このコードを実行すると、sample.htmlという名前のローカルHTMLファイルがWKWebView上で表示されます。

ただし、sample.htmlはプロジェクトのリソースとして追加されている必要があります。

○サンプルコード8:ユーザーエージェントの変更

ユーザーエージェントは、Webブラウザやその他のクライアントがサーバーに自身を識別するための文字列です。

WKWebViewを使用する際に、特定のサイトでの表示をカスタマイズするためにユーザーエージェントを変更したい場合があります。

このコードでは、WKWebViewのユーザーエージェントをカスタム値に設定する方法を表しています。

この例では、デフォルトのユーザーエージェントに任意の文字列を追加して設定しています。

import UIKit
import WebKit

class ViewController: UIViewController {
    var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let webConfiguration = WKWebViewConfiguration()
        webView = WKWebView(frame: self.view.frame, configuration: webConfiguration)
        self.view.addSubview(webView)

        webView.evaluateJavaScript("navigator.userAgent") { (result, error) in
            if let userAgent = result as? String {
                self.webView.customUserAgent = userAgent + " MyCustomAgent/1.0"
            }
        }
    }
}

このコードを実行すると、WKWebViewのユーザーエージェントがデフォルト値に「MyCustomAgent/1.0」を追加した形で変更されます。

○サンプルコード9:WKWebViewでのクッキー管理

Webページ間のセッション情報を維持するためには、クッキーの管理が不可欠です。

WKWebViewには、クッキーを操作するためのAPIが用意されています。

このコードでは、WKWebViewでのクッキーのセットと取得を行う方法を表しています。

この例では、クッキーの値を設定し、その後でその値を取得しています。

import UIKit
import WebKit

class ViewController: UIViewController {
    var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let webConfiguration = WKWebViewConfiguration()
        webView = WKWebView(frame: self.view.frame, configuration: webConfiguration)
        self.view.addSubview(webView)

        // クッキーの設定
        let cookie = HTTPCookie(properties: [
            .domain: "example.com",
            .path: "/",
            .name: "sampleCookie",
            .value: "sampleValue",
            .secure: "FALSE",
            .expires: Date().addingTimeInterval(3600)
        ])
        if let validCookie = cookie {
            webView.configuration.websiteDataStore.httpCookieStore.setCookie(validCookie)
        }

        // クッキーの取得
        webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in
            for cookie in cookies {
                if cookie.name == "sampleCookie" {
                    print("Found our cookie: \(cookie.value)")
                }
            }
        }
    }
}

このコードを実行すると、「sampleCookie」という名前のクッキーが設定され、その後そのクッキーの値がコンソールに出力されます。

上記の例では「example.com」というドメインのクッキーを設定していますが、適切なドメイン名に変更する必要があります。

●WKWebViewの注意点とその対処法

WKWebViewはiOSプラットフォームでWebコンテンツを表示するための非常に強力なコンポーネントですが、その利用にあたり注意しなければならないポイントがいくつか存在します。

今回は、それらの注意点と対処法を、実際のサンプルコードとともにご紹介いたします。

○メモリリークとの取り扱い

WKWebViewを使用する際の最も一般的な問題の1つがメモリリークです。

WKWebViewは内部で多数のリソースを管理しており、適切に解放しないとアプリケーションのパフォーマンスに影響を及ぼす可能性があります。

□サンプルコード1: WKWebViewのメモリリークの原因

import WebKit

class ViewController: UIViewController {
    var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()
        webView = WKWebView(frame: self.view.bounds)
        self.view.addSubview(webView)
    }
}

このコードでは、WKWebViewをViewControllerのプロパティとして保持しています。

しかし、ViewControllerが解放される際に、webViewも適切に解放される保証がありません。

□対処法

WKWebViewのインスタンスを適切に解放するためには、deinitメソッド内でwebViewの参照をnilにするか、またはweak参照を使用することを推奨します。

class ViewController: UIViewController {
    weak var webView: WKWebView?

    override func viewDidLoad() {
        super.viewDidLoad()
        let tempWebView = WKWebView(frame: self.view.bounds)
        self.view.addSubview(tempWebView)
        webView = tempWebView
    }

    deinit {
        webView = nil
    }
}

この例では、WKWebViewの参照をweakとして保持し、ViewControllerが解放される際にはwebViewも自動的にnilとなり、メモリリークが防止されます。

○セキュリティ上のリスク

WKWebViewを利用する際のもう一つの重要な注意点は、セキュリティ上のリスクです。

特に、不正なWebページからの攻撃を受ける可能性があります。

そのため、安全なコンテンツのみを表示すること、及びユーザーの情報を適切に保護することが不可欠です。

□サンプルコード2:不正なURLのロード

import WebKit

class ViewController: UIViewController {
    var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()
        webView = WKWebView(frame: self.view.bounds)
        self.view.addSubview(webView)
        let url = URL(string: "http://不正なURL.com")
        webView.load(URLRequest(url: url!))
    }
}

このコードでは、不正なURLからのコンテンツをロードしてしまっています。

□対処法

不正なURLのコンテンツを表示しないためには、WKNavigationDelegateのメソッドを利用して、ロードするURLをチェックすることが推奨されます。

import WebKit

class ViewController: UIViewController, WKNavigationDelegate {
    var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()
        webView = WKWebView(frame: self.view.bounds)
        self.view.addSubview(webView)
        webView.navigationDelegate = self
        let url = URL(string: "http://不正なURL.com")
        webView.load(URLRequest(url: url!))
    }

    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        if let host = navigationAction.request.url?.host, host.contains("不正なURL") {
            decisionHandler(.cancel)
        } else {
            decisionHandler(.allow)
        }
    }
}

この例では、ロードしようとしているURLが不正である場合に、そのロードをキャンセルしています。

●WKWebViewの拡張機能とプラグイン

WKWebViewは、Appleが提供するiOSやmacOSのアプリケーションにWebコンテンツを表示するためのビューコンポーネントです。

その基本的な機能としてWebページの表示やJavaScriptの実行などがありますが、それだけではありません。

WKWebViewは多くの拡張機能やプラグインを持っており、これらをうまく利用することでより高度なWebコンテンツの表示や操作が可能となります。

○サンプルコード10:拡張機能を利用した高度な設定

このコードでは、WKWebViewの拡張機能を利用して高度な設定を行う例を表しています。

具体的には、コンテンツのズーム機能を制御し、ユーザーがページを拡大・縮小することを禁止します。

この設定は特定のアプリケーションでページのデザインやレイアウトを保持するために有効です。

import UIKit
import WebKit

class ViewController: UIViewController, WKUIDelegate {
    var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let webConfiguration = WKWebViewConfiguration()

        // ズーム機能を無効にする
        webConfiguration.userContentController.addUserScript(
            WKUserScript(source: "var meta = document.createElement('meta'); meta.name = 'viewport'; meta.content = 'initial-scale=1.0, maximum-scale=1.0, user-scalable=no'; document.getElementsByTagName('head')[0].appendChild(meta);",
            injectionTime: .atDocumentEnd, forMainFrameOnly: true)
        )

        webView = WKWebView(frame: self.view.bounds, configuration: webConfiguration)
        webView.uiDelegate = self
        view.addSubview(webView)

        let myURL = URL(string: "https://www.example.com")
        let myRequest = URLRequest(url: myURL!)
        webView.load(myRequest)
    }
}

この例では、JavaScriptを用いてHTMLのヘッダに特定のmetaタグを追加することで、ズーム機能を制御しています。

WKWebViewのWKUserScriptを使うことで、ページの読み込みが終わった後に任意のJavaScriptを実行することができます。

ページが表示されると、上記の設定によりユーザーは画面をピンチイン・ピンチアウトしてもコンテンツの拡大・縮小ができなくなります。

このようにWKWebViewの拡張機能を活用することで、様々なカスタマイズや高度な設定が可能となります。

まとめ

WKWebViewは、Swiftを使用したiOSやmacOSのアプリケーションでWebコンテンツを表示する際の強力なツールです。

基本的な使い方から高度な拡張機能、プラグインの利用まで、その幅広い機能を活用することで、多様なWebコンテンツの表示や操作を実現することができます。

この記事を通じて、WKWebViewの基本的な概念や機能、そして拡張機能を利用した高度な設定方法についての理解を深めたことでしょう。

今後のアプリケーション開発において、WKWebViewを最大限に活用して、より質の高いWebコンテンツ表示を実現してください。