- 小程序同层渲染原理剖析
众所周知,小程序当中有一类特殊的内置组件——原生组件,这类组件有别于 WebView 渲染的内置组件,他们是交由原生客户端渲染的。原生组件作为 Webview 的补充,为小程序带来了更丰富的特性和更高的性能,但同时由于脱离 Webview 渲染也给开发者带来了不小的困扰。在小程序引入「同层渲染」之前,原生组件的层级总是最高,不受 [代码]z-index[代码] 属性的控制,无法与 [代码]view[代码]、[代码]image[代码] 等内置组件相互覆盖, [代码]cover-view[代码] 和 [代码]cover-image[代码] 组件的出现一定程度上缓解了覆盖的问题,同时为了让原生组件能被嵌套在 [代码]swiper[代码]、[代码]scroll-view[代码] 等容器内,小程序在过去也推出了一些临时的解决方案。但随着小程序生态的发展,开发者对原生组件的使用场景不断扩大,原生组件的这些问题也日趋显现,为了彻底解决原生组件带来的种种限制,我们对小程序原生组件进行了一次重构,引入了「同层渲染」。 相信已经有不少开发者已经在日常的小程序开发中使用了「同层渲染」的原生组件,那么究竟什么是「同层渲染」?它背后的实现原理是怎样的?它是解决原生组件限制的银弹吗?本文将会为你一一解答这些问题。 什么是「同层渲染」? 首先我们先来了解一下小程序原生组件的渲染原理。我们知道,小程序的内容大多是渲染在 WebView 上的,如果把 WebView 看成单独的一层,那么由系统自带的这些原生组件则位于另一个更高的层级。两个层级是完全独立的,因此无法简单地通过使用 [代码]z-index[代码] 控制原生组件和非原生组件之间的相对层级。正如下图所示,非原生组件位于 WebView 层,而原生组件及 [代码]cover-view[代码] 与 [代码]cover-image[代码] 则位于另一个较高的层级: [图片] 那么「同层渲染」顾名思义则是指通过一定的技术手段把原生组件直接渲染到 WebView 层级上,此时「原生组件层」已经不存在,原生组件此时已被直接挂载到 WebView 节点上。你几乎可以像使用非原生组件一样去使用「同层渲染」的原生组件,比如使用 [代码]view[代码]、[代码]image[代码] 覆盖原生组件、使用 [代码]z-index[代码] 指定原生组件的层级、把原生组件放置在 [代码]scroll-view[代码]、[代码]swiper[代码]、[代码]movable-view[代码] 等容器内,通过 [代码]WXSS[代码] 设置原生组件的样式等等。启用「同层渲染」之后的界面层级如下图所示: [图片] 「同层渲染」原理 你一定也想知道「同层渲染」背后究竟采用了什么技术。只有真正理解了「同层渲染」背后的机制,才能更高效地使用好这项能力。实际上,小程序的同层渲染在 iOS 和 Android 平台下的实现不同,因此下面分成两部分来分别介绍两个平台的实现方案。 iOS 端 小程序在 iOS 端使用 WKWebView 进行渲染的,WKWebView 在内部采用的是分层的方式进行渲染,它会将 WebKit 内核生成的 Compositing Layer(合成层)渲染成 iOS 上的一个 WKCompositingView,这是一个客户端原生的 View,不过可惜的是,内核一般会将多个 DOM 节点渲染到一个 Compositing Layer 上,因此合成层与 DOM 节点之间不存在一对一的映射关系。不过我们发现,当把一个 DOM 节点的 CSS 属性设置为 [代码]overflow: scroll[代码] (低版本需同时设置 [代码]-webkit-overflow-scrolling: touch[代码])之后,WKWebView 会为其生成一个 [代码]WKChildScrollView[代码],与 DOM 节点存在映射关系,这是一个原生的 [代码]UIScrollView[代码] 的子类,也就是说 WebView 里的滚动实际上是由真正的原生滚动组件来承载的。WKWebView 这么做是为了可以让 iOS 上的 WebView 滚动有更流畅的体验。虽说 [代码]WKChildScrollView[代码] 也是原生组件,但 WebKit 内核已经处理了它与其他 DOM 节点之间的层级关系,因此你可以直接使用 WXSS 控制层级而不必担心遮挡的问题。 小程序 iOS 端的「同层渲染」也正是基于 [代码]WKChildScrollView[代码] 实现的,原生组件在 attached 之后会直接挂载到预先创建好的 [代码]WKChildScrollView[代码] 容器下,大致的流程如下: 创建一个 DOM 节点并设置其 CSS 属性为 [代码]overflow: scroll[代码] 且 [代码]-webkit-overflow-scrolling: touch[代码]; 通知客户端查找到该 DOM 节点对应的原生 [代码]WKChildScrollView[代码] 组件; 将原生组件挂载到该 [代码]WKChildScrollView[代码] 节点上作为其子 View。 [图片] 通过上述流程,小程序的原生组件就被插入到 [代码]WKChildScrollView[代码] 了,也即是在 [代码]步骤1[代码] 创建的那个 DOM 节点对应的原生 ScrollView 的子节点。此时,修改这个 DOM 节点的样式属性同样也会应用到原生组件上。因此,「同层渲染」的原生组件与普通的内置组件表现并无二致。 Android 端 小程序在 Android 端采用 chromium 作为 WebView 渲染层,与 iOS 不同的是,Android 端的 WebView 是单独进行渲染而不会在客户端生成类似 iOS 那样的 Compositing View (合成层),经渲染后的 WebView 是一个完整的视图,因此需要采用其他的方案来实现「同层渲染」。经过我们的调研发现,chromium 支持 WebPlugin 机制,WebPlugin 是浏览器内核的一个插件机制,主要用来解析和描述embed 标签。Android 端的同层渲染就是基于 [代码]embed[代码] 标签结合 chromium 内核扩展来实现的。 [图片] Android 端「同层渲染」的大致流程如下: WebView 侧创建一个 [代码]embed[代码] DOM 节点并指定组件类型; chromium 内核会创建一个 [代码]WebPlugin[代码] 实例,并生成一个 [代码]RenderLayer[代码]; Android 客户端初始化一个对应的原生组件; Android 客户端将原生组件的画面绘制到步骤2创建的 [代码]RenderLayer[代码] 所绑定的 [代码]SurfaceTexture[代码] 上; 通知 chromium 内核渲染该 [代码]RenderLayer[代码]; chromium 渲染该 [代码]embed[代码] 节点并上屏。 [图片] 这样就实现了把一个原生组件渲染到 WebView 上,这个流程相当于给 WebView 添加了一个外置的插件,如果你有留意 Chrome 浏览器上的 pdf 预览,会发现实际上它也是基于 [代码]<embed />[代码] 标签实现的。 这种方式可以用于 map、video、canvas、camera 等原生组件的渲染,对于 input 和 textarea,采用的方案是直接对 chromium 的组件进行扩展,来支持一些 WebView 本身不具备的能力。 对比 iOS 端的实现,Android 端的「同层渲染」真正将原生组件视图加到了 WebView 的渲染流程中且 embed 节点是真正的 DOM 节点,理论上可以将任意 WXSS 属性作用在该节点上。Android 端相对来说是更加彻底的「同层渲染」,但相应的重构成本也会更高一些。 「同层渲染」 Tips 通过上文我们已经了解了「同层渲染」在 iOS 和 Android 端的实现原理。Android 端的「同层渲染」是基于 chromium 内核开发的扩展,可以看成是 webview 的一项能力,而 iOS 端则需要在使用过程中稍加注意。以下列出了若干注意事项,可以帮助你避免踩坑: Tips 1. 不是所有情况均会启用「同层渲染」 需要注意的是,原生组件的「同层渲染」能力可能会在特定情况下失效,一方面你需要在开发时稍加注意,另一方面同层渲染失败会触发 [代码]bindrendererror[代码] 事件,可在必要时根据该回调做好 UI 的 fallback。根据我们的统计,目前同层失败率很低,也不需要太过于担心。 对 Android 端来说,如果用户的设备没有微信自研的 [代码]chromium[代码] 内核,则会无法切换至「同层渲染」,此时会在组件初始化阶段触发 [代码]bindrendererror[代码]。而 iOS 端的情况会稍复杂一些:如果在基础库创建同层节点时,节点发生了 WXSS 变化从而引起 WebKit 内核重排,此时可能会出现同层失败的现象。解决方法:应尽量避免在原生组件上频繁修改节点的 WXSS 属性,尤其要尽量避免修改节点的 [代码]position[代码] 属性。如需对原生组件进行变换,强烈推荐使用 [代码]transform[代码] 而非修改节点的 [代码]position[代码] 属性。 Tips 2. iOS 「同层渲染」与 WebView 渲染稍有区别 上文我们已经了解了 iOS 端同层渲染的原理,实际上,WebKit 内核并不感知原生组件的存在,因此并非所有的 WXSS 属性都可以在原生组件上生效。一般来说,定位 (position / margin / padding) 、尺寸 (width / height) 、transform (scale / rotate / translate) 以及层级 (z-index) 相关的属性均可生效,在原生组件外部的属性 (如 shadow、border) 一般也会生效。但如需对组件做裁剪则可能会失败,例如:[代码]border-radius[代码] 属性应用在父节点不会产生圆角效果。 Tips 3. 「同层渲染」的事件机制 启用了「同层渲染」之后的原生组件相比于之前的区别是原生组件上的事件也会冒泡,意味着,一个原生组件或原生组件的子节点上的事件也会冒泡到其父节点上并触发父节点的事件监听,通常可以使用 [代码]catch[代码] 来阻止原生组件的事件冒泡。 Tips 4. 只有子节点才会进入全屏 有别于非同层渲染的原生组件,像 [代码]video[代码] 和 [代码]live-player[代码] 这类组件进入全屏时,只有其子节点会被显示。 [图片] 总结 阅读本文之后,相信你已经对小程序原生组件的「同层渲染」有了更深入的理解。同层渲染不仅解决了原生组件的层级问题,同时也让原生组件有了更丰富的展示和交互的能力。下表列出的原生组件都已经支持了「同层渲染」,其他组件( textarea、camera、webgl 及 input)也会在近期逐步上线。现在你就可以试试用「同层渲染」来优化你的小程序了。 支持同层渲染的原生组件 最低版本 video v2.4.0 map v2.7.0 canvas 2d(新接口) v2.9.0 live-player v2.9.1 live-pusher v2.9.1
2019-11-21 - 社区每周|Mac小程序公测、模板消息调整、云开发等能力升级与社区每周反馈(12.30-01.03)
各位微信开发者: 以下是Mac 版小程序开发者公测、模板消息能力调整说明、云开发相关功能更新、“小程序助手”性能分析功能升级、商品数据接入(内测)及上周小程序相关能力更新及我们在社区收到的问题反馈、需求的处理进度,希望同大家一同打造小程序生态。 微信 Mac 版小程序开发者公测微信 Mac 版新版本中,支持打开聊天中分享的小程序,开发者可下载安装微信 Mac 版公测版本进行体验和适配。 最新版微信开发者工具新增支持在微信 Mac 版中预览小程序和进行真机调试,详情请查看《Mac小程序开发说明》。 微信 Mac 版公测版:点击下载微信开发者工具:点击下载 关于小程序模板消息能力调整说明原计划2020年1月10日下线小程序模板消息能力,由于部分开发者反馈尚未完全将模板消息切换为订阅消息,为降低业务影响,现做如下调整: 下调模板消息接口日调用额度,2020年1月10日起(含1月10日),未开通支付能力的帐号调至5万/日,已开通支付能力的帐号调至50万/日2020年1月10日24:00以后,新发布的小程序,只能使用订阅消息,在该时间点之前发布的小程序仍然可以使用模板消息。(回退的版本,按当前发布时间算)2020年4月10日24:00以后,所有版本的小程序都不能使用模板消息,请还未切换使用订阅消息的开发者,在此时间点前完成切换 周期性更新/数据预拉取支持从云开发环境中获取数据周期性更新能够在用户未打开小程序的情况下,也能从服务器提前拉取数据,当用户打开小程序时可以更快地渲染页面,减少用户等待时间,增强在弱网条件下的可用性。目前,系统已支持从云开发环境中获取数据,并将数据下载到本地。开发者可登录小程序 MP 管理后台,进入设置->开发设置->数据周期性更新中进行配置。详情功能介绍请参考文档《周期性更新》。 [图片] 同时,小程序·云开发还支持数据预拉取功能,详细功能介绍请参考文档《数据预拉取》 商品数据接入(内测)商品数据目前应用于微信扫一扫识物、小程序商品搜索和扫条码三个功能。这些功能可以很好的满足微信用户对商品的信息获取诉求,同时也能为商家小程序带来曝光流量和建立用户品牌认知的机会。 商品数据接入方式请阅读《商品数据接入文档(内测)》。 服务平台新增AI、安全、地图等多项能力服务平台新增AI人脸检测、信息安全检查、地理位置、音乐资源等多项接口能力,帮助小程序开发者降低开发门槛、快速接入服务。可点击前往了解能力详情 [图片] “小程序助手”性能分析功能升级为了帮助小程序开发者分析性能数据并优化小程序体验,“小程序助手”升级了性能分析功能,新增启动性能、运行性能和网络性能等方面的数据,支持开发者监控小程序的基本性能指标。 [图片] 扫描下方小程序码即可立即体验: [图片] 上周问题反馈和处理进度(12.30-01.03) 已修复的问题微信更新到7.0.10之后, 安卓 wx.hideLoading 失效的问题 查看详情 小程序不能发布的问题 查看详情 微信开放平台 第三方平台代公众号授权突发异常授权失败,返回 system_error的问题 查看详情 发送模板消息超出限制的问题 查看详情 页面未找到 4.4 根据 OpenID 列表群发卡券消息的问题 查看详情 微信公众平台重复提示登录超时的问题 查看详情 编译提示cloud init error: Error: errCode: -1的问题 查看详情 2020年第一个BUG,排行版BUG,显示0月的问题 查看详情 安全接口报错 VM22379:1 cloud init error: Error: errCode 的问题 查看详情 文章模块MD样式错乱、插入图片展示很小的问题 查看详情 下个基础库修复开发者工具地图 marker anchorX 报错的问题 查看详情 picker 未点击确认前 columnChange 不触发的问题 查看详情 修复中的问题今天的开发者工具有种sublime的感觉的问题 查看详情 社区小程序不能回答,且“写回答”三个字位置固定的问题 查看详情 开发工具RC V1.02.1912261 wx.showModal 在开发工具上单行显示的问题 查看详情 发送订阅消息报错的问题 查看详情 wx.navigateBackMiniProgram() 安卓无效的问题 查看详情 创建SocketTask连接,session过期并断网,重连后,框架自动关闭的问题 查看详情 input 密码类型与 text 类型的 input 框的问题 查看详情 微信浏览器 原生 select 标签 点击不唤起下拉框的问题 查看详情 "jsserverRoot": "jsserver/"无法上传 checkInteractive 的问题 查看详情 SocketTask.onMessage 出现以下报错的问题 查看详情 为什么OPPO 华为某些机型登录微信小游戏出现黑屏现象的问题 查看详情 textarea 组件在2.10.0出现不支持的情况,无法显示多行输入的问题 查看详情 wx.getLocation在微信开发者工具里面调用成功,但预览、真机测试调用的时候安卓返回fail 的问题 查看详情 所有安卓 version7.0.10 版本保存图报错的问题 查看详情 小游戏2.10.0 copyFile 接口的问题 查看详情 使用最新调试基础库2.10.0,地图Map组件加载报错的问题 查看详情 微信7.0.10版本部分机型 select 点不了的问题 查看详情 banner广告内存问题问题 查看详情 荣耀play 微信版本更新到7.0.10 发现下拉框无法选择 查看详情 虚拟支付midas.getBalance接口报错 查看详情 开发者工具基础库2.10.0版本地图markers,报错的问题 查看详情 小游戏编译的时候出现错误的问题 查看详情 layaair 网络加载资源的问题的问题 查看详情 需求反馈需求评估中微信开发者工具中公众号收藏的链接有一个备注的需求 查看详情 建议小程序加个配置文件,用户共享配置的需求 查看详情 蓝牙发送数据API增加参数的需求 查看详情 小程序公众平台-开发-错误查询结果里显示时分秒的需求 查看详情 微信团队 2020.01.10
2020-01-10