window.requestNative && requestNative(JSON.stringify(params)); 3 return; ifr = $('<iframe src="' + url + '"/>'); 6 $('body').append(ifr); 7 setTimeout(function () { 8 ifr.remove(); 9 ifr = null; 10 }, 1000)
优劣URL Schema与JavaScriptCore的优劣不好说,还是看具体使用场景吧,不考虑参数问题的话,真正有使用经验的朋友可能会发现url schema方案可能更加适用,因为:
URL Schema方案是监控Webview请求,所以比较通用;而JavaScriptCore的注入是在Webview加载时候注入。
如果页面刷新,这个注入也就丢了需要做特殊处理(糯米接入一个常见BUG就是糯米容器提供的方法不执行)
使用JavaScriptCore的话,页面刷新会导致Hybrid项目瘫痪的问题,我们IOS同事首先调整了注入方法的时间点,放到了webViewDidFinishLoad中,因为webViewDidFinishLoad的注入在页面js声明之后,所以如果一来就有Hybrid的交互便不会执行,比如:
Hybrid.ui.header.set({ 3 title: '设置右边按钮', 4 });
所以我与Native约定在webViewDidFinishLoad后执行一个我定义的方法,我们将页面初始化逻辑放到这个事件里面,比如:
1 Hybrid.ready = function() { 2 hybridInit(); 3 }
对比这个方法与之前jQuery的dom ready有点类似,我们可能会担心这样会影响页面的渲染速度,这里特别做了一个测试,这段代码对真实逻辑执行确实有一定影响,首次启动在30-90ms之间,第二次没什么影响了,这里也形成了一个一个优化点,只将那种页面一加载结束就需要执行的逻辑放入其中,影响主页面的逻辑可优先执行,如果觉得麻烦便直接将页面的载入放到这个方法中即可。
选择建议根据我们的使用过程,发现JavaScriptCore还是不好用,因为对Native的不熟悉,在js方法注入的时间点一块我们踩了一些坑,我们想在webViewDidFinishLoad中注入方法,但是发现有一定几率是页面js已经执行完了才注入,导致Hybrid交互失效。
而且我们对Native一块声明js方法的生命周期与垃圾回收一块也不熟悉,总担心埋下什么坑,加之之前30-90ms的延迟,我们最终是实现了两套方案:
一般情况下仍旧使用URL Schema,如果有不满足的场景,我们会使用JavaScriptCore,因为底层架构搭建不能耗费太多时间,所以对JavaScriptCore的研究便暂时到此,后续有时间需要对他做深入研究。
Hybrid版本APP会有版本号概念,每个版本会加一些新的特性或者会改一些BUG,一般的版本号是1.0.0,如果改了BUG打了补丁是1.0.1,有新特性就是1.1.0,如果有大改变的话就2.0.0咯,我们在实际业务代码中可能会有用到版本号的地方,所以Native需要将当前版本号告诉我们,一般是采用Native篡改navigator.userAgent写入特殊标志实现,我们这里是写入了这种标识:
xxx hybrid_1.0.0 xxx
然后我们会在全局释放一个工具类方法获取当前版本号:
1 var getHybridInfo = function () { 2 var platform_version = {}; 3 var na = navigator.userAgent; 4 na = na.toLowerCase(); 5 var info = na.match(/hybrid_\d\.\d\.\d/); 6 if (info && info[0]) { 7 info = info[0].split('_'); 8 if (info && info.length == 2) { 9 platform_version.platform = info[0]; 10 platform_version.version = info[1]; 11 } 12 } 13 return platform_version; 14 };
于是,我们在业务开发中便能知道当前是不是处于Native容器中,和获取版本号。
根据之前的共识,我们的代码只要运行在Native容器中就应该表现的像Hybrid,在浏览器中就应该表现的像H5
上面这句话可能很多朋友觉得有点奇怪,这里的界限在于有些方法H5提供了Native也提供了,究竟该用哪个的问题,比如获取当前位置信息,如果在Native容器中自然走Native获取,如果在浏览器中那就走H5接口。
交互格式约定做一件事情重中之重的就是基础约定,我们这里做Hybrid架构首先就要做好交互格式约定,这种格式约定的要灵活一点,这个将会在后续扩展中提现他的优势,我们这里依旧采用类似Ajax的交互规则:
请求格式1 requestHybrid({ tagname: 'hybridapi', param: {}, callback: function (data) { 8 } 9 });
tagname是标志这次请求的唯一标识,在接口比较多的情况有可能会有命名空间,比如:tagname: 'ns/api'。
回调格式回调的方式都是Native调用H5的js方法,前端需要告诉Native去哪个对象拿回调方法,另外前端需要与Native约定返回时所带的参数,我们是这样设计的:
{ data: {}, errno: 0, msg: "success" }
其中每个错误码需要详细的约定,比如:
{ data: {}, errno: 1, msg: "APP版本过低,请升级APP版本" }
但是真实业务调用的时候却不需要特别去处理响应数据,因为前端应该有统一的地方处理,到具体业务回调时应该只需要使用data数据即可。
调用方式的困惑一般来说,H5与Native通信都只会使用一个方法,我们之前是H5创建url schema,后面有有了新的方案,是Native释放一个requestNative给H5调用,这里就产生了一个之前没有的问题: