此文章曾發於 2022 年 IT 鐵人賽 - 使用 SwiftUI 讓有趣的點子變成 Apps

現代的 app,基本都會有和網路進行溝通的 feature。這一篇文章會讓 app 加上一頁 WebView,去連到葛麗絲.霍普的 wiki 頁面。這樣可以保證大家在讀取資料的時候,資訊是和 wiki 上的一樣,而不用在每次資訊有更新的時候,需要進行 client 端的更新。

葛麗絲.霍普的 wiki https://en.wikipedia.org/wiki/Grace_Hopper

SwiftUI 使用 WebView 的方法

目前 SwiftUI 沒有 WebView 元件,所以需要使用 WebKit 的 WKWebView。橋接 SwiftUI 和 UIKit 的方法很簡單,讓元件 conform UIViewRepresentable 後,實作 makeUIView(:), updateUIView(:,:)。就能使用 UIKit 的元件了。

在這個 WKWebViewContainer 裡面,我們會放一個 url: URL,讓裡面的 WKWebView,去讀這個 URLRequest。

import WebKit

struct WKWebViewContainer: UIViewRepresentable {
    
    var url: URL
    
    func makeUIView(context: Context) -> WKWebView {
        return WKWebView()
    }
    
    func updateUIView(_ webView: WKWebView, context: Context) {
        let request = URLRequest(url: url)
        webView.load(request)
    }
}

再把 WKWebViewContainer 包起來,這樣可以在上下左右加上其他 SwiftUI 元件。

struct MyWebView: View {
  
  let urlString: String
  
  var body: some View {
    
    if let url = URL(string: urlString) {
      WKWebViewContainer(url: url)
    } else {
      Text("not a url")
    }
  }
}

嗯…🤔🤔🤔🤔🤔 如果解不開,目前的程式碼是會呈現一個 Text,這樣有點怪怪,這邊加上一個 Error View 好了。

在 Image 上,可以直接使用 SF Symbole 的 wifi.exclamationmark,不用特別去找素材。

SF Symbols 的網站,這邊可以下載 SF Symbols 的 app。

https://developer.apple.com/sf-symbols/

// 如果 URLString 給錯,就會跳 Error view
struct URLNotCorrectView: View {
  
  var body: some View {
    
    VStack {
      Image(systemName: "wifi.exclamationmark")
        .font(.system(size: 150))
        .padding()
      Text("Oops! Internet got error")
        .bold()
        .multilineTextAlignment(.center)
        .font(.system(size: 44))
    }
  }
}

no internet view

最後, MyWebView 看起來就像這樣

struct MyWebView: View {
  
  let urlString: String
  
  var body: some View {
    
    if let url = URL(string: urlString) {
      WKWebViewContainer(url: url)
    } else {
      URLNotCorrectView()
    }
  }
}

不過, preview 是沒辦法看到網頁的,所以我們在進入點,把 View 換成 MyWebView,看一下結果。

import SwiftUI

@main
struct DemoApp: App {
    var body: some Scene {
        WindowGroup {
          MyWebView(urlString: "https://en.wikipedia.org/wiki/Grace_Hopper")
        }
    }
}

你也可以故意塞一個不是網址的 string,當無法轉換成 URL,就會出現前面寫好的網路故障 View。

展示 Grace Hopper 的 wiki

Wiki of Grace Hopper

Updated: