浅谈Hybrid技术的设计与实现第第2章



前言

接上文:浅谈Hybrid技术的设计与实现(阅读本文前,建议阅读这个先)

上文说了很多关于Hybrid的概要设计,可以算得上大而全,有说明有demo有代码,对于想接触Hybrid的朋友来说应该有一定帮助,但是对于进阶的朋友可能就不太满足了,他们会想了解其中的每一个细节,甚至是一些Native的实现,小钗这里继续抛砖引玉,希望接下来的内容对各位有一定帮助。

进入今天的内容之前我们首先谈谈两个相关技术Ionic与React Native。

Ionic是一个基于Cordova的移动开发框架,他的一大优势是有一套配套的前端框架,因为是基于angularJS的,又提供了大量可用UI,可谓大而全,对开发效率很有帮助;与我们所说的Hybrid不同的是,我们的Native容器是由公司或者个人定制开发,Ionic的Native壳是第三方公司做的平台性产品,优劣不论,但是楼主是绝不会用太多第三方开源的东西的,举个例子来说,你的项目中如果第三方UI组件越多,那么性能和风险相对会越多,因为你不了解他。另一方面angular对于H5来说,尺寸着实过大,最后以逼格来说,Ionic还是多适用于外包了。

与Ionic不同的是React Native,根据他写出来的View完全是Native的View,那么这个逼格和体验就高了,小钗在这次Hybrid项目结束后,应该会着力在这方面做研究,这里没实际经验就不多说了。

文中是我个人的一些开发经验,希望对各位有用,也希望各位多多支持讨论,指出文中不足以及提出您的一些建议

设计类博客(还有最后一篇便完结)

http://www.cnblogs.com/yexiaochai/p/4921635.html
http://www.cnblogs.com/yexiaochai/p/5524783.html

ios博客(持续更新)

http://www.cnblogs.com/nildog/p/5536081.html#3440931

文中IOS代码由我现在的同事Nil(http://www.cnblogs.com/nildog/p/5536081.html)提供,感谢Nil对项目的支持。

之前Android代码由明月提供,后续明月也会持续支援我们Android的实现,感谢明月。

代码地址:https://github.com/yexiaochai/Hybrid

因为IOS不能扫码下载了,大家自己下载下来用模拟器看吧,下面开始今天的内容。

H5与Native通信

Url Schema

根据之前的知识,H5与Native交互的桥梁为Webview,而“联系”的方式是以url schema的方式做的,在用户安装app后,app可以自定义url schema,并且把自定义的url注册在调度中心, 例如

  • ctrip://wireless 打开携程App
  • weixin:// 打开微信

事实上Native能捕捉webview发出的一切请求,所以就算这里不是这种协议,Native也能捕捉,这个协议的意义在于可以在浏览器中直接打开APP,相关文献为:

又到周末了,我们一起来研究【浏览器如何检测是否安装app】吧

这里盗用一张之前的交互模型图,确实懒得画新的了:

 

浅谈Hybrid技术的设计与实现第第2章_第1张图片

我们在H5获取Native方法时一般是会构造一个这样的请求,使用iframe发出(设置location会有多次请求覆盖的问题):

复制代码
 1 requestHybrid({
 2   //创建一个新的webview对话框窗口
 3   tagname: 'hybridapi',
 4   //请求参数,会被Native使用
 5   param: {},
 6   //Native处理成功后回调前端的方法
 7   callback: function (data) {
 8   }
 9 });
10 //=====>
11 hybridschema://hybridapi?callback=hybrid_1446276509894¶m=%7B%22data1%22%3A1%2C%22data2%22%3A2%7D
复制代码

多数情况下这种方式没有问题,但是我们在后续的开发中,为了统一鉴权,将所有的请求全部代理到了Native发出,比如这样:

复制代码
 1 requestHybrid({
 2     tagname: 'post',
 3     param: {
 4         url: 'http://api.kuai.baidu.com/city/getstartcitys',
 5         param1: 'param1',
 6         param2: 'param2'
 7     },
 8     callback: function(data) {
 9     }
10 });
复制代码

请注意,这里可是POST请求,这里首先考虑的是长度限制,毕竟这个是由iframe的src设置的,虽然各个浏览器不一样,但必定会收到长度限制(2k),针对这个问题我咨询了糯米以及携程的Hybrid底层团队,得到了比较零星的回答:

① 移动端一般来说不会有这么长的请求(这个在理)

② 我们不支持IOS6了,现在用的JavaScriptCore

上面的答复不太满意,于是我尝试在页面上放一个全局变量(或者文本框)以解决参数过大的问题,而当我尝试解决的时候,产品告诉我:我们早不支持IOS6了

如果只用支持chrome用户,那么坚决不支持IE的!抱着这一想法,小钗也就放弃IOS6了

如果不支持IOS6,那么事情似乎变得好办多了。

JavaScriptCore

在ios7后,Apple新增了一个JavaScriptCore让Native可以与H5更好的交互(Android早就有了),我们这里主要讨论js如何与Native通信,这里举一个简单的例子:

PS:楼主对ios不熟,这段代码引至https://hjgitbook.gitbooks.io/ios/content/04-technical-research/04-javascriptcore-note.html

① 首先定义一个js方法,这里注意其中调用了一个没有声明的方法:

function printHello() {
    //未声明方法
    print("Hello, World!");
}

然后,上述未声明方法事实上是Native注入给window对象的:

复制代码
 1 NSString *scriptPath = [[NSBundle mainBundle] pathForResource:@"hello" ofType:@"js"];
 2 NSString *scriptString = [NSString stringWithContentsOfFile:scriptPath encoding:NSUTF8StringEncoding error:nil];
 3 
 4 JSContext *context = [[JSContext alloc] init];
 5 [context evaluateScript:scriptString];
 6 
 7 self.context[@"print"] = ^(NSString *text) {
 8     NSLog(@"%@", text");
 9 };
10 
11 JSValue *function = self.context[@"printHello"];
12 [function callWithArguments:@[]];
复制代码

这个样子,JavaScript就可以调用Native的方法了,这里Native需要注意方法注入的时机,一般是一旦载入页面便需要载入变量,这里的交互模型是:

浅谈Hybrid技术的设计与实现第第2章_第2张图片

于是,我们这里只需要将原来底层的通信一块改下即可(Android本身就支持类似的实现,这里暂时不予关注):

复制代码
 1 //使用jsCore与native通信
 2 window.requestNative && requestNative(JSON.stringify(params));
 3 return;
 4 //兼容ios6
 5 var ifr = $('