iOS內實現h5原生開發

jackyshan_發表於2019-01-09
301129-68cf18d5d54faf90.png

介紹

Xcode可以直接引入h5的介面,實現原生介面內嵌h5開發。其實這裡不止iOS可以這樣做,安卓也可以引用同樣的h5介面,實現介面使用同一份h5程式碼。

為什麼要寫h5的介面呢,原因是第一Xcode很卡,畫圖效果也不如h5方便。第二是除錯h5直接通過瀏覽器除錯就行了,不像Xcode每次編譯跑起來真是卡的一批,時間又長。
所以我就研究了這一套本地h5開發的邏輯,既能很好的實現業務邏輯的開發,又能方便開發,統一多端,效率大大提升。

步驟如下

301129-151e4006ead9d4c4.png

把目錄匯入到Xcode中,選擇Create folder references點選完成

301129-54e0530428f5fab8.png

引入h5目錄效果如上

下面從實現介面和實現邏輯兩個部分講解。

實現介面

301129-c0b4d0d620e9d21b.gif

上面是實現的h5介面,通過webview引入專案,可以看到效果和原生幾乎一樣。

當然需要達到和原生效果一樣,還要對h5的介面做一些配置。

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<meta name="format-detection" content="telephone=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black">

上面的配置規定了頁面的不能縮放,數字不會直接顯示號碼的樣式,還要狀態列的顯示顏色為黑色

/* 禁用長按 */
body {-webkit-touch-callout:none;/*系統預設選單被禁用*/-webkit-user-select:none;/*webkit瀏覽器*/-khtml-user-select:none;/*早起瀏覽器*/-moz-user-select:none;/*火狐瀏覽器*/-ms-user-select:none;/*IE瀏覽器*/user-select:none;/*使用者是否能夠選中文字*/}

html{
    font-family:PingFangSC-Regular;
}

上面是一些通用的css配置,我放到了style.css裡面,一是禁止使用者長按顯示放大顯示器的效果,二是統一使用蘋方字型。

有了以上配置,基本就可以好好實現介面的開發了,開發h5的流程沒有和正常h5開發沒有什麼流程。

iOS引入資源的方式如下

let configuration = WKWebViewConfiguration()
configuration.preferences = WKPreferences()
configuration.preferences.javaScriptEnabled = true
configuration.userContentController = WKUserContentController()

let webview = WKWebView.init(frame: self.view.bounds, configuration: configuration)
self.view.addSubview(webview)
webview.navigationDelegate = self
webview.load(URLRequest.init(url: URL.init(fileURLWithPath: Bundle.main.path(forResource: "licheng", ofType: "html", inDirectory: "h5")!)))

webview引入licheng.html,通過urlrequest請求資源,渲染到當前的webview介面上,由於是本地直接載入,不存在網路延遲的問題,所以載入速度很快,幾乎和原生介面一樣。

下面講講邏輯部分,比如網路,點選跳轉,傳值等。

實現邏輯

之前的部落格也有講過wkwebview混合開發,怎麼實現傳值的方式。主要過程就是實現js和原生互動,有了互動外加一層封裝,就可以方便的通過介面實現我們傳值功能。

301129-a9c5231609377c9e.gif

新增一個name的handler,h5可以通過傳送這個handler,呼叫原生的代理方法

func addJsFunc(_ name: String, _ callback:@escaping ((Any)->Void)) {
    wkconfiguration.userContentController.add(self, name: name)
    
    jsFuncArr.append(JsFuncModel.init(name: name, callback: callback))
}

h5傳送handler

window.webkit.messageHandlers.openvc.postMessage({name:'aa', sex:'male', age:21})

原生代理方法接收,匹配到相應的name,執行原生的callback

public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    
    print(message.name)
    print(message.body)
    
    for jsFunc in jsFuncArr {
        if jsFunc.name == message.name {
            jsFunc.callback(message.body)
            break
        }
    }
}

以上是新增一個handler的方式,可以使js呼叫原生並傳值。這樣就能實現介面之間的跳轉的action,以及js一些傳值動作的執行了。

下面實現原生傳值給js環境

func addJsObj(_ key: String, _ value: String) {
    wkwebview.evaluateJavaScript("vm.\(key) = \(value)", completionHandler: nil)
}

通過kv的方式設定vm的屬性值,vm是我們vue全域性環境的例項。我們的h5的元件是通過vue完成雙向繫結的,通過設定vm的屬性的值,
可以把data迅速的渲染到我們的頁面上。這裡引入vue這個框架的好處是,我們不用那麼頻繁的操作dom了,
有vue做mvvm的架構,介面的渲染真是比原生實現輕鬆太多了。

以上是原生通過evaluateJavaScript傳值給js環境,這樣就能實現在原生實現網路請求回來的資料,直接給到h5介面去渲染。或者原生的一些動作可以通知到h5去執行。

注意這裡網路請求是放在原生環境實現的,原因是瀏覽器和後臺部署都是不支援跨域訪問的,這個問題可以具體google。

通過上面的開發基本上可以實現h5的原生開發了,因為h5是打包到專案裡面的,所以效能很好。
我對這一套渲染和傳值的邏輯進行了封裝,放在了JWebViewController裡面,繼承該類就可以使用了。
程式碼參考iOSh5vue

注意事項

  • 頂層資料夾名字要命名為h5,因為JWebViewController底層封裝寫死了h5的目錄。

  • 在頁面返回時,要做合適的時機呼叫clearJs方法,這樣vc才會被析構。不然會出現記憶體洩露。

  • 相關邏輯都封裝在JWebViewController裡面了,需要繼承JWebViewController,實現業務邏輯的部分。

相關文章