在这里 射灯 我们是 反应本机 ,这是Facebook的开放源代码框架,用于使用React构建本机移动应用程序。 反应本机使具有现代JavaScript经验的任何开发人员都能相对轻松地进入移动应用程序开发的范围,并以与构建React Web前端相同的声明式,可组合的,基于组件的方式构建跨平台移动应用程序。
因此,当客户与我们联系以构建包含大量功能(包括实时文本和图像聊天,视频流以及包含用户完成的闪存卡和测验的教育组件)的功能清单的Android应用程序时,很自然地,我们对实现的最初想法得到了利用反应本地。
即使我们正在构建仅针对Android的应用程序,但能够使用React Native的好处显而易见。
我们有很多功能要构建,而很少有时间来构建它们。我们需要以JavaScript的速度工作。我们需要在整个应用程序中无缝共享整个组件和业务逻辑块。我们需要利用许多 500,000个npm软件包 可用,因此我们可以专注于解决客户的问题,而不是重新发明轮子。我们需要脚手架,构建和快速迭代。
此外,JavaScript开发人员的数量比世界上(以及Postlight!)的Android开发人员多,因此我们知道,找到能够构建和维护应用程序的开发人员 交接后 会容易得多。
只有一个收获,一个需要进一步考虑的问题,另一个是“功能请求”:所有将使用此应用程序的人?他们住在印度。他们中的大多数使用通过慢速且不稳定的移动网络连接的廉价,低端Android设备。这意味着该应用程序必须精简且快速才能在速度较慢的硬件上工作,可以容忍网络不一致,并且在根本没有可用的网络时可以脱机工作。它不仅需要可用。这些限制是印度市场所特有的,并且需要执行 好 在目标市场中。
当面对这样的工程约束时,JavaScript成为一个臭名昭著的参与者。 的JavaScript具有当之无愧的声誉 不必要地使页面膨胀 和为 在Android设备上执行特别慢 ,而不用于启用关键性能的脱机优先本机应用程序。我们不确定低端Android设备是否具有执行像React Native这样的高级框架所需的硬件资源,更不用说我们是否可以在其之上构建性能。我们决定找出答案。
了解你的 audience
面对现实吧:我们大多数生活在发达国家中的人都生活在技术泡沫中。我们这些在发达的西方国家从事技术工作的人生活在泡沫内部。产品的用户比您使用最新的Apple硬件(通过最昂贵的互联网计划进行连接)的可能性要小得多。
的重要性 狗食 您制造的产品得到广泛认可和实践。当您自己成为要构建的软件的使用者时,识别多余的功能并查看缺少的功能要容易得多。重要的是,“狗食”需要测试 实际使用情况 产品。的 真实世界 可能是一个与气泡内部的气泡完全不同的世界。可能是慢速的硬件和互联网连接不稳定,不稳定和不稳定。我们中有多少人开发,测试和“测试”我们构建的软件 真实世界 条件?
该指数包括的75个国家中,平均94%的人口生活在移动信号范围内。但是,只有43%的用户可以访问4G信号。
— 2016年连通性状况:使用数据向更具包容性的互联网发展
我们的客户认识到目标市场与我们在泡沫中的泡沫之间存在脱节,并通过Google云端硬盘解决了这个问题,该研究充满了详细的研究和统计数据,详细说明了印度的消费者技术状况。这里有移动网络类别及其分布图,流行设备的市场趋势及其硬件和软件规格,以及我们闻所未闻的使用习惯分析。 (您知道吗,在印度等地区流行的大多数手机都与 多个SIM卡插槽 ?我们没有!它们使用户能够订阅多个电话服务提供商,并利用文本,通话和数据价格的差异。)
通过这项研究,我们确定了一组Android设备和移动网络属性,旨在公平地代表普通印度人使用的设备和移动网络属性。
我们降落在 卡尔本·阿尔法A112 和一个 麦克默斯Q336 作为我们在整个开发过程中使用的主要设备。这些设备是近年来印度最受欢迎的设备之一,它们代表了制造商之间的共同趋势:具有512 Mb RAM的单核1 GHz处理器,运行Android Jelly Bean或KitKat。其他设备包括 小米Redmi 4A , 三星Galaxy J1 Ace 和 一加一 .
您可以用2,800印度卢比/ $40.
寻找具有代表性的网络规范更加困难。作为一个新兴市场,印度移动网络的整体可用性,访问方式和类型每年都在发生巨大变化。印度继续位居互联网用户增长最快的国家之列,每年新增千万用户。这种增长速度需要互联网基础设施自身的快速增长。
脸书 2016年的“连通性状况” 在整体互联网“可用性”方面,印度排名世界第46位,平均移动下载速度为5633 Kbps,只有不到一半的人口能够使用4G网络。由于此类网络与大多数员工使用的50+ Mbps以太网连接有很大不同,因此我们求助于软件来模拟它们。存在各种用于限制网络速度和人为丢弃数据包的工具和开源软件,我们发现, 增强交通管制 和 网络链接调节器 .
在项目过程中,这些设备和网络成为了我们的新泡沫。我们开发,测试和评估了针对他们的里程碑式进展。应用程序性能进入了我们的票证跟踪系统,性能下降与功能下降被视为相同:需要修复的错误。
在这些条件下限制我们的开发和质量检查周期可能会减慢我们的输出-每个ListView 一点点 加载和渲染的时间更长了-但这使我们所构建建筑物的性能处于中心位置。当开发人员,产品经理,设计师在现实世界中使用产品并被迫面对现实世界中的缺点时,应用程序性能就会从模糊的概念(您偶尔会感觉良好)转变为产品优先级。软件产品的性能与您用来构建它的过程一样,也取决于您用来构建它的技术体系结构。
要自私:解决您的问题(客户的问题)并委托 rest
面对有限的硬件功能和不完整的网络连接(在应用程序功能的全部列表中)的现实状况将给我们带来的种种困难,我们围绕技术架构的最初讨论重点在于如何最大程度地降低风险。
我们坚信通过重新发明工作来获得现成的服务和OSS依赖性。如 吉娜·特拉帕尼(Gina Trapani)在“如何为交接建立基础”中指出 ,这些依赖关系通常更容易理解和维护,尤其是在项目从Postlight过渡到客户的内部工程团队时。
Firebase实时数据库 形成了我们架构的核心。以前,我们在各种应用中都取得了巨大的成功 内部 和基于客户端的网络工作,但这是我们在移动应用中使用它的第一次经验。我们很高兴发现它可以立即解决许多苛刻的网络要求。这是“脱机优先”且乐观,在网络连接可用时尝试在与中央服务器同步之前将数据持久保存在本地。它出色地处理了不可靠的连接,同步了可能的连接,并在网络状态动摇时必须重试请求时对请求进行排队。它甚至通过持久的WebSocket连接建立隧道请求,从而避免了延迟,从而减少了延迟。 发出独立HTTP请求的固有开销。
我们充分利用了Firebase产品套件的其他功能, Firebase云功能 用于维护索引(请参见下文),并从客户端卸载计算量大的任务, Firebase电话验证 ,以及他们的Google Analytics(分析)和崩溃报告产品。
通过将网络弹性和脱机数据同步的棘手问题委托给Firebase处理,我们能够节省数月的工程时间,使我们能够集中精力解决客户的问题:构建和优化面向用户的功能。应用。
快点,正确,正确...等等, what?
现在,我们正在模拟普通印度人从家庭办公室直接面对的网络和硬件条件,因此我们开始验证我们提出的技术架构决策是否可以使我们在可接受的性能范围内落到任何地方。我们知道这将是一场充满优化和折衷的艰苦战斗,但我们需要确保它不会成为西西弗。
我们认为,做到这一点的最佳方法是设计一种初始原型的颠倒概念。我们并不关心构建原型时所关心的通常的优先顺序:它并不需要真正起作用(“这里只有一个ListView,别无其他!”), 当然不一定是正确的(“会话持久性到底是什么?”, 它只是必须很快。真的非常非常快。
在两个星期的过程中,我们重新启动了该项目,并构建了定型的准系统聊天应用程序-ListView用于对话,每个对话都链接到用户之间发送的消息的ListView。初始版本对于原型来说速度很快,但是对于 我们的 prototype. It took another week of work optimizing queries, selectors 和 judiciously tuning shouldComponentUpdate
until single user performance was acceptable. But we were building a chat app. How did 我们的 prototype handle many users? We spun up virtual machines that ran scripts faking load on Firebase, sending fake messages to fake users several times each minute in order to test message receipt latency in 真实世界 conditions
很快,与客户互动的时间相对较短,我们只有4周的时间,除了(非常真实,非常快速)的聊天原型之外,没有太多工作来展示实际产品。实际上,当我们实现目标时,时间是充裕的:
我们验证了我们的核心技术架构是否满足性能要求。可以使用React Native和Firebase构建可在目标设备上高效运行的应用程序。
我们了解了必须预先做出的折衷和优化,特别是在数据模式方面。 Firebase中存储的数据习惯上是高度非规范化的,但是在我们的案例中,我们无法管理执行客户端联接所固有的往返延迟。数据必须复制并直接在重要位置的Firebase中加入。在其他位置,仅复制了显示特定屏幕所需的关联数据字段,而在渲染屏幕后可以获取完整的数据结构。最后,我们通过云功能维护了临时索引,其中一些Firebase节点是常规的和非规范化的,而另一些则与特定屏幕高度耦合。这种类型的模式调整本来是非常昂贵的优化,必须进一步进行开发。
在某种程度上,我们的原型阶段遵循正常的事件顺序,只是“快速完成”是“使其正常工作”的关键组成部分。如果该应用的运行速度不足以使其无法在目标设备上使用,则不应将其视为“正常运行”。
手工,自由范围,小批量优化
随着项目的启动和架构的验证,我们有了一个高级框架,可以在其中开始充实产品功能。围绕正确的体系结构构建意味着进一步的开发更多地是要在增加复杂性的同时保持应用程序的性能,而不是使其具有性能,这说起来容易做起来难。通过少量的优化,我们实现了大多数剩余的必要性能提升:
使用平台 :与JavaScript重新实现相比,本机组件和API始终具有更高的性能。请勿在导航器,对话框或选项卡之类的JavaScript组件中使用或重新发明它们,因为它们是平台提供的原语。只要有可能,组件应该是平台提供的实现周围的薄包装。
实施自定义 shouldComponentUpdate
处理程序: redux-connect
和 反应.PureComponent
bring their own implementations, but they have to be general enough to work with most 反应 applications by default. You know your data model 和 能够 realize sizable performance improvements by leveraging that domain knowledge.
导航库打破了组件生命周期的假设: When a new screen is transitioned to in most 反应本机 navigation libraries, the components making up the previous screen are not unmounted. This behavior breaks the “clean up” logic encapsulated in componentWillUnmount
in libraries that subscribe to a centralized store 和 trigger re-renders e.g. react-redux
. Our solution to this involved subscribing to screen visibility events 和一个dding an isScreenVisible
flag into the 反应上下文 . If a component was on a screen that was not currently visible, we knew we could short-circuit its render cycle with shouldComponentUpdate
to avoid wasting time rerendering a non-visible view.
反应本机在这里 stay
我们能够使用React Native并使其在对性能至关重要的应用程序中运行的事实证明了它的强大功能和灵活性。
反应本机是一个用于构建移动应用程序的高级框架,但是令人惊讶的是,它没有关于如何在该框架中工作的规定。它定义了合同,但具体细节由您自己决定。
如果标准库中捆绑的视图或平台API不存在,则可以很容易地自行构建,将其安装到位,并且使您的应用程序代码更明智。如果特定组件或屏幕的性能不足,则可以用纯本机实现替换它。 反应本机为您提供了一个布置精美的房屋,但仍会向您显示所有出口的位置。
这种灵活性使我们能够在可能的情况下对Android平台的细节进行抽象,从而缩短了开发时间,同时仍能够在需要调整性能的地方使用本机代码。结合起来,这就是从React架构本身(可组合的,声明性的,基于组件的UI方法)中benefits取的好处,显然,React Native将继续其 快速上升 作为移动开发的首选框架。
反应本机是以下原因的自然结果 阿特伍德定律 ,其中指出:
任何应用程序 能够 用JavaScript编写, 将 最终用JavaScript编写。
而且我们对此感到高兴。
丹尼尔·拉米雷斯(Daniel Ramirez)是一名工程师 射灯 ,这是一家位于纽约的数字产品工作室。是否有需要构建的跨平台或其他技术挑战性的移动应用程序? 保持联系 .