接上文:浅谈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项目结束后,应该会着力在这方面做研究,这里没实际经验就不多说了。
文中是我个人的一些开发经验,希望对各位有用,也希望各位多多支持讨论,指出文中不足以及提出您的一些建议。
设计类博客(还有最后一篇便完结)
ios博客(持续更新)
文中IOS代码由我现在的同事Nil()提供,感谢Nil对项目的支持。
之前Android代码由明月提供,后续明月也会持续支援我们Android的实现,感谢明月。
代码地址:https://github.com/yexiaochai/Hybrid
因为IOS不能扫码下载了,大家自己下载下来用模拟器看吧,下面开始今天的内容。
H5与Native通信 Url Schema根据之前的知识,H5与Native交互的桥梁为Webview,而“联系”的方式是以url schema的方式做的,在用户安装app后,app可以自定义url schema,并且把自定义的url注册在调度中心, 例如
事实上Native能捕捉webview发出的一切请求,所以就算这里不是这种协议,Native也能捕捉,这个协议的意义在于可以在浏览器中直接打开APP,相关文献为:
又到周末了,我们一起来研究【浏览器如何检测是否安装app】吧
这里盗用一张之前的交互模型图,确实懒得画新的了:
我们在H5获取Native方法时一般是会构造一个这样的请求,使用iframe发出(设置location会有多次请求覆盖的问题):
1 requestHybrid({ tagname: 'hybridapi', param: {}, callback: function (data) { 8 } 9 }); 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对象的:
ofType:]; 2 NSString *scriptString = [NSString stringWithContentsOfFile:scriptPath encoding:NSUTF8StringEncoding error:nil]; 3 4 JSContext *context = [[JSContext alloc] init]; 5 [context evaluateScript:scriptString]; 6 ] = ^(NSString *text) { , text}; ]; 12 [function callWithArguments:@[]];
这个样子,JavaScript就可以调用Native的方法了,这里Native需要注意方法注入的时机,一般是一旦载入页面便需要载入变量,这里的交互模型是:
于是,我们这里只需要将原来底层的通信一块改下即可(Android本身就支持类似的实现,这里暂时不予关注):