Worktile 移动团队如何使用 C++ 完成跨平台应用开发

2016-04-12 15:39:51 +08:00
 Worktile

动机

“好的代码值得共享”

“快速完成第一版的原型,快速迭代”,如同许多初创 Sass 公司一样,我们也同样信奉这个时代快速迭代的开发方式,按照设计,我们第一个上线的版本是我们的 Web 版以及 iPhone 端,紧接着,我们面临着需要做 Android 移植开发的需求,这时摆在我们面前的有几个纠结: 如果开放 iPhone 的源码给 Android 的同学 “翻译” 一遍 iPhone 的工程了话可能会面临同样的一个 Bug 被 duplicate 了一遍,然后 iPhone 的改了,再建个任务给 Android 的同学 - “ Hi, 我们这里改了一个 Bug, 你们也改改吧”,然后每做一个模块,再各自产生一堆的 Bug ,再疯狂的改 Bug - 好的代码没有被复用,只是 Bug 被一次又一次的提上日程。而且在快速迭代中,我们需要用很少的人力(1 iOS, 1 Android)来完成初期版本的开发,而且在快速的迭代过程中,我们需要频繁的面对诸如接口变动,某个类添加了一个字段这种需求,所以我们自然开始探索起一份跨平台的解决方案。

在探索了当前主流的跨平台技术路线中, runtime 方式跨平台的(如嵌入一个 WebView)方式由于其性能有明显的滞后感并没有列入我们的考虑范围,我们主要考虑了使用 C++ 这种各个平台都支持的方案以及“翻译系”的方案(j2objc 等) 后,针对我们的背景: 开发人员比较少,而且之后招聘到的人员应当是以原生平台语言为主 (这点在事后被证明创业公司非常需要考虑,比如做 iOS 开发的招到一个会 Swift 的也会 Java 的相对来说还是很困难的),最终决定使用 C++ 11 作为核心库的语言 (核心库指的是 MVC 中 Model 层的所有代码)。

在 1 年半的实践中, C++ 11 带来的好处主要有 稳定: C++ 的方法几乎不会出现 deprecated 的状况,相对于我们 iOS 使用 Swift 几乎每次 Swift 都有代码迁移的工作, C++ 的代码部分极其稳定 性能: 这点其实在对性能要求相对较低的 App 开发领域,其实不是特别特别需要考虑的问题 容易搜索: 作为一门历史悠久的成熟语言,大部分的问题都可以 Google 出来 (这点其实也是非常重要的) 单元测试: 依赖于 gtest ,单元只需要写一遍, 并且可以运行于所有的平台之上 (单元测试是我们目前发现的唯一一种可以保证代码质量的方法) 有现成的代码规范: 基于 Google C++ Code Style 以及其提供的 lint 检测工具,我们可以很大程度上保证 C++ 代码的可读性,这份 Code Style 很好的解决了 C++ 内存管理部分难以判断的问题

方法

“ C++ 11 是一门全新的语言”

C++ 在 iOS 上可以通过 Objective-C++ 的形式进行几乎原生的调用,并且由于 C++ 11 Smart Pointer 的出现,几乎不需要进行额外的内存管理。

在 Android 平台上, C++ 是通过 NDK 进行的调用,对于 Java 的开发者来说, C++ 仍然是一门有着比较陡峭的学习曲线的语言,但是在工程开始初期,团队只需要 1 名 C++ 的编写者,所以还是有比较充分的学习时间留给 Android 开发的同学。

在成功的 Hello World 之后接下来就是考虑一些常用模块的迁移 (这里也是一个极其重要的需要预先调研的地方,如果一个功能的第三方库没有找到很好的 C++ 的替代品,那么用 C++ 自行实现一次有时候会是一个非常巨大的成本)

对于我们常用的网络链接、缓存等功能,都已经有一些现成的成熟第三方库可以满足我们,对于 App 开发,常见的有:

HTTP 网络连接: (libcurl)

SQLite 持久化存储(easySqlite)

JSON 解析 (json11)

XML 解析 (tinyxml2)

Websockets (libwebsockets)

Key-value 缓存 (levelDB 或者用 SQLite)

结构

如上图所示,我们将所有复杂的核心逻辑都写在了 C++ Core 这层, Objective-C++ 和 Java Wrapper 只是简单的将 C++ 的方法以 Objective-C 和 Java 的形式暴露给了 App Developer 进行调用 (Win C++ 可以直接调用标准 C++,只需要 dll import/export 好了对应的代码就行)。对于 UI 层的界面代码,我们仍然使用 Swift 以及 Java 进行书写,这样可以保证我们最大可能的能获取原生 App 带来的好处,以及对系统自身的 API 访问的便利性,而且原生的 App 开发者在进行产品布局等改动的时候也能最大程度的获得原生平台的大量的第三方库的帮助。

示例代码

本篇我们将提供最简单的 iOS 以及 Android 示例代码 来阐述我们的结构。

下一节

下一节中我们将以 Worktile OpenAPI 介绍我们是如何搭建一个包含网络请求、缓存的应用。

再下一节

下一节中我们将介绍我们如何使用代码自动构建工具构建出我们的 Model 层代码以节约反复编写同样结构代码的时间。

2130 次点击
所在节点    问与答
8 条回复
chmlai
2016-04-12 15:44:32 +08:00
不错啊
matsuijurina
2016-04-12 16:02:47 +08:00
确实有很多好处,首先就是方便封装多平台 sdk ,其次开发 windows 桌面客户端水到渠成。但是对核心技术团队水平要求很高,在安卓和 ios 平台有差异化需求的时候,也会有些麻烦。
3dwelcome
2016-04-12 16:13:32 +08:00
个人感觉,业务代码大量用 c++并不是一个太明智的选择,还不如对 lua 之类的做个封装。

in-house script 才是比较适合面向业务的语言。
lovelypeople
2016-04-13 10:38:18 +08:00
@matsuijurina 嗯,这个选择的确和我们团队的技术背景有关(之前做地图引擎,熟悉 OpenGL ES 以及 C++),在平台有差异化的需求的时候,我们会通过平台宏来分开实现 (#if WTC_PLATFORM == WTC_PLATFORM_IOS)。
lovelypeople
2016-04-13 10:41:42 +08:00
@3dwelcome 嗯,确实在团队扩张的时候我们面临了招聘相关方便的困难,不过在我们准备的第三篇稿中我们将会阐述下我们的 model-builder (描述好类的形态后直接构建相应的 C++, Objecitve-C 以及 Java/JNI 的代码),所以只需要第一次把代码的形态定型,后面超过 90% 的工作都是比较 smooth 的 (嗯,因为我们之前这个 builder 只是内部使用,现在正在编写文档,会在第三节中再介绍它)
nut799
2016-04-20 17:27:23 +08:00
感觉 ui 层,每个平台(android,ios)的各自开发还是无法避免。有没有什么好的方法?
lovelypeople
2016-04-21 15:17:29 +08:00
@nut799 我们并没有发现什么很好的办法目前,因为几乎无论我们选择了何种"翻译式"的方案 - JS 翻译成 swift 再运行类似的原理,我们最终都面临着自己封装一些组件的问题,并且我们觉得一个 iOS 一个 Android 的配置似乎省不掉。
ddr1984
2017-04-24 13:39:44 +08:00
另外一个问题: 如果图片 app,大图片存储这块,在哪里做? c++实现一个本地文件存储管理吗?因为用 SQLite 应该会比较慢。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/270470

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX