0%

【學習筆記】如何在 iOS APP 透過 WKWebView 實現內嵌網頁功能

Photo by Daniel Korpai on Unsplash

What is Webview?

Webview 其實就是一個精簡的瀏覽器,透過渲染引擎(Webkit)呈現網頁內容,中文又翻作「網頁視圖」。

和我們所熟悉的瀏覽器(例如:iOS / Safari 和 Android / Chrome)相比,最大差異在於,外觀介面沒有網址列、功能鍵等功能。

透過 Webview 實現的混合模式開發(Hyprid APP),相較於原生開發(Native APP),具備跨平台開發、開發效率高、降低成本、可離線執行等優點;然而,也須考量效能性、安全性與兼容性等問題。

iOS APP 顯示網頁的三種方式

iOS SDK 提供三種方式,讓開發者用來顯示網頁內容:

透過 UIApplication 外開網頁視窗

UIApplication.shared.open 是 Swift 中的一個 API,功能是可暫時離開當前 APP,開啟指定的 URL。

import SwiftUI
struct ContentView: View {
    
    var body: some View {
        Button(action: {
            let url = URL(string: "https://heidiliu2020.github.io/")!
            UIApplication.shared.open(url)
        }) {
            Text("點我前往連結")
        }
    }
}

WKWebView

和 Android 的 Webview 元件類似,iOS 同樣有 Webview 能用來顯示網頁內容。

而在 iOS 的 WebView 分為 UIWebView 和 iOS 8+ 新增的 WKWebView 兩種類型。

WebKit 框架中的 WKWebView 相較於前者,在於性能與穩定性的提升,具備 Nitro JavaScript 引擎的等優點。並透過 UIViewRepresentable 協定包裝 View,顯示特定的網頁內容。

import SwiftUI
import WebKit

struct WebView: UIViewRepresentable {
    
    func makeUIView(context: Context) -> some UIView {
        // return UIView object
    }
    
    func updateUIView(_ uiView: some UIView, context: Context) {
        // update UIView
    }
}

使用上需注意 WKWebView 沒有內建的 Back & Forward 按鍵,若需提供返回歷史頁面等功能,必須自行開發一個自訂的網頁瀏覽器。

SFSafariViewController

相較於 WKWebView 的限制,iOS 9 中導入的控制器 SFSafariViewController,能使用與 Safari 瀏覽器相同的功能,例如切換上下頁。

方法是透過 UIViewControllerRepresentable 協定定義 SwiftUI view 型別,將 SFSafariViewController 包裝成 SwiftUI view,即可顯示網頁內容。

import SwiftUI
import SafariServices

struct SafariView: UIViewControllerRepresentable {
    // TODO...
}

實戰練習

Step1. 環境架設:安裝 XCode

首先進入官網下載頁面,登入後選擇要下載 XCode 版本。

不同版本的 XCode,在使用上須考慮開發環境、APP 套件與 iOS 版本相容性,若需要安裝特定版本的 XCode,可參考這篇文章:如何手動快速下載不同版本的Xcode - Poy Chang

Step2. 建立新專案

運行 XCode 後,點擊「Create a new Xcode project」建立新專案。

接著點選 APP 建立專案範本,內建範本有預設程式碼,能夠協助快速開發:

Step3. 利用 UIViewRepresentable 協定調用 WKWebView

接著透過 UIViewRepresentable 協定包裝 View,顯示指定的網頁內容:

  • ContentView.swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        WebView(url: URL(string: "https://heidiliu2020.github.io/")!)
            .edgesIgnoringSafeArea(.all)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
  • SwiftUIView.swift
import SwiftUI
import WebKit

struct WebView: UIViewRepresentable {
    let url: URL

    func makeUIView(context: Context) -> WKWebView  {
        let wkwebView = WKWebView()
        wkwebView.load(URLRequest(url: url))
        return wkwebView
    }

    func updateUIView(_ uiView: WKWebView, context: Context) {
    }
}

Step4. Building and running an app

最後是運行 APP 驗證結果,點選上方的開始鍵執行 Building,點開右側的選單可選擇要運行的裝置版本,或是透過傳輸線連接在實體機上進行測試。

小結

同樣是因為專案上的測試需求,沒想到這回又再次把 Xcode 安裝回電腦中,也許因為過去曾稍微接觸過一點,這回相對沒那麼迷惘。

能夠直接把 APP Build 到實體手機測試,和透過 XCode 模擬器終究還是有很大區別,雖然要實際上架到 App Store 需要課金,但以現階段而言也已經很夠用了。回顧過去所接觸的知識,似乎明白儘管當初一知半解,只要再多經歷幾次也能夠好好運用這些技術了。

Reference

  • 使用 UIViewRepresentable 協定 讓你輕鬆建立 SwiftUI TextView
  • 利用 UIViewControllerRepresentable 協定 在 SwiftUI 存取相簿並使用相機