适用于iOS的Basecamp 3:混合架构

过去,我们已经针对构建混合移动应用程序的方法撰写了很多文章。 Basecamp 3代表了该架构的最新一代,它吸收了我们从先前版本中学到的所有知识。

Basecamp 2应用程序的第一个应用程序仅为iPhone,使用RubyMotion编写,作为UIWebView的薄包装。 接下来,我们为Basecamp 2开发了一个新的通用应用程序,该应用程序使用Xcode + Objective-C编写,仍然使用UIWebView,但是还添加了一些本机代码。对于Basecamp 3,我们用Swift,UIWebView替换了Objective-C与WKWebView并添加了Turbolinks,以及更多的本机代码,以及本机和Web之间的更深入的集成。

定义混合

首先,有助于弄清我们所说的“混合”是什么意思。 该术语在许多不同的上下文中使用,几乎没有意义。 在我们的使用中,我们指的是标准本机应用程序,其中很大一部分内容是使用网络技术呈现的。 我在那里明确表示内容,因为这是一个重要的区别。 我们没有使用试图模仿使用HTML / CSS的本机控件的框架。 我们没有使用试图将另一种语言编译为本机代码,或从单个代码库制作跨平台应用程序的框架。

对我们来说,这意味着使用Xcode + Swift,并遵守有关导航/表示的所有平台约定。 我们的应用程序的构建基块由UINavigationControllerUITabViewControllerUISplitViewControllerUIViewController等组成。在这些容器中,我们有很多屏幕都是使用UITableViewUICollectionView构建内容的,而在由WKWebView填充角色的地方,还有更多的WKWebView

引擎盖下

适用于iOS的Basecamp 3使用最新版本的Xcode在Swift 3.1中(即将成为4)100%编写。 我们只有几个依赖项,但是我们确实有一些依赖项是由Carthage管理的。 启用这种混合体系结构的核心库是Turbolinks。 我们在网络上使用Turbolinks,并且我们的iOS和Android配套框架也允许我们在本机应用程序中使用它。 该框架处理与Turbolinks.js的通信,并允许使用在多个不同屏幕之间共享的单个WKWebView

路由器/导航器
除了Turbolinks,我们还有许多其他组件来支持它。 我们在iOS应用中的大多数导航都是URL驱动的。 网址可以来自许多来源(Web链接,推送通知,来自另一个应用程序的通用链接,本机操作等),它们都通过路由器。 该路由器负责确切确定对给定的URL采取什么操作。 如果路由器用于其他域,则路由器可以在Safari中打开url,如果图像/视频是路由器,则可以显示媒体查看器,或者在通常情况下,创建要显示的新视图控制器。 路由器将视图控制器移交给负责演示的导航器 。 大多数视图控制器被推送到当前导航堆栈上,但是我们还支持模态显示某些屏幕(例如新视图/编辑视图),或在适当时替换当前屏幕。


构成混合体系结构的最后一个组件(尽管我们还有许多其他与混合部分无关的组件)被称为“桥梁”。 这是涉及本机→网络(或Web→本机)通信的应用程序各个部分的总称。 此处的主要代码是嵌入在应用程序中并使用WKUserScript注入到Web视图中的本地JavaScript文件(以TypeScript编写)。 这为本机代码提供了一个API,用于与Web视图进行通信,而无需直接查询DOM或执行复杂的JS。 使用WKScriptMessageHandler ,我们可以响应通过网桥从Web视图发送的消息。

上面是行动桥梁的一个例子。 我们使用它来隐藏许多通常在移动网络上显示的元素,这些元素在应用程序中没有意义。 由于我们提供了用于顶层导航的标签栏,因此我们不需要此处显示的标签栏。 由于我们具有导航控制器,因此不需要导航的面包屑。 最后,我们隐藏了Web编辑/书签/操作菜单,而是提供了本机版本。

例子

通过一些示例,可以更轻松地直观地看到实际情况。 在下面的图片中,我将使用紫色的叠加层指示Web视图,并使用绿色的叠加层指示本机UI。

主要标签
适用于iOS的Basecamp 3具有4个主要选项卡( HomeHey!ActivityFind )。 这些标签中的每一个都是100%本机的。 这些是应用程序中交互的主要点,我们希望它们尽可能快。 我们还希望提供与台式机不同的体验,例如统一的Hey !,这在移动设备上更有意义。 所有的通知,其中还包括最近的Ping。

信息
当您在Hey!中轻按通知时,说出一条新消息,然后在导航堆栈中推送新的TurbolinksViewController

这是一个典型的屏幕,其中所有内容都是Web视图。 通过网桥 ,我们将数据从页面中拉出以显示在导航栏中。 同样,我们使用DOM中的数据来填充当您点击“…”按钮时显示的本机操作菜单弹出窗口。 由于此动态是由页面提供的,因此我们可以随时在服务器端更改它。 最后,如果您点击导航栏标题,我们将显示一个本机的“工具菜单”,该菜单提供了快速浏览项目的权限。

营火
我们也有一些屏幕,其中的内容是本机和Web的混合。 篝火就是这种情况:

此处的主要聊天内容是网络,但我们决定使用本机视图进行输入。 这解决了Web输入中的许多问题,例如在滚动时保持正确的位置,并且我们还可以更好地控制交互式键盘的关闭等操作。 输入某人的姓名时,我们使用本机提及自动完成程序。 轻触回形针按钮将显示附件选择器,这是一个本机元素,我们在整个应用程序中使用了一些不错的技巧,例如快速选择最近拍摄的照片。 所有这些组件都可以在同一屏幕上无缝地一起工作。

摘要

这些仅是几个示例,但展示了此方法的灵活性。 该体系结构的关键是我们不会陷入一种方法或框架中。 本机或网络不是二进制选择,而是频谱:

对于应用程序的每个屏幕,我们都可以调整我们在该频谱上的位置。 我们可以确定本机屏幕使用很少并且不值得维护,因此我们将其更改为Web。 我们可以确定网络屏幕无法提供最佳体验,然后将其转换为本地屏幕。 我们可以决定尝试使用React Native并将其混合使用。 只要Apple发布新的API,我们就可以立即支持它,因为我们不依赖于要更新的​​第三方框架。

我们在大本营深为珍惜的一件事是团队的独立性。 如果我们必须与网络,iOS和Android团队紧密协作来协调每个功能的开发和发布,我们将一无所获。 这种架构使我们的Web团队可以构建新功能并在所有平台上同时发布。 默认情况下,我们有一个视图控制器,可以显示Basecamp 3中的任何URL,因此任何新的URL都将在应用程序中起作用。 我们可以在Web上进行迭代和实验,立即在所有平台上发布,如果感觉可以改善体验的话,可以稍后将其本地化。

这也使我们的移动团队专注于如何最好地为平台提供服务。 我们的目标之一是100%覆盖移动应用程序,您永远不必去台式机,因为这些应用程序不支持某些功能。 利用网络提供的坚实基础,我们可以实现该目标,然后将精力集中在针对特定平台的改进上。 这些功能包括丰富的内容推送通知,通用链接,切换支持,iCloud钥匙串支持,共享扩展,今天的小部件等功能。 如果我们没有完整的本地支持,其中的某些事情将是不可能或不平凡的。

Interesting Posts