写点什么

如何用游戏引擎改造 Hybrid App?

  • 2018-05-01
  • 本文字数:4105 字

    阅读完需:约 13 分钟

在移动设备上,Hybrid 混合开发的性能问题一直为人诟病,对它的各种优化、hack 层出不穷,但你听说过用游戏引擎来优化 Hybrid 性能的吗?这次我们的 GMTC 邀请到了腾讯高级工程师潘伟洲分享《基于 Cocos 的高性能跨平台应用开发方案》,我们提前对他进行了采访,了解了一些技术细节,分享给大家。

InfoQ:Cocos 作为开源的跨平台游戏引擎框架,是一个什么样的契机让你和你的团队想到了用 Cocos 来改造原本 Hybrid 形式的产品的?

潘伟洲:先从动力说起:ABCmouse 原来的版本出于跨平台的目的,项目的大部分采用的是 Hybrid 的形式,大部分的页面加载都非常耗时,以一个画图的功能为例,从打开到加载完成可能要耗费十几秒的时间,这对于大部分用户来说是难以忍受的。

通过初期技术预研后,我们决定使用 Cocos 来改造这个项目,主要出于以下几个考虑:

  1. 跨平台。Cocos 支持使用同一套代码构建生成 Web、iOS、Android 等几个端,最新的版本还支持发布到微信小游戏、Facebook Instant Games 和 QQ 玩一玩;
  2. 性能。Cocos 的原理是在 Activity 中绘制一个 OpenGL 的 SurfaceView ,并由其完成页面的渲染的。与基于 WebView 渲染的 Hybrid 应用相比,Cocos 的渲染速度更快,性能更好。
  3. 效率。借助可视化的 Cocos Creator 工具,界面的开发和资源的管理非常便捷,设计团队也可以参与进来设计界面和动效,提升开发效率。
  4. 表现力。ABCmouse 中包含了很多诸如游戏、画图、音乐等带游戏和娱乐性质的场景,而 Cocos 本身是为游戏开发设计的,更适合用在我们的产品中。

InfoQ:在实际开发过程当中,与其他跨平台的开发框架相比较,你觉得用 Cocos 的优势在哪里?

潘伟洲:首先是生成的平台更多,除了常见的 Web、iOS、Android 外,难得的还支持微信小游戏、Facebook Instant Games 和 QQ 玩一玩的发布。其次,因为 Cocos 的核心开发团队来自中国,能提供更好的技术支持。腾讯也是 Cocos 的合作伙伴,我们与他们建立了良好的合作关系。

InfoQ:使用 Cocos 开发,你们在技术选型,基础组件储备上做了哪些尝试与创新呢?

潘伟洲:技术选型方面,我们先是为 UI 层设计开发了一些 Cocos 所缺失的一些通用组件,包括:对话框、日期选择器、Toast、Loading 组件等,这些组件能在全部目标平台上通用,并且遵循着统一的接口风格,使得 UI 层的开发更加便利;

在图片加载方面,我们实现了一个带缓存功能的图片加载组件,优化二次加载在线图片的性能,并自动管理内存回收。另外, 为了提高图片的加载性能,我们改进了 Cocos 的图片的加载方式,让其支持使用 ETC2 纹理渲染,使得内存消耗降低了接近 70% 。

由于应用中有非常多的音乐、音效、语音,为了减小包大小,大部分的语音素材放在 CDN 上,需要的时候才从 CDN 上拉取播放。少部分常见的音效会直接打进应用包中。而 Cocos 自带的 AudioEngine 组件在 Native 端只支持本地资源的播放。因此,我们又封装了一个跨平台的音频播放器,可以自动根据指定的音频路径决定使用播放方式:

  • 对于 Web 端或者 Native 端的本地资源文件,直接使用 AudioEngine 来播放。
  • 对于 Native 端的远程音频,使用 Native 的播放器来播放。

由于对外的接口只有一套,开发者无需考虑具体的平台和底层播放器的选择。并且可以使用同样的接口来统一管理不同的音频。

由于客户端大部分的功能都是使用 JS 写的,为了更快速地定位问题,我们在底层对 JS Exception 做了拦截,一旦出现 JS Exception,就将错误信息通过 Toast 展示出来,并且详细的给出了堆栈信息和场景信息。这个错误展示帮助我们发现并修复了很多 JS 错误。

除了以上所提到的几个能力,我们在 Cocos 层还提供了通用的日志记录、事件上报等。这些在不同的端有不同的实现,但都通过 Cocos 层进行了适配,使得对开发者都是统一的一套接口。

InfoQ:在开发设计 ScrollView 控件时,你们做了哪些优化?

潘伟洲:官方 ScrollView 组件需要配合 layout 组件,当一次加载大量的子节点组件,或者分帧加载单个子节点组件时,初始化 ScrollView 节点视图会比较慢,在加载完成前存在拖动掉帧的问题。另外,一次性加载所有节点,也会导致内存资源的浪费。

我们对 ScrollView 进行了重写,基本的优化思路是:一次仅加载页面可容纳的少量数目子节点。并在滚动过程中,回收不可视的子节点组件并重用。

具体来说,ScrollView 大多数情况下表现为列表组件和宫格组件,以列表组件为例,可以根据子节点数目和子节点大小,计算出整个 ScrollView 内容的宽高,同时计算出屏幕可视区域最多可以容纳的子节点行数 rows,加载时仅加载 rows + 2 个子节点组件,其中添加的 2 个字节点组件作为滚动回收缓冲。举个具体点的例子,当手势向上,内容往下滚动时,一旦最上面一个子节点组件 A 不可视,就立马回收掉 A 并将其重用于将要渲染的子节点组件。

我们做过测试,我们有个页面加载了非常多的内容,在优化前,拖动的时候帧率可能会跌到 8 fps,而使用优化后的 ScrollView,帧率能够稳定在 60 fps。

InfoQ:在实际运用 Cocos 开发过程中,你们有踩过哪些坑呢?包大小的问题又是怎么解决的呢?

潘伟洲:我们遇到的第一个坑和 Cocos 的 VideoPlayer 组件有关:Cocos 的基本原理是在 Activity 里头展示一个 OpenGL 的 SurfaceView ,这个 SurfaceView 不能直接绘制视频。

为了解决视频的播放问题,Cocos 的引擎开发者们将视频播放器作为独立的一层 View ,并保持置顶。这带来的问题是:VideoPlayer 组件上无法绘制任何其他组件。比如,如果希望定制播放按钮、进度条等元素,使用 Cocos 的 VideoPlayer 是做不到的。

最终我们放弃了在 Cocos 层开发视频播放器的功能,而是在底层为各个端开发视频播放器,并各自实现界面的定制。

第二个坑是跨层调用的响应问题。Native 层和 Cocos 层交互时,存在一定的响应时间。

比如,前面说到,我们的视频播放器是在 Native 层开发的,我们有一个需求:当视频播放完后,立即跳转到另一个 Cocos 的场景。然而,由于跨层调用存在一定响应时间,当把视频播放器的 activity 关闭时,此时页面会回到调起视频播放器前的场景,然后才进入一个新的场景。

为了解决这个问题,我们在 Cocos 层设计了一个隐藏的常驻节点,在关闭 activity 前,先把这个节点设为可见,并将其颜色改为下一个场景的背景色,直到下一个场景加载完毕时才重新将该节点设为隐藏。由于设置节点的可见性远比加载场景要快,此时再关闭 activity 时,用户先看到的是这个节点,给用户一种即将进入下一个场景的错觉,就不会觉得场景的跳转很突兀。

最后我们遇到的一个比较严重的问题是 local reference table overflow error 问题。

为了复用 Native 端的能力,我们在 Cocos 层大量地使用反射机制来调用 Native 端提供的方法。然而,我们经常会遇到 local reference table overflow error 错误导致的界面卡死问题。最初,我们怀疑是反射调用使用得太频繁导致。因此,我们对诸如打 log、事件上报等 Native 方法进行了频率限制,例如使用缓冲的方法将多个 log 合并后再打印。

然而,虽然这个做法减少了界面卡死的发生,但依然没有彻底杜绝问题的再次出现,就像是一个定时炸弹一样,威胁着我们应用的稳定性。通过阅读引擎的代码,我们发现 Cocos 的引擎在反射阶段处理字符串参数时,使用了 NewStringUTF() 方法将其转换为 JNI 层的字符串,然而在调用执行完成后并没有相应地使用 DeleteLocalRef() 释放该字符串的引用,从而导致了引用表的溢出。了解到这个原因后,我们给 Cocos 的引擎提交了一个 pull request,修复了这个问题。

在包大小的控制方面,我们都知道图片资源往往是导致应用包臃肿的元凶。因此,为了减少包大小,我们应该能够找出工程里头的无用资源,以及可优化的资源。

针对无用资源,Cocos 建议将静态引用的图片存在 res 目录,而将动态引用的图片放在 resource 目录。这么区分的好处是,res 目录下的图片只有存在引用时才会被打包进应用,而没有被引用的图片则不会被打包进应用。

因此,我们首先编写了静态分析脚本,找出工程中不合理放置的图片资源(例如将静态引用的图片放置到 resource 目录的情况),并移除 resource 中没有使用的图片。另外,对于 res 目录,我们也会经常检查是否存在不必要的引用,比如移除废弃的场景或者节点等。

可以优化的资源指的是可以进一步压缩的资源,这个和原生应用的优化思路差不多。比如合理的使用有损压缩 / 无损压缩工具来压缩图片文件。对于不需要透明度的图片资源,则使用 JPEG 格式代替 PNG 格式。

另外,在实现一些动效时,我们也尽量使用属性动画而不是帧动画,以节省空间。在这一点上,Cocos 的优势比较明显。我们的动效通常是设计团队直接使用 Cocos Creator 的动画编辑器创建的动画剪辑,并非简单的帧动画。

InfoQ:在什么样的场景下,才适合做基于 Cocos 的产品开发呢?

潘伟洲:取决于产品的定位。Cocos 主要是为游戏开发设计的,所以产品的表现力更佳,但在性能、内存占用、耗电上不如普通原生应用。当你的产品要求有更高的表现力,UI 开发更灵活,并且希望能实现跨平台开发时,Cocos 是一个值得考虑的选择。

InfoQ:在众多的跨平台 app 开发框架当中,开发者如何找到适合自己的框架?

潘伟洲:建议结合产品的需求、定位、框架成熟度、社区支持情况等维度进行综合考量。

比如,如果你要开发一个视频播放器,那么像 Cocos 这种使用 OpenGL 绘制 UI 的框架就难以实现跨平台开发。而如果要开发一个高表现力的应用,比如内置小游戏或者是带翻书特效的阅读应用,那么就应该考虑 Cocos 这类支持 OpenGL 绘制的框架,或者与 H5 页面结合的 Hybrid 框架。

另外,如果产品对性能要求更高,那么应该选择更 “Native” 的框架,例如 React Native、Weex ,或者 Flutter 。而如果产品比较轻量,也更看重开发效率,那么可以选择 Hybrid 的框架。

除了从产品自身的需求定位出发,选择一个框架还应该考虑这个框架本身的成熟度以及社区支持情况。比如,Google 的 Flutter 是最近比较受关注的跨平台开发框架,它的亮点在于跨平台、高性能和不俗的表现力。然而这个框架目前还不够成熟,社区的轮子还不够丰富,能够得到的帮助也比较有限,所以建议现阶段可以保持关注,但小团队不要贸然去尝试。

感谢覃云对本文的审校。

2018-05-01 18:162800

评论

发布
暂无评论
发现更多内容

码住!8个小众宝藏的开发者学习类网站

伤感汤姆布利柏

学习 效率 低代码 低代码开发工具

cannot load "mso.dll" vs2008 web开发问题

GoodTime

web开发 VS2008

软件测试/测试开发|edge浏览器首页及新标签页设置

霍格沃兹测试开发学社

每日一题:LeetCode-152. 乘积最大子数组

Geek_4z9ami

面试 算法 LeetCode 动态规划 滚动数组

区块链背后的秘密:从交易看故事

Footprint Analytics

区块链

【直播预告】刘军博士:科学研究中的AI计算:何助力团队协作创新

九章云极DataCanvas

独立站新手教程引流篇:YouTube SEO优化指南!

九凌网络

软件测试/测试开发丨Python面向对象 学习笔记

测试人

Python 软件测试 测试开发

什么是意向锁?它和意向书有什么区别?

王磊

Java 面试

妨碍有效沟通的5种认知谬误

俞凡

沟通 思维模型 认知

外贸网站显示不安全警告怎么办?消除网站不安全警告超全指南

九凌网络

Eudic欧路词典 for mac(英语学习工具) v4.5.6完美激活版

mac

苹果mac Windows软件 英语学习软件 欧路词典 Eudic

AIBP,我的下一个职业规划

法老猫

AIGC LLMs AIBP

怎么在GridView中限制显示字数

GoodTime

C# asp.net GridView

软件测试/测试开发|IntelliJ IDEA安装与配置教程

霍格沃兹测试开发学社

妨碍做出正确决策的5种认知谬误

俞凡

思维模型 认知

【论文解读】模型即服务-介绍MaaS中所涉及的关键技术

合合技术团队

人工智能 大数据 合合信息 论文解读

购买体育赛事直播系统源码:如何找到靠谱一手源码,避免二道贩子源码

软件开发-梦幻运营部

字节跳动 MapReduce - Spark 平滑迁移实践

字节跳动云原生计算

大数据 spark 云原生

平凯数据库亮相 2023 信息技术应用创新论坛

PingCAP

数据库 信息化 TiDB

天猫店铺所有商品数据接口(Tmall.item_search_shop)

tbapi

天猫API接口 天猫商品数据接口 天猫店铺所有商品数据接口 天猫店铺商品接口

TiDB 入选 2023 年中国云原生数据库十大厂商推荐

PingCAP

数据库 云原生 TiDB 金融业

荣耀Magic6系列旗舰新品及MagicOS 8.0发布会

荣耀开发者服务平台

安全 UX 交互 人机协作 loT

干货满满!学习有限元分析软件Abaqus的几个必备理论

思茂信息

abaqus abaqus软件 abaqus有限元仿真 有限元分析

如何用游戏引擎改造Hybrid App?_语言 & 开发_胡骁杰_InfoQ精选文章