Worktile 移动团队如何使用 C++ 完成 Worktile Pro 跨平台应用开发<之二>
设计
“网络请求 - 解析数据 - 写入缓存 - 读取缓存”
在上篇的文章中我们说明了我们在是在 MVC 层面的 M 层共享了代码,不过对于只是“有可能”需要 OpenSDK 的团队来说,更重要的还是保证 M 层的代码能够支撑 VC 层的调用方式。我们在编写界面的时候,通常情况下是先从缓存(SQLite,下同)中查询该界面已经缓存的数据用于显示一屏预览数据,此时在界面上某个角落显示 HUD,然后发起网络请求,请求到数据之后解析数据(JSON,XML,Protol Buffers),然后将数据类化写入缓存——YES,就这么俩事(儿),too 易姿 too 森破。
网络请求 - 解析
“libcurl & json11”
我们团队在 Web 上用的是 MEAN Stack,对于 Client 来说,就是发起一个请求,然后获得一个以 JSON 形式表示的结果,Client 将其解析为类,然后将结果同步到 SQLite 中,方便下一次缓存页面的使用,在具体的使用中,我们参考 cocos2d-x 对 libcurl 的封装,并结合 C++ 11,封装了一个 HttpClient 用于普通的 GET/POST/PUT/DELETE 请求,对于 iOS 和 Android 的上传和下载部分,我们仍然使用了原生的方法,因为有些时候上传和下载需要在“后台”进行,这意味着需要提供能访问 framework API 的能力,对于 Windows 和 Mac,则可以继续使用 HttpClient 中提供的 C++ 方法来进行操作 (因为并没有“后台”一说)。请求下来数据之后,我们使用了 dropbox team 提供的 json11 进行解析,类化。
写入缓存 - 读取缓存
“easySqlite”
在数据缓存方面,我们选用了大家都说好的 SQLite,在 SQLite 的方案上我们其实做过一些探讨——我们可以选择 CoreData 作为 iOS/Mac 的方案,Android 也有原生的 Helper,Windows 则只能使用 C/C++ 的原生方案。经过实践我们发现其实在客户端几乎只有读取缓存的需求——因为写入缓存的操作可以在 C++ 层面完成——紧接在 HTTP 请求之后,所以我们就选用了所有平台都使用 C/C++ 的方式进行数据库操作,查了几个可选的 C/C++ 库之后,我们觉得 easySqlite 是比较容易使用和维护的。(轻量是我们评估方案的一个重要参考指标,轻量不仅意味着小,而且意味着 fork 之后我们可以自己进行修改而不用在弄懂里面的工作原理上花过分多的时间)
在缓存策略上,我们就是简单的将 JSON 解析后类的表存储到数据库中。这里有个小插曲,之前有看到有策略是将每个页面的 JSON 直接存储到数据库中,然后取出的时候解析呈现,不过我们的移动端和桌面端有可能调用不同的 API 接口,而且如果按照页面缓存,就不是一个适合放在 Core 层的方案了,故最终该方案还是没有敌过我们一颗面向对象的心。
Prebuilt & Future
“Sakura”
由于我们在 Worktile Pro 版与 Worktile协同版中使用了同一套的底层工具库,而 build 过 C++ library 的同学也应该会觉得其实每个平台看着对应库的文档去 build 也是挺蛋疼的一件事情,所以我们将我们用到的 C++ 库 fork 一份并且编译出来,连我们一起的弄出一个 prebuilts 作为我们 C++ 的核心库的工具库,用 git submodule 形式管理使用。(为了体现一点情怀,我们取名为 Sakura>>)
自动构建代码 — Model Builder
“人生苦短,我用 Python”
上文介绍的 C++ 跨平台的目的,是在创业公司初期人少的时候提供一个可以很快出产品的技术方案,在我们编写一个又一个的模块时,我们发现我们在做一个比较重复性的事情 ——写一个 User,写一个 UserManager 用于管理 User 相关的 API,为 UserManager 编写一个 FetchUsersFromCache, 用于从 SQLite 从读取用户的信息,然后编写对应的 Objective-C++ Wrapper 以及 Java Wrapper,然后我们编写一个任务的模块的时候,我们又重复了同样的一个过程——当然,细想一下,我们重复做的事情并不能通过在 C++ 设计 Super Class 或者 Template 抽象出来,但是我们的的确确在用一套重复的思维方式,于是,我们将应该由 Contributor 消费脑力完成的设计过程提炼成 module.xml,然后编写了一个 Python 脚本用于生成 C++, Objective-C++ 以及 Java 部分的代码>> 。
使用 Model Builder 构建代码的好处一方面是可以保证全部门的代码风格统一并且符合规范,另外也可以解决一些由于传参太多或者重构的时候顺序乱了造成的一些低级错误。不过需要特别提一句的是,即使使用了 Model Builder,我们仍然认为只有 Unit Test 能保证你的代码质量,我们仅将 Model Builder 视为代码构建的辅助工具。另外,因为在我们公司我们无法获取 Web 端的代码,如果你所在的公司处在刚起步的阶段,你完全可以考虑将 Model Builder 自行扩展下使其能够生成你们的样式的 Web 端代码以及文档,这样更让联调这一过程变得 smooth (因为返回的 JSON 的 Key 声明在了 module.xml 中,这样就可以保证服务端所使用的 path 和客户端的相同)。
示例代码
本篇我们将提供 iOS 以及 Android 示例代码 来阐述我们上文中提到的用法。
下一节
下一节中我们将针对初创公司端技术团队构建的一些问题来阐述我们的团队如何构建以及运作的。