iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 17
0
自我挑戰組

IOS app開發介紹系列 第 17

IOS app開發介紹 - 內嵌WebView(1) 載入網頁

有時候我們需要在app裡面內嵌一些網頁來達到方便跨平台的效果,不用分別刻Android和IOS app原生UI,今天先簡單介紹創一個WebView來內嵌一個網頁,以及利用WebView提供的Function來實現像瀏覽器一樣回到上一頁與到下一頁的功能


分為4個項目來介紹

1. 內嵌一個網頁
2. 設定WKNavigationDelegate
3. 實現回到上一頁與到下一頁的功能
4. Security導致無法載入網頁

1. 內嵌一個網頁

首先我們需要創一個WKWebView(iOS 8.0+),來呈現我們的網頁內容:

            mWebView = WKWebView(frame: self.view.frame)
            if let mWebView = mWebView {
                mWebView.navigationDelegate = self
                mWebView.load(request)
                self.view.addSubview(mWebView)
            }

第一行先指定我們的WkWebView的大小,接下來指定WKNavigationDelegate為目前的ViewContrller,
之後再載入我們希望的URL,並把我們創造出來的WkWebView加到目前的ViewContrller上.


2. 設定WKNavigationDelegate

載入網頁在正常情況下會成功,但總有某些狀況會導致失敗,這時候我們必須讓我們的ViewContrller去實作WKNavigationDelegate來接收成功或失敗的system callback,詳細程式碼如下:

extension WebViewController: WKNavigationDelegate {
    func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
        print(error.localizedDescription)
    }
    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        print("Strat to load")
    }
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        print("finish to load")
    }
}

didFailProvisionalNavigation這個system callback執行到的時候,表示我們載入網頁失敗,這時候我們應該跳出對話框提示使用者暫時離開畫面或是重新嘗試載入網頁.
didStartProvisionalNavigation這個system callback執行到的時候,表示我們載入網頁成功,網頁會慢慢顯示出來
didFinish這個system callback執行到的時候,表示我們網頁載入完成,此時應該能看到完整的網頁畫面

以下為完整的範例程式碼:

import UIKit
import WebKit
class WebViewController: UIViewController {
    var mWebView: WKWebView? = nil

    override func viewDidLoad() {
        super.viewDidLoad()
        let url = "https://www.google.com.tw/"
        loadURL(urlString: url)
        
    }
    
    private func loadURL(urlString: String) {
        let url = URL(string: urlString)
        if let url = url {
            let request = URLRequest(url: url)
            // init and load request in webview.
            mWebView = WKWebView(frame: self.view.frame)
            if let mWebView = mWebView {
                mWebView.navigationDelegate = self
                mWebView.load(request)
                self.view.addSubview(mWebView)
                self.view.sendSubviewToBack(mWebView)
            }
        }
    }
 
}


extension WebViewController: WKNavigationDelegate {
    func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
        print(error.localizedDescription)
    }
    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        print("Strat to load")
    }
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        print("finish to load")
    }
}

3. 實現回到上一頁與到下一頁的功能

IOS的WKWebView提供了兩個function goBack()goForward(),只要呼叫這兩個function,我們就能夠實現如同瀏覽器的回到上一頁與到下一頁的功能,為此我們新增了兩個button,並在這兩個button的@IBAction function內去加入以下的code:

    @IBAction func backAction(_ sender: UIButton) {
        if mWebView?.goBack() == nil {
            print("No more page to back")
        }

    }
    
    @IBAction func forwardAction(_ sender: UIButton) {
        if mWebView?.goForward() == nil {
            print("No more page to forward")
        }
    }

呼叫 goBack() 和 **goForward()**外,我們還加上了null的判斷,因為IOS很貼心的為我們處理當沒有上一頁可以回去及沒有下一頁可以去的狀況,當發生前述狀況時,就會回傳null.我們當然可以利用 goBack() 和 **goForward()**這兩個function是否回傳null來決定要enable或disable back button或forward button,但是因為WKWebView提供了兩個屬性 canGoForwardcanGoBack ,所以我們只要在每次載入新的網頁時(即 func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) 中),去加入以下判斷就好:

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        print("finish to load")
        if let webView = mWebView {
            mForwardBtn.isEnabled = webView.canGoForward
            mBackBtn.isEnabled = webView.canGoBack
        }
    }

這樣我們就能夠集中管理按鈕的enable或disalbe狀態,不用分散在兩個Action function裡面

4. Security導致無法載入網頁

你在點擊某些網頁連結的時候,有可能無法正常載入,有一種情況是因為 Security 的關係,你如果是在debug mode下,你會看到 didFailProvisionalNavigation 被執行到,且印出以下錯誤訊息:
The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.
官網的描述如下:
Starting in iOS 9.0 and macOS v10.11, App Transport Security (ATS) is enabled by default for connections created by URLSession. ATS requires the use of best practice secure protocols in HTTPS.
ref: https://developer.apple.com/documentation/foundation/urlerror/2865492-apptransportsecurityrequiressecu
簡單來說 iOS 9.0 和 macOS v10.11以後,所有的連線預設都要是 HTTPS 才行.可是還是有很多網頁不支援 HTTPS 連線,那怎麼辦呢? 我們可以在info.plist檔中去加入以下的key value來幫助我們解決這個問題.
https://ithelp.ithome.com.tw/upload/images/20181101/20111592iHUBhVgttn.png

更多關於App Transport Security的設定可參考以下連結:
https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW33


到這裡我們就知道如何在IOS中載入網頁與控制回到上一頁與到下一頁的操作,完整的專案放在以下連結裡:

https://github.com/tgnivekucn/WKWebView1


ref:
https://developer.apple.com/documentation/webkit/wkwebview


上一篇
IOS app開發介紹 - 編譯優化
下一篇
IOS app開發介紹 - 內嵌WebView (2) 與App互傳資訊
系列文
IOS app開發介紹22

尚未有邦友留言

立即登入留言