首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >小程序iOS客户端框架——控件事件逻辑框架与控件原生化(下)

小程序iOS客户端框架——控件事件逻辑框架与控件原生化(下)

作者头像
腾讯NEXT学位
发布2018-10-12 16:27:34
2.8K0
发布2018-10-12 16:27:34
举报
文章被收录于专栏:腾讯NEXT学位腾讯NEXT学位

小程序自发布以来,为开发者和用户提供了一种轻量级的App。作为一种不需要下载安装即可使用的应用,它实现了应用“触手可及”的梦想,用户扫一扫或者搜一下即可打开应用。小程序也体现了“用完即走”的理念,用户不用关心是否安装太多应用的问题。 微信客户端为小程序的运行提供了框架支持,如service运行环境、页面缓存机制以及控件原生化支持等,本文将对这些部分实现原理做一一介绍。

6. 原生控件的创建与交互机制

小程序内部提供了部分非H5实现的原生控件。原生控件可以提供H5控件无法实现的一些功能,原生控件的用户体验感受上也会更加流畅,另外,使用原生控件减少了Objective C代码与WebView通信的流程,降低了通信开销。

以画布为例,前端提供了wx-canvas控件给开发者,当开发者在页面中设置一个画布标签<canvascanvas-id="xxx" ></canvas>,并调用绘制接口时,前端SDK将会有如下JSAPI的调用流程: 

(图6. 画布控件原生化创建逻辑) 

如上图所示,wx-canvas控件初始化时,将会通过Webview SDK的封装调用,执行客户端提供的“组件API”:insertCanvas接口以及updateCanvas接口(可选),绘制时通过调用客户端的drawCanvas接口,将绘制命令传递给客户端,客户端解析drawCanvas接口所带的参数,获取绘制命令集,并使用了Quarz2D来进行图形绘制。

insertCanvas通知客户端,在当前WebView上插入一个画布控件,客户端根据传入的位置和宽高参数来决定插入控件的位置和大小;

当开发者改变了wx-canvas控件的位置大小时,通过updateCanvas接口通知客户端,客户端对原生控件frame位置大小属性做对应的修改;

页面离开时,removeCanvas接口的调用将画布控件从webview上移除。

除了画布以外,Video组件对AVPlayer进行了封装,利用系统组件功能提供了边下边播的功能,并定制了原生化全屏等更加友好的用户操作界面;Map组件对QQ地图组件的封装将QQ地图的丰富功能引入到小程序,让开发者具有更广阔的开发想象空间;输入控件分别引入了iOS原生的UITexField和UITextView,提供了HTML输入框无法满足的定制化输入键盘等功能。

为了提供更加灵活可控的控件功能,小程序还对H5中的Toast、Alert、Picker、ActionSheet等控件做了原生化。这些组件是采用“开发API”的方式提供给开发者。

7. 原生控件插入到网页DOM节点

控件原生化带来了更加流畅的原生化体验和更加丰富的控件功能,但是同时也带来了新的难题。如前所述,原生控件是插入到webview控件上(实际实现时是插入到WKWebView下的WKScrollView下),如图7,网页元素总是绘制在WKContentView控件上——WKContentView负责绘制网页中的全部HTML元素,视频控件插入后将覆盖网页中的所有HTML元素:

(图7. 原生控件插入到WKWebView后将覆盖控件树中的HTML节点)

如上图,插入的原生控件必然总是盖住网页(节点树中越靠下的节点,显示层级越高),这样就会导致:

1

如果开发者期望在原生控件上覆盖一些自定义HTML元素,将无法被支持到。

2

所有的H5弹出元素都会被原生控件遮挡,比如alert对话框。这一问题可以通过将H5的弹出组件都原生化得以解决,如上节提到的Toast、Alert、Picker、ActionSheet的原生化;

3

如果开发者在div滚动条中插入原生控件作为div的子节点,预期原生控件应该随着父节点div滚动条的滚动而移动,并且超出div区域的内容应该被裁掉,但是由于原生控件是直接插入到webview下,与div之间没有关联,所以不会跟随移动也不会被裁减,在表现上会出现与开发者预期不一致的情况,影响用户体验。

为了解决这一问题,客户端尝试对WKWebView解析HTML元素的原理进行分析,WKWebView在进行HTML解析时,会根据页面DOM元素在WKWebView控件下生成对应的iOS原生控件,通过分析,普通情况下生成的原生控件与HTML节点无对应关系,但是在某些特殊情况下,一些特殊DOM元素会在WebView的对应位置生成位置、大小完全一致的原生控件,如包含overflow属性的DIV标签,如下图所示:

(图8. WKWebView解析HTML在客户端生成对应的原生控件示例)

如上图所示,WKWebView将在解析HTML时将该标签位置生成一个对应的UIScrollView控件。利用这个属性,我们可以在开发者期望插入原生控件的位置,预生成一个包含overflow标签的DIV节点,然后在插入原生控件时,将原生控件插入到该标签对应的UIScrollView上,就可以做到“原生控件不遮挡HTML元素”。例如将一个视频播放器插入到DOM节点以后,节点树如下:

 (图9. 将视频控件插入到网页DOM节点后的节点树)

客户端采用的“原生控件插入到网页DOM节点”方案,具体实现原理如下:

a、WEB端预先在需要插入原生控件的预留位置插入一个具有overflow属性的DIV标签,并通过“组件API”insertContainer通知客户端该滚动条的位置、大小;

b、客户端根据insertContainer传入的位置和大小,在WKWebView下遍历找到这个DIV标签对应的UIScrollView(大小位置均一致),保存其对象指针,并分配一个id返回给WEB端;

c、当WEB端插入原生控件时,通过接口传入id通知客户端:该原生控件属于哪个div滚动条,客户端找到该滚动条对应的原生UIScrollView,并将控件插入到该UIScrollView下;

d、当页面的DOM元素发生变化时,需要通过updateContainer告诉客户端调整指定的原生控件的大小,客户端根据参数调整原生控件的大小(位置不需要调整,因为总是在相对于父控件的原点位置)。

插入DOM节点后原生控件事件处理。由于WKWebView会接管用户的所有操作事件,因此按照上述方案插入后,原生控件是无法响应用户事件的。因此需要对事件做特殊处理:通过重载WKWebView的hitTest方法,在该方法的处理逻辑中优先处理网页上的事件,如果网页未处理,再传递给原生控件。

8. 总结

微信客户端为小程序提供了整套运行环境:包括js脚本的运行时支持、小程序任务管理、service中的js脚本与webview之间的通信桥接机制,以及对复杂控件进行了原生化。从而为开发者及用户提供了良好的小程序体验。

--------------------------------------------------------------------------

原文作者:腾讯工程师王召伟。

来源:腾讯内部KM论坛。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-09-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯NEXT学位 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云开发 CloudBase
云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档