iOSHybird

Hybrid App的架构与实现

2016-09-08  本文已影响4643人  西山薄凉

公司想要将自己的产品由网页端移植到原生,提升用户体验,因此在网上查找相关资料。最后App决定使用Hybrid架构来实现快速上线。
第一次写文章,比较粗糙,诸位看官如果想更细致的了解HybridApp,请移步最下参考资料。
文章部分引用了相关资料的语句,在此感谢相关资料的作者。


伴随着移动互联网产业的兴起,各式App层出不穷,我们迫切需求一种更快速、成本更低、技术更为成熟的项目开发方案,而H5的成熟让我们看到了希望,使得Web App开始崛起。
为了提高用户体验,目前网站一般分为3个版本,简版、移动版、电脑版,简板Web普遍是基于WAP2.0开发的,界面视觉效果差、功能简单;移动版则普遍使用H5开发,适用于现在大家普遍使用的移动上网设备,拥有更好的视觉效果、交互方式,迥然不同于简板Web的设计风格;而电脑版在此则不做讨论。
个人认为现在的Web App就是由移动版网页发展而来。


目前App大致分为三个大类

三者之间的比较三者之间的比较

需要考虑的方面


Hybrid交互设计

UIWebView由于其API难用、还有内存泄漏,现在已经弃用,iOS8以上都应该尽量用新的WKWebview。WK提供了一系列API来使得Native与Web的信息交换简单高效。还有一个不可忽视的一点是WK使用与Safari相同的JS引擎+内置手势+无内存泄漏,是UIWebView的替代者。所以在这里UIWebView只做简要介绍。

    func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool{
             //如果请求协议是hello 这里的hello来自js的调用,在js中设为 document.location = "hello://你好";
             //scheme:hello ,msg:你好
             //通过url拦截的方式,作为对ios原生方法的呼叫
             if request.URL?.scheme == "hello"{
                 let method:String = request.URL?.scheme as String!
                 let sel =  Selector(method+":")
                 self.performSelector(sel, withObject:request.URL?.host)
                 request.URL?.path
                 //如果return true ,页面加载request,我们只是当做协议使用所以不能页面跳转
                 return false
             }
             return true
         }

函数回调/返回值
Native调JS可以有返回值,但是JS调Native是通过间接的拦截request方式实现,它根本就不算方法调用,所以应该是不存在可以直接产生返回值的。当然如果需要Native对JS的调用有所响应,可以通过回调函数的方式回应JS。可以在调用Native的时候增加一个JS回叫函数名 app在处理完之后调用回调函数并把需要的参数通过回调函数的方式进行传递。

    let source = "document.body.style.background = \"#777\";"
    let userScript = WKUserScript(source: source, injectionTime: .AtDocumentEnd, forMainFrameOnly: true)
 
     let userContentController = WKUserContentController()
     userContentController.addUserScript(userScript)
     let configuration = WKWebViewConfiguration()
     configuration.userContentController = userContentController
     self.webView = WKWebView(frame: self.view.bounds, configuration: configuration)

Native调JS方法

     //直接调用JS
      webView.evaluateJavaScript("hi()", completionHandler: nil)
         //调用JS带参数
         webView.evaluateJavaScript("hello('liuyanwei')", completionHandler: nil)
         //调用JS获取返回值
         webView.evaluateJavaScript("getName()") { (any,error) -> Void in
             NSLog("%@", any as! String)
         }
WK通过与UIWebView类似的方法调用JS语句,但获取返回值的方式不同,WKWebView用的是回调函数获取返回值。

**JS调Native方法**
Web中的信息也可以通过调用这个函数被传给Native里:
```
var message = {
                         'method' : 'hello',
                         'param1' : 'haibao',
                         };
window.webkit.messageHandlers.webViewApp.postMessage(message);
//这个 API 真正神奇的地方在于 JavaScript 对象可以自动转换为 Objective-C 或 Swift 对象。
//Native中Handler的注册handler需要在WKWebView初始化之前
config = WKWebViewConfiguration()
          //注册js方法
         config.userContentController.addScriptMessageHandler(self, name: "webViewApp")
         webView = WKWebView(frame: self.webWrap.frame, configuration: config)
//处理handler委托。ViewController实现WKScriptMessageHandler委托的func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage)方法
//实现WKScriptMessageHandler委托
      class ViewController:WKScriptMessageHandler
      //实现js调用ios的handle委托
      func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) {
          //接受传过来的消息从而决定app调用的方法
          let dict = message.body as! Dictionary<String,String>
          let method:String = dict["method"]!
          let param1:String = dict["param1"]!
          if method=="hello"{
              hello(param1)
          }
      }
```
**Alert拦截**
在WKWebview中,JS的Alert是不会出现任何内容的,你必须重写WKUIDelegate委托的runJavaScriptAlertPanelWithMessage message方法,自己处理Alert。类似的还有Confirm和Prompt也和Alert类似。
```
Alert拦截方法
func webView(webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: () -> Void) {
         completionHandler()
         let alert = UIAlertController(title: "ios-alert", message: "\(message)", preferredStyle: .Alert)
         alert.addAction(UIAlertAction(title: "ok", style: .Default, handler:nil))
         alert.addAction(UIAlertAction(title: "cancel", style: .Cancel, handler: nil))
         self.presentViewController(alert, animated: true, completion: nil)
     }
```

Native/Web端做好交互格式约定,Native端提供规范性的API供Web端访问。
常用API:
* 界面跳转(N->W/W->N/W->W/W->W新开WebView)+过场动画
* Header组件
* NativeUI相关组件(Loading遮罩等)
* 分享
* 推送
* 登录


框架架构

架构选择MVC,因为上层逻辑都是Web端实现的,对于Controller的负担不是太重。
框架结构为TabBar+Navi。
Web部分将入口界面的样式资源存放本地,后续跳转及动态数据通过网络获取。
下图是参考的Web目录结构图。


Hybrid目录结构图Hybrid目录结构图

数据请求

约定调用请求格式

let data = {url:'requestURL',
             param: {参数},
             type: 'post'
}

约定返回数据格式

let data = ["data": data,     //网络请求结果、本地数据等回传信息
          "errno": errno,   //错误码
            "msg": msg,       //描述
            "callback": callback]    //回调ID

Web端通过传递一个字典将需要的请求信息交给Native处理,Native处理完毕后数据通过Web端回调。

let dataString = self.toJSONString(data)
webView.stringByEvaluatingJavaScriptFromString(self.getRequest + "(\(dataString));")

本地数据访问

约定数据访问格式

let data = {name:'name',
            type:'dataType'
}

约定返回数据格式

let data = ["data": data,     //本地数据请求结果
          "errno": errno,     //错误码
            "msg": msg,       //描述
            "callback": callback]    //回调ID

参考资料:

聊聊Web App、Hybrid App与Native App的设计差异
Hybrid App开发实战
iOS 8 WebKit框架概览
浅谈Hybrid技术的设计与实现1
浅谈Hybrid技术的设计与实现2
去啊App实战:极致的Hybrid混合式开发
三层架构
UIWebView和WKWebView的使用及js交互
WKWeb View

上一篇下一篇

猜你喜欢

热点阅读