新应用程序“水母”。为什么扑扑?

技术总监Boris Goryachev讨论了Medusa如何使用它一年,以及为何用Flutter编写它


5月12日,发布了新的Medusa移动应用程序(iOSAndroid,距离我们决定重写它们将近两年。为什么这么久?为什么不使用本机应用程序?为什么颤振? Medusa Boris Goryachev的技术主管告诉了所有这一切。



与我们的旧应用程序不同,我们决定不使新应用程序成为本地应用程序。首先,两次编写相同的代码很繁琐。其次,它将永远无法实现,因此在不同的人编写的两个不同的项目中,所有事物都是同步且相同的。通常情况下,某人工作慢一些,某人去度假,某人有技术债务需要关闭。我们在创建和支持本机应用程序方面的所有经验都提示我们-我们做错了什么,或者这根本不是我们的方式。我们开始寻找我们的。我们尝试了React Native和Ionic,考虑了Basecamp方法-网络中的所有内容+薄的原生层,甚至尝试使用Progressive Web App并保持在线状态。

大约在同一时间,我参加了Google I / O会议,并结识了在那里创建Flutter的人。我立即尝试使用Dart并在Flutter上进行了一些工作,但是当时该技术尚未为Medusa做好准备:不可能将各种交互式材料嵌入到我们的材料中,但这对于媒体来说至关重要。所以我决定等到Flutter长大。

在等待期间,我们在网络上做了很多事情:重写了网站,编写了新版本的AMP。我们编写了Medusa的所有项目,并将其转移到ui-kit,这是该站点使用的单个组件库,因此,我们的大量游戏机制都可以实现。我们将网站的桌面版和移动版分为两部分,以便根据各自的规则在两个不同的地方形成分发页面(主页和分区页面)。

与该站点上的工作同时,我们正在考虑一个新的应用程序-我们提出了其导航,含义,屏幕,功能等。



同时,技术部门的结构发生了重要变化。我们开始积极使用Google日历和其他会议计划工具,然后从Trello转到Basecamp。很明显,谈论它甚至很奇怪。但是,花费大量时间和精力来简化混乱情况。清晰的会议议程,快速的跟进,不丢失的文件以及山图范围使应对大量任务而永不枯竭成为可能。

为什么它仍然颤动。关于Dart的一些知识


当人们了解Flutter时,他们必然会了解Dart。似乎它被认为是Flutter的最大缺点,但是恰好在您尝试编写它之前。他真的很酷。遵循JavaScript非常特别。

Dart是Google开发的一种编程语言。它是在2011年宣布的,也就是说,它仍然是一门年轻的语言。 (至少到目前为止)它还没有成为主要的编程语言,但与此同时,它在公司内部也非常活跃。除了Google之外,还有其他大型公司,例如Wrike,它们使用Dart并在其上写满堆栈。

由于Dart和Flutter都由同一家公司支持,因此可以根据Flutter的需要更改语言。据我所知,两个团队都积极地进行互动,因此芯片会不断出现在语言中,从而使您可以在Flutter上编写更悦耳的代码。

我不会尝试解释Flutter的组成-Wikipedia可以更好地应对这一任务,但是我只想说作者中有使用Chromium进行渲染的人。

2018年12月,Flutter团队在Flutter中发布了Webview嵌入库。它是原始的,顺便说一句,它仍然没有离开“开发人员预览状态”,但是这一事实并没有停止,开始估计未来应用程序的结构。在几个月的时间里,我尝试了自己的业余时间,然后做出了最终决定。

最初,我坐下来编写专门针对该应用程序的API的新版本。该API的思想可以表述为:如果可以在后端完成某些工作,那么您需要在后端进行。这不是因为很难在客户端上做某事。事实是,在App Store和Google Play上发布是一个费力而漫长的过程。您需要适应他们的工作计划,并记住并非所有用户都会立即更新该应用程序。当服务器上发生主要逻辑时,可以避免这种情况。是否需要将标题下移10个像素?别客气。快速删除或添加组件?没问题!



出于同样的原因,用于移动应用程序的API包含可能的最简单的组件,几乎所有的材料都从其中递归收集。我说“差不多”是因为我们通过WebView展示游戏。该应用程序显示什么无关紧要-卡,播客,新闻或“大热门”。一切都由一个代码处理,应用程序的任务是获取组件并将其呈现(或转到其子代列表并递归调用)。

支持Flutter的另一个重要论点是:开发人员“控制所有像素”。当您需要确保每个地方都有正确的阴影时(如Sketch中的布局),或者您希望透明度随曲线变化,或者您想要自定义字体大小和所有字体时,Flutter中的所有内容都是简单而现实的。

Flutter的另一个杀手级功能是开发舒适度。我在Web开发中已经习惯了热重装,并且在不丢失状态的情况下快速重装应用程序的速度使这项工作变得尽可能容易。您无需坐着等到重建应用程序,再等到新代码正常工作,然后重复工作的状态即可。一切都发生得真快又酷。

生态系统


尽管Flutter和Dart并不是很流行的技术,但我们在查找库方面没有任何问题。应用程序所需的大部分内容都在框架本身中或在pub.dev上。社区非常愉快,随时准备提供帮助。这种交流是真正的新鲜空气,非常有帮助。

此外,Google本身也很好地支持Flutter。我们使用Firebase进行推送,分析,配置文件和存储用户数据(读取历史记录,剧集位置,书签),并且一切在这里都“有效”。当然,作为一个以前从未编写过本机应用程序的人,有时候疯狂地爬入gradle文件或将属性放入info.plist中是很疯狂的。但通常所有内容都经过Google搜索,并且没有任何难以置信的复杂性。

平台差异


您可以无休止地谈论iOS和Android之间的区别。通常,他们立即记住用户应该熟悉模式,并且必须遵循设计准则。我们对此表示同意,但并不完全同意。重要的是要记住您的公司身份,常识以及已经熟悉的用户的行为逻辑。

如果您查看平台本身的历史,我们会发现某些模式随设备而改变,而另一些模式则从系统流向系统。这些不是平板电脑,什么也不会停滞。有数十个很酷的例子,公司在这些例子中偏离了Google和Apple的建议,并做了他们认为正确的事情。



最简单,最生动的示例是在iOS中向后滑动。默认情况下,接受刷卡的屏幕区域很小,约为20像素。这就是Mail应用程序在iPhone上的工作方式,这非常不方便。在Twitter上,该区域略有扩展,而在Telegram上,这是巨大的! Android上的Telegram从聊天列表到聊天都有其特殊的导航类型,它是iOS和Android之间的交叉。是的,指导方针很酷,但是在iPhone XR上,将手指伸到设备的左上边缘非常不便。因此,我们决定(当然,取决于数据)在“ Medusa”应用程序中,iOS上的“后退”按钮将位于下方。但是在Android上根本不会。为此,有svaypas(我们自己的和新的Android svaypas)和系统按钮“返回”。

我的同事,美杜莎·纳斯塔·雅洛瓦亚(Medusa Nastya Yarovaya)艺术总监说:

我的手很小,电话也很大。看起来很荒谬,但它影响了开发过程中的两个重要决定。首先,我建议大幅增加滑动区域(增加到50%),这是与指南的第一个偏差。然后,当我们处理资料中的导航和功能按钮时,我建议将“后退”按钮放在下面的常规菜单中-这是与界面中通常模式的另一个偏差。现在您可以用拇指触碰到它,因为它们主要是通过它滚动的。


我们知道,我们一定会因为我们违反了Apple和Google的许多建议而飞奔而去。但是,如果有的话,我们还使用电话,并且了解到许多模式已经过时了,因为它们是为设备发明的,只有一半。

一点练习:如何在Flutter中工作


在使用React和其他响应式框架之后,您可以在几天之内在Flutter上构建原型。 Flutter的一般概念-一切都是小部件。 Flutter提供了两种(实际上是三种)范例:您可以使用遵循材料设计概念的材料小部件。您可以使用Cupertino小部件-这些小部件的外观和行为类似于iOS上的。您可以自己编写所有内容。

粗略地说,开发人员可以与两种类型的小部件进行交互:无状态和有状态。

无状态小部件是加号或减号小部件,它们内部不包含应更改小部件状态的逻辑。

有状态的小部件具有setState函数(您好,反应!)。您更改状态,小部件将重新绘制。

但是,当然,在简单的setState上的大型应用程序不会走太远,因此需要一种状态管理解决方案。

Flutter有几种解决方案。例如,存在一个BloC模式,其中使用了来自数据源的流和事件,它们包含引发新事件诞生的业务逻辑。小部件会听到这些事件,并且小部件会响应更改。

那些追随React的人可能想尝试Redux。从理论上讲,如果您使用此方法在React中编写,应该不会有问题。

我尝试了两种方法,最后选择了第三种。水母应用程序使用提供程序。这是不是由Google编写的库,但是有趣的是,在国内尝试使用Provider的Google开始放弃其BloC,甚至决定将Provider重复作为一个单独的库。但是最后,他放弃了重复别人的代码的想法,开始使用和维护作为开源而诞生的东西。

提供程序设备非常简单。这是一个内部有状态的小部件。此状态由内部调用notifyListeners()的函数更改。这些必须响应更改的窗口小部件在窗口小部件树中-它们是窗口小部件提供者的直接子代或子代提供者的子代。调用notifyListeners()时,子代会通过上下文获取新值并进行重建。

通常,提供程序是在应用程序的“顶部”发布的,您可以一次使用多个提供程序-每个提供程序负责其自己的业务逻辑。

现在,我们使用了八个正在“监听”应用程序不同位置的提供程序。例如,书签提供者的工作方式如下,这要归功于读者可以保存自己喜欢的资料,离线阅读以及在不同设备上的同一位置阅读。

该响应会添加到实例中,以更改Firebase中的文档,其中包含读者添加书签的材料的键。对于此文档的每个onChange,将更新提供程序中的关联变量,并调用notifyListeners。结果,所有侦听此提供程序的窗口小部件都显示正确的图标。

通过提供者,应用程序主题也已切换。该应用程序具有ThemeProvider,该模板本身包含两个主题实例-实际上,它只是一个Map,其中包含我们对颜色的命名以及颜色本身。

结果,正确的颜色出现在小部件上,如下所示:

TextSpan(
	text: block['data']['first'],
	style: TextStyle(
		color: Provider.of<ThemeProvider>(context)
        .current
        .bodyFontColor,                            
  fontFamily: 'Proxima Nova',
));

提供者代码(如果简化)将是:

class ThemeProvider extends ChangeNotifier {
  CustomThemeData current;
  
  CustomThemeData blackTheme = CustomThemeData(
    name: 'black',
    bodyFontColor: Color.fromRGBO(184, 184, 184, 1),
    ...
  );
  
  CustomThemeData lightTheme = CustomThemeData(
    name: 'black',
    bodyFontColor: Color.fromRGBO(184, 184, 184, 1),
    ...
  );
  
  ThemeProvider(withTheme, withFontMultiplier, withAutoTheme) {
    theme = withTheme;
    autoTheme = withAutoTheme;
    current = withTheme == 'light' ? lightTheme : blackTheme;
  }
}

因此,当您更改当前变量时,所有从主题中获取颜色的小部件都将正确显示,没有例外。

下一步是什么


最近几周,我们一直在对数百名Medusa读者进行积极的测试。我们将在另一篇文章中告诉您测试的进行方式,但是我只会注意到Flutter满足了我的所有期望。是的,他有一种方法可以开发,是的,不是所有功能丰富的库,但是,观察到所有过程的运行速度,我(至少对我自己而言)得出结论,Flutter与Medusa的合作将持续很长时间。

All Articles