阅读 324

网易技术干货 | 云信跨平台C++ SDK开发实战

1. 序 言

2018年,Flutter Release正式发布,将移动端跨平台开发技术再一次推上风口浪尖。2019年5月,Flutter 1.5正式支持Web开发,而预告中正在开发的Flutter for Desktop以及对于嵌入式的支持,使得Flutter最终目标将不再是移动框架,而是一个跨平台、多平台框架。再往前推数年,RN、小程序已经是移动端生产开发中常见的跨平台开发技术,Electron、Qt也逐渐成为当前桌面端跨平台应用的首选技术方案。
综上所述,在客户端一次编写,多处运行的大趋势下,底层SDK服务能力的跨平台化、多平台化就显得更为重要和自然。
云信SDK提供有iOS/OSX、AOS、Windows、Linux、Unity等常见平台的支持,从长期的开发维护中得到的经验,我们认为底层能力的跨平台化应该解决如下痛点:
  1. SDK接口在各平台上不统一,包括接口的命名、传参,对外部开发者不友好。
  2. SDK功能在各平台上由不同团队维护,需求需要反复沟通保障实现上的统一,使得产品迭代速度很慢。
  3. 如果团队之间没有有效的沟通,面对同样的需求和能力,不同的实现方案,测试团队往往需要设计不同的测试用例,降低了产品迭代效率。
当然,跨平台开发也有一些不足,比如跨平台代码往往需要引入第三方库,不如原生平台编写的代码精简,遇到与设备相关的逻辑,还是避免不了需要采用原生代码编写插件的形式来提供能力等等。

2. 架构介绍

网易云信C++ SDK目前还只支持Windows平台,架构设计如下图:
  • third patry:引入的三方库。
  • 组件层:SDK开发框架的根基,提供对通信套接字、本地缓存、加/解密、线程模型、日志等基础功能组件,并对引入的三方库进行二次封装。
  • SDK业务实现层:包含了所有SDK业务逻辑的实现,SDK内部线程的管理等。
  • SDK接口层:对外暴露SDK各功能接口并提供c++封装层
nbase整合自chromium开源项目中的一部分,是长期支撑云信Windows客户端SDK的基础库,包含了基本框架Messageloops,闭包,基本函数库(file、network等),基本类库(time,线程,定时器等),基本工具库(log,加解密)等,功能丰富,但是目前仅支持和适配了Windows平台,并不能很好的支撑其他平台的开发,因此改进和改造nbase模块是我们跨平台开发过程中最先考虑的。

3. 跨平台改造

nbase模块与SDK的实现已深度的耦合,此次改造我们提出了以下几个目标:
  1. 对上层业务代码最少的改动,最好是不要改动。
  2. 可方便更换跨平台框架,虽然我们选择了Chromium base作为我们开发框架,但是有可能会随着Chromium的迭代而对跨平台框架进行升级/降级,或者为满足特殊设备改用其它跨平台方案。
基于以上两点考虑,我们把原来nbase模块抽象为框架适配层,将引入的跨平台框架进行隔离,nbase模块不再实现任务具体功能,只是对跨平台框架的二次封装,在最大程度上减少上层代码的改动。
改造后的结构图:

4. 改造之路

4.1. 规范化编码
除了遵循Google cppguide外我们还整理了与我们SDK开发相关的一些规则:
  1. 头文件: 为了避免某些编译器编译失败,包含的头文件不能使用‘\’,必须全部使用‘/’,不要使用#pragma once ,使用#ifndef _XXX_H_ #define _XXX_H_ #endif,头文件目录必须从顶层目录开始,比如’core/core/nim_core.h’。
  2. 命名空间: [namespace]_BEGIN_DECLS/[namespace]_END_DECLS/ USING_NS_[namespace] 替换原先的命名空间定义。
  3. 导出API/类: XXX_EXPORT,导出的类和函数都要加上这个宏。
  4. 规范系统定义: OS_WIN/OS_MAC/OS_LINUX/OS_ANDROID/OS_IOS尽量不要直接使用系统自带的宏 比如WIN32。
  5. 规范各平台实现的区别: 通过文件后缀来区分,比如 platform_device_win.cpp、 platform_device_android.cpp等。
  6. 字符串编码格式的标准化: 使用 std::string/UTF8String/UTF16String/UTF32String。
4.2. base库的编译
参考官方文档Checking out and Building Chromium for Windows
chromium原生采用的是Ninja的脚本编译,我们并没有进行直接的生成,而是选择自行搭建Visual Studio/XCode项目,这样做的目有两个:
  1. 方便集成到我们的工程调试,在开发过程中经常会碰到这样那样的问题,所以调试是必不可少的步骤。
  2. 为了后续对base库的精简和可控打下基础。
目前支持的平台是Windows/IOS/MacOS三个平台的编译,Android/Linux在后续安排开发。编译步骤基本就是创建新项目,把所有代码文件加入到项目,然后再剔除非该平台的代码文件,各平台都适用这步骤。
4.3. extention库
前面提到把原来nbase模块抽象为框架适配层,我们料想到这个过程无法在一个迭代周期内完成,所以采用分批适配的方式来进行,于是我们又定义了extension库(同属nbase命名空间)来对nbase库进行抽象,同时对base库的一些功能进行外围补充补充。
4.4. 对windows xp的支持
自2014年4月8日之后,微软不再提供 Windows XP技术帮助,但并不代表用户可以马上升级到新的windows操作系统,尤其我们的SDK可能会用于多个行业,对于某些行业用户来说支持Windows XP是硬性需求,经过几次讨论后,我们发现目前还不可以放弃Windows XP系统,前面提到,我们选择使用Chromium base (v71.0.3578.98)做为我们跨平台开发框架,而支持Windows XP系统的chromium版本是“49.0.2623.112”,得益于nbase库抽象为框架适配层,跨平台开发框架很快的切换到了chromium 49版本。在编译支持XP版本时我们需要设定以下几个配置:
  • Windows SDK 改为使用7.0
  • WINVER = 0x0501
  • PSAPI_VERSION = 1

5. 经验分享

网易云信目前已经开发完成并上线了跨平台C SDK,从一开始的开发跨平台C SDK到如今的对C++ SDK的跨平台改造,开发小组也接触了许多C++开发领域常见并熟识的跨平台基础库,例如stl、boost、Poco、folly等,内部也对几个基础库做过详细的对比,首先根据我们的SDK业务需求,以及对平台的需求,如果我们做到跨平台需要满足以下几个最基本的需求:
Facebook 的 folly库应该也是个很好的选择,但由于时间关系没有去整理,看介绍,这个库为了效率重造了很多轮子,估计会有很多诡异的实现,所以并未进入对比范围。
  • chromium base + net
资料文档较少,支持我们所需的各种平台,代码较复杂,完整的base库较大,使用或修改对C++泛型编程与模板元编程要求较高
  • Boost
资料文档丰富,支持我们所需的各种平台,代码还算简捷,可以有选择的引入库,有些功能需要配合其它三方库来完善,使用起来与STL相差不大
  • Poco
资料文档丰富,支持我们所需的各种平台,代码简捷,从功能上来说比较全
POCO c++library:pocoproject.org/

6. TO DO

目前,云信跨平台SDK已经支持Windows(xp+)、OSX、iOS平台,我们计划2019年Q4完成对Linux部分桌面发行版的开发支持工作,2020年Q1完成对AOS的开发支持工作,后期也会增加对常见的小型设备的开发支持工作。此外,为了方便开发者快速接入SDK,我们将在2019年Q4上线基于跨平台SDK封装的ElectronSDK,2020年上半年上线FlutterSDK。
跨平台SDK本身很多组件或思想来自于开源社区,未来我们计划开源跨平台开发框架,通过回馈开源社区,希望继续与社区一起打造好玩的“轮子”,大家可以先关注https://github.com/netease-im/phoenix。开源该技术提高了产品团队与开发者之间的透明度,有助于跨平台开发的普及,并使开发者能够参与并对这些开源技术做出持续贡献。
最后,感谢曾经以及如今还在为网易云信跨平台SDK贡献代码的小伙伴们,包括但不限于rg,gg, harrison等等大佬们。

7. 传送门