【第17期】去哪儿网的iOS 客户端架构演进

 

同学们晚上好,很高兴有这样一个机会和大家分享去哪儿网的iOS客户端架构演进,我先做一下自我介绍。我是08级计科的毕业生孟超,目前是去哪儿网平台事业部前端iOS的负责人,主要做hybrid等相关工作。...

前言
同学们晚上好,很高兴有这样一个机会和大家分享去哪儿网的iOS 客户端架构演进,我先做一下自我介绍。我是08级计科的毕业生孟超,目前是去哪儿网平台事业部前端iOS的负责人,主要做hybrid等相关工作。
正文
做项目时,经常脑袋一热,二话不说上来就撸代码。然后就发现框架不行,不够灵活无法扩展,功能缺失!然后在你准备调整架构的时候,产品经理就跳出来补上一刀——改需求。



既然好的架构如此重要,那么去哪儿 app的架构如何呢?

我会分为四个部分来阐述这个主题:

1、小型客户端的架构

2、去哪儿app早期客户端架构

3、去哪儿app现有客户端架构

4、总结

小型客户端的架构

小型客户端参与开发的人比较少,或者干脆就一个人在开发,所以一般情况下不太在意架构。如果每天陷入在如何做架构上,效率肯定不会太高。以去哪儿hybrid框架早期版本为例,一开始为了尽快成型,使用了很多优秀的第三方库。我先介绍下hybrid app的概念:Hybrid App(混合模式移动应用)是指介于web-app、native-app这两者之间的app,兼具“Native App良好用户交互体验的优势”和“Web App跨平台开发的优势”。(来自百度百科)

hybrid项目主要涉及到的功能有:webview和native(objective-c)的交互,网络请求的拦截(用来加载本地html)还有zip包解压,版本比较等等。功能就这么多的情况下,我们要实现这个框架,优先想到了去github上搜一圈,就找到了下面这些库。

WebViewJavascriptBridge: UIWebview 和OC 的交互框架

WebViewProxy: 用来拦截webview 网络请求

AFNetworking 2.0:对iOS 系统提供的网络请求的封装,在github(大家一定要多使用这个网站)上有25428个星星,8074次fork。

XMLParse: 解析XML文件,主要是服务器配置文件等。

PS: 当时公司的服务器太多,有dev、beta、线上服务器(在大点的公司,这些都是常识吧,那时最让我头疼的就是配置host,因为我只知道皮毛)。

ZipArchive:zip解压库,用来把html、js、css等静态资源的压缩包从本地解压,然后直接在本地加载。

EDSemver: 一个版本比较的库



这些代码都是比较成熟的,完全可以满足我们的要求。使用了上面这些从github上找到的库之后,再加上我对OC的了解,就可以像拼积木一样,把要做的工作完成了。就这样快速取得团队其他人员的认可,过了试用期。做了这么些工作之后,我们成功上线过好几款独立客户端,但是都很小,几乎native代码都是我们写的,没有任何的挑战。但是因为做了这些,为下面hybrid框架进入到大客户端做了铺垫。下面给大家介绍一下“去哪儿app早期客户端架构”

去哪儿app早期客户端架构

从毕业直到来去哪儿的前半年,基本上都属于单打独斗的情况。第一次有了大客户端代码的权限,那个兴奋啊!从gitlab上拉到代码,不知道怎么玩了,长这么大还没用过git submodule,总觉得很高深似得。学了半天的git submodule(大家可以Google学习下,其实也就几句命令,关键是概念和原理要清楚),不知道删了重新拉的多少次代码,终于搞定了。由于都是以源代码的形式把项目组织到一块的,第一次编译了整整50分钟。不管编译时间了,先看一下工程构成.



一个主工程下面有这么多子工程,每个子工程都是通过git submodule加进来的。主工程大家有兴趣,打开xcode创建就可以得到,把这些子工程以添加静态库的形式加入到主工程就是去哪儿早期的架构,清楚了工程结构,我的目标是将hybrid框架迁移到大客户端,这个时候,我就不能肆无忌惮的使用第三方库了。我首先要过一遍大客户端到底有没有和我类似的第三方,看来看去也就只要解压库了,还在攻略模块里,就这样我依赖了攻略模块。

大家从这里可以看出来了吧,这个时候去哪儿的客户端,虽然是按模块给各个业务线分出了子项目,但是没有任何的隔离,基本上各个模块都会有互相调用的情况(不可避免的是,业务线之间有交集)。细细想想,这个架构随着时间的发展必然会是一团乱麻。

但是不管怎么说,每个业务线的开发者应该在不到万不得已的情况下,不要随便依赖别的模块。具体到HYBrid框架,我为了避免和大客户端冲突,将所有网络请求改成了iOS 提供的,将很多第三方库都进行了重命名或者替代处理。

今天的hybrid框架已经不依赖任何第三方库了,其实从第一阶段到现在,hybrid框架的核心功能没怎么变(和我前面说的小型app的基本一致,把第三方开源库的功能自己实现了,毕竟我们有时只要其中一点点功能,或者开源库有很大限制或者bug),只是代码被重构了好多次。

说了这么多,我其实想表达的是,这个阶段的去哪儿客户端,已经给团队带来了麻烦,往往改个bug就要加班到晚上大半夜。

下面说一下,去哪儿客户端是如何发版的呢?我们有十多个业务线,总不能每个业务有新功能或者bug fix都要发版吧。



给大家一张图,基本上说清楚了十多个业务线如何合作发布同一份代码的。

去哪儿app现在客户端架构

老架构,由于所有代码都是以源码形式放在一个工程里,导致编译一次时间过长(因为编译一次时间过长,一不小心就加班到晚上4点了)。还有各业务线代码耦合严重,于是就有了去年底的新架构。

新架构具有如下的特点:

- 轻架构,客户端平台等同于OS- 解耦,各业务开发完全解耦,包括前端和后端



大家可以看看这个架构图,结构要比之前架构清晰很多。我按图上标出来的数字进行说明。

1、CommonFrameWork:公共框架,主要放一些各业务线都会调用的不涉及业务的代码,比如网络请求的封装,公共组件的封装,scheme的跳转,数据的存储接口等等。

2、Configure:这个工程巧妙,主要是配置文件,比如程序入口、服务器地址、版本号、scheme和业务线对应关系、各种ID什么的,反正这个库的内容是可以变动的。

注意:这些配置项都是一些宏定义,宏定义在编译的时候,会替换为本来的值编译到静态库里,所以ConFigure工程并不会编译成一个静态库,而是以源码的形式被各个业务当做基础库引用。这也是唯一一个不编译成静态库的模块。

3、CommonKit:毕竟去哪儿客户端已经发展多年了,会有很多历史代码,这些代码删也删不掉,怎么办呢?就先放到CommonKit模块里吧,会告诉各个业务线,这里的代码不会维护了,这样随着时间的推移,会有节奏的废弃掉。说实话放出去的接口,很难收回来,所以设计接口一定要慎重。

4、Hybrid:hybrid框架已经成为去哪儿客户端不可获缺的一部分,打开去哪儿的客户端,随处可见的h5都运行在hybrid框架之上。(有机会可以给大家分享下实现原理)。

5、qunar React Native:不知道大家有没有在App store上下载,如果app 的大小超过100M,在非Wifi网络下,会弹出一个提示框,提示用户APP 的大小超过100M。所以各大公司都在尽量保持App 的大小少于100M,很不幸,去哪儿的app在迁移完新架构之后,超过了100M(原因大概是,有些业务线为了和别的模块解耦,会copy别的模块的代码。导致客户端暂时多了些重复代码),并且越来越大,所以在这个压力下,react native成了减size的一根稻草。

6、说完了基础模块,接下来就轮到业务模块了,业务模块会依赖基础模块,基础模块暴露了头文件。业务模块之间不可以互相调用,只能通过CommonFrameWork里提供的Scheme接口。

7、cocoapods又是另一个话题了,大家如果对包管理有兴趣可以自行查看。

8、Jenkins是自动化打包平台。

一下子抛出这么多,大家以后先慢慢消化。

简单说一下打包,每个模块都会有个打包job,都能独立发布静态库。在最终上线的时候,每个模块的负责QA在指定平台上确认要发布的版本,然后在发布当天早上,公共QA通过各业务线指定的版本拉取静态库,打包编译(由于各个业务线已经是静态库形式,所以总体打包时间在3分钟之内),接下来进行集成测试。终于解决了打包一次50分钟的情况,自此我再也没加班过。

各模块做到解耦是因为新架构做了以下规定:

- 模块之间的调用是通过scheme(类似URL的样子,这里理解为一种接口吧,可以传参,可以得到返回值)调用。

- 只有公共部分代码提供头文件,可以被别的业务线调用。

   总结

以上主要是分享了去哪儿客户端的架构演进。目前并不算是最好的架构,但也最符合当下的去哪儿app。随着业务的发展,我相信架构还会一直进化。而且行业不同,可能架构也不一样。就比如我们的架构肯定不适用于滴滴。我们的页面数量多的我根本数不过来。预见性的架构设计思想可以让开发避免很多麻烦,所以,像一些基本的设计原则比如 单一 原则、里氏替换原则、依赖倒置原则等等(请自行查看设计模式即可),众多设计模式有良好的扩展和灵活特性的指导。又或者利用其他编程范式如函数式、响应式来写出更加健壮灵活的代码,可以让你的项目更加健壮、灵活、高效、优雅。

最后,网上有一些组件化的文章,大家有兴趣可以看看。

蘑菇街 App 的组件化之路 http://limboy.me/ios/2016/03/10/mgj-components.html

蘑菇街 App 的组件化之路·续 http://limboy.me/ios/2016/03/14/mgj-components-continued.html

iOS应用架构谈 组件化方案 http://casatwy.com/iOS-Modulization.html

OK,我以上的分享,基本上没有涉及到代码,主要是考虑到大家学iOS的人不多。如果大家有进一步学习iOS的目标,可以留着在我的分享中获取一些信息。我介绍了一些工具或者框架,但是我并没有细说。比如Jenkins和Cocoapods 都是一个话题。


问答 FAQ
学长觉得今年将发布的swift3.0会是个稳定些的版本吗?

不是,苹果已经把README改了,说这次不是ABI稳定版本。也就说编译的二进制不是稳定的。我们只能期待swift 3.x 或者4了。
就是说即使苹果更新了swift学长还是更建议学OC?

对的,目前来看OC是必须要会的,毕竟很多优秀的第三方库还没有swift版本或者替代品,除非去了一个创业公司。这样就自由多了。我上面分享的时候,提到了客户端的size问题。也就是说客户端最好不要超过100M,swift有个致命的缺陷,就是在iOS9之前,需要把运行时打包到程序里,大概会增加8M,对大公司来说是不可能接受的。在98%的用户没有升级到iOS 9之前,OC还是很有优势的。补充一下,以前统计过我们公司光车车一个业务线就有40万行代码,要切到swift不容易啊。iOS 9的市场份额。



大家可以这里查看 https://developer.apple.com/support/app-store/目前大家采取的都是OC和swift共存的策略,比如 猿题库从 Objective-C 到 Swift 的迁移http://blog.devtang.com/2016/05/24/migrate-from-oc-to-swift/
OC或者Swift除了开发iOS之外还能做啥?

OC可以做mac app。但是mac app大部分人选择用h5做了包一个壳,所以OC的应用范围会越来越小。swift的话,目前已经有类似nodejs的express框架,所以将来在Linux上做服务端肯定没问题,替代Python写脚本也可以。。前段时间有新闻说Google打算把swift 改成Android的开发语言,这个也不是没有可能,就算是Google不做,开源社区也会做的。
学长我写OC感觉练习和实际的应用代码完全不一样,实际应用用到了大量陌生的方法,这个问题要怎么解决?

要是仅仅写OC的话,你涉及到的还是语法层面的东西。在语法层面,任何一门语言都可以很快掌握。 你要解决这个问题,就要尝试做项目,熟悉常用框架的用法。比如Foundation,UIKit,包括很火的AFNetworking。你使用几次,熟悉之后就会好很多。对于大量的陌生方法,这个是肯定的,我们现在写代码也会碰到大量陌生方法,就算是同一个团队的人,他有可能会写出一个我不认识的方法。我们要做到会使用这些方法,比如方法如何调用,block如何用,多线程,autolayout等等,这些基础知识掌握了,陌生方法也会在你的预料之内,完全可以应付。唯一麻烦的就是,实现一个功能需要多个方法或者类的配合,这个时候就很麻烦,具体问题具体解决


欢迎关注《天理互联网技术》公众号

我们的微信名:天理互联网技术

微信ID:tjut_tech


点击查看历史消息,查看更多内容。


长按图片识别二维码,一键加关注,防走丢。
如果你是一名天津理工大学的互联网人,也可以在公共号内回复『Join』加入『天理互联网技术群』,亲身参加分享和技术讨论。


    关注 天理互联网技术


微信扫一扫关注公众号

0 个评论

要回复文章请先登录注册