iOS-Swift快速进入Hybrid开发

前言:

Hybrid(混合)开发在现今的app开发中相当常见,本文的目的是从iOS端引导大家快速进入Hybrid开发。

正文:

首先,我们先来了解一下为什么混合开发是如此必要。无论是Android,还是iOS,如果你仅采用原生开发,那么你的每一次变动,都需要将应用打包后发给应用商店,等待审核成功后,用户安装了新版本才可以使用。这无疑是浪费了太多的时间。那么你自然会想到,把容易变化的页面放在html上,而将程序的固定模块用原生开发。也就是在客户端接入h5(即web前端,后文简称h5)的页面,完成我们所需的功能。

而由于h5的页面,不仅仅是展示功能,也包含用户的操作,因此还需要客户端与h5的互相调用,那么仅仅用webView显示,那是远远不够的。例如:h5页面需要上传相片,那么就需要客户端将相片传给h5。这里h5需要向客户端发送打开相机或相册的请求,客户端选中相片后,也需要向h5上传。那么,我们进入了今天的主题,Hybrid开发。

Hybrid开发的基础在于两点:

1:客户端对h5的调用

这里的关键方法只有一个

webView.evaluateJavaScript(javascriptString, completionHandler: nil)

其中webView是WKWebView的实例.
WKWebView是苹果在iOS 8之后推出的框架WebKit中的浏览器控件, 其加载速度比UIWebView快了许多, 但内存占用率却下降很多, 也解决了加载网页时的内存泄露问题. 现在的项目大多数只需适配到iOS 8, 所以用WKWebView来替换项目中的UIWebView是很有必要的.

evaluateJavaScript这个方法是向浏览器传递javaScript,其中参数javascriptString是JSON格式的字符串。
无论是向h5传递参数,还是调用方法,都要将执行的语句作为参数,并用WKWebView调用evaluateJavaScript来传递给h5。

2.h5调客户端的调用

关键方法也是只有一个

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {}

需要遵循WKScriptMessageHandler协议, 在本方法中获取h5端传递的事件和参数,接下来再调用客户端的原生方法。
其中事件和参数都包含再message参数的body属性里

3.实例演示

这里先给大家推荐一个第三方库AXWebViewController,该控制器自带WKWebView,并且对进度条等控件进行了封装,使用起来非常方便。只需要继承该控制器就可以了。

(1)首先引入AXWebViewController,然后新建一个控制器WebViewController并继承AXWebViewController,作为主控制器。

import AXWebViewController
class WebViewController: AXWebViewController {}

(2)为主控制器添加extension,遵循AXWebViewControllerDelegate

//MARK: -AXWebViewControllerDelegate
extension WebViewController: AXWebViewControllerDelegate {
    //开始加载
    func webViewControllerDidStartLoad(_ webViewController: AXWebViewController) {}
    //完成加载
    func webViewControllerDidFinishLoad(_ webViewController: AXWebViewController) {
        //DOM操作,对webView的基础设置
        //1.禁止用户选中文本
        webView.evaluateJavaScript("document.documetElement.style.webkitUserSelect='none';", completionHandler: nil)
        //2.禁止按住目标的手势
        webView.evaluateJavaScript("document.documentElement.style.webkitTouchCallout='none';", completionHandler: nil)
        //3.向h5注入所需要的数据,如:app版本号,token等
        self.invokeJavascript(method: "dataInit", data: ["token":token,"platform":"iOS","appVersion":sysManager.appVersion,"UUID":SysManager.main.uuid()])
    }
    //加载失败
    func webViewController(_ webViewController: AXWebViewController, didFailLoadWithError error: Error) {}
}

以上3个代理方法,分别对应webView的开始加载,完成加载和加载失败3种状态。
其中开始加载和加载失败两个代理方法里,我们根据自己的需求来实现。如加载失败,显示失败对应的页面等。
那么重点来看完成加载这个方法。在本方法中:
1,2分别是都是直接调用WKWebView的evaluateJavaScript方法,向h5注入语句达到1.禁止用户选中文本 2.禁止按住这个手势
3中所设置的是h5页面中的基础配置,其中调用了一个我们自己实现的方法,invokeJavascript,目的也是向h5传递javaScript。这里的方法dataInit和参数token,版本号等也都是和h5所约定好的。

func utimesInvokeJavascript(method:String, data:Any?) {
        do {
            let jsonData =  try JSONSerialization.data(withJSONObject: data!, options: [])
            let para = String(data: jsonData, encoding: .utf8)
            let javaScriptString =  "window.bridge.emit('"+method+"',"+para!+")"
            webView.evaluateJavaScript(javaScriptString, completionHandler: { (_, error) in})
        } catch {
            print(error)
        }
}

以上这个自定义的方法就是将参数和方法转化为JSON字符串,并传递给h5。其中的"window.bridge.emit('"+method+"',"+para!+")"也是和h5约定好的格式来接收。

之后每次想要向h5注入javaScript,也就是让h5响应客户端,我们都可以通过utimesInvokeJavascript来调用evaluateJavaScript.

(3)遵循WKScriptMessageHandler协议

//messageHanlderName为和h5约定好的通信名称
webView.configuration.userContentController.add(self, name: messageHandlerName)

实现协议方法

//MARK: -WKScriptMessageHandler
extension WebViewController: WKScriptMessageHandler {
    //负责接收h5对客户端原生方法的调用
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        let dictionary = message.body as! Dictionary
        let method = dictionary["method"] as? String
        let args = dictionary["args"] as? Dictionary
        self.reflectMethod(method:method, args: args)
    }
}

h5对客户端调用时,需要传递参数对象过来,就包含在message对象的body属性里。
这里面的method和args两个参数对应调用的方法和参数,也是h5和客户端所约定的方式
其中reflectMethod这个方法是自定义以响应h5对客户端的调用。

//响应javascript对原生方法的调用
    func reflectMethod(method:String?, args:Dictionary?) {
        if method == "goBack" {
            perform(#selector(back), with: args, afterDelay: 0.1)
        }
    }
    
    @objc func goBack() {
        navigationController?.popViewController(animated: true)
    }

例如我们定义了一个名为goBack的方法,那么h5只需按约定方式将goBack对应字符串放进method参数里再传递过来,我们就在识别后就可以响应此方法
(4)当h5页面加载出现异常可能会有以下情况

1.可能因为h5需要的参数未传递

//此方法属于AXWebViewControllerDelegate的代理方法
func webViewController(_ webViewController: AXWebViewController, didFailLoadWithError error: Error) {
        //对错误进行处理,如显示加载失败等
}

2.可能因内存过高而导致webView进程的结束,如多次上传图片

//此方法属于WKNavigationDelegate,因AXWebViewController遵循WKNavigationDelegate,因此可直接重写
override func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
        //可调用webView.reload()重新加载,或者返回上一页面
}

(5)当需要调用时,我们只需要实例化WebViewController就好了

let webController = WebViewController(address: urlString)   //urlString为html地址
navigationController?.pushViewController(vc, animated: true)

总结:

那么再来总结一下关键点:
1.创建控制器,继承于第三方控制器AXWebViewController
1.使用WKWebView,通过webView.evaluateJavaScript(javaScriptString, completionHandler: nil)向h5注入javascript,使h5端响应客户端要求;
2.遵循WKScriptMessageHandler,实现代理方法func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage){},使客户端响应h5端要求
3.在func webViewControllerDidFinishLoad(_ webViewController: AXWebViewController) {}在完成h5端需要的基本配置,如token,uuid等
4.javaScript的传递格式需要客户端和h5端共同约定

以上就是iOS端快速接入Hybrid的方法,喜欢的朋友点个赞吧~

你可能感兴趣的:(iOS-Swift快速进入Hybrid开发)