刚进到新的项目组,就接到WebRTC相关的任务。我们的项目是需要基于WebRTC上做二次开发。而最新版本的WebRTC的工程是基于gn和ninja,每次修改完后,编译成lib或者framework才能进行调试。特别不方便。本文记录的就是分离WebRTC的OC工程的踩坑过程。
注:目前编译通过,但是还是存在内存问题。GN的编译条件还存在差别。暂时还没解决。
0x00 什么是WebRTC?
WebRTC,名称源自网页实时通信(Web Real-Time Communication)的缩写,是一个支持网页浏览器进行实时语音对话或视频对话的技术,是谷歌2010年以6820万美元收购Global IP Solutions公司而获得的一项技术。2011年5月开放了工程的源代码,在行业内得到了广泛的支持和应用,成为下一代视频通话的标准。
官网介绍:https://webrtc.org
0x01 获取源码
第一步就是获取源码。由于不可抗力,需自行备梯。我们的目标是获取iOS版本的代码。原文档:https://webrtc.org/native-code/ios/
-
获取depot tools, 并且配置好环境。http://dev.chromium.org/developers/how-tos/install-depot-tools
-
获取WebRTC iOS版本代码。
$ mkdir webrtc && cd webrtc # 下载源码库 $ fetch --nohooks webrtc_ios # 同步第三方依赖库 $ gclient sync
接下来就是耐心的等待, 代码库大概是6G左右。我获取是1月3号的版本:
d25f79e
。
坑:由于使用了代理。所以需要设置curl的代理配置。否则git无法正常工作。
$ export https_proxy=http://127.0.0.1:1235;export http_proxy=http://127.0.0.1:1235
0x02 编译库
WebRTC是使用GN来生成ninja工程文件的。所以需要了解GN和ninja的基本使用。中文资料很少,但是官网上的教程写得非常好,容易上手。当然你也可以不了解的情况下,直接用下面几个命令就可以编译出WebRTC.framework。
## 生成ninja工程文件
# debug build for 64-bit iOS
gn gen out/ios_64 --args='target_os="ios" target_cpu="arm64" is_component_build=false'
# debug build for simulator
gn gen out/ios_sim --args='target_os="ios" target_cpu="x64" is_component_build=false'
## 编译WebRTC.framework 文件
ninja -C out/ios rtc_sdk_framework_objc
上面的方法可以编译出某一cpu架构版本的库,但是实际开发时需要支持多个cpu架构。
在代码库中已经包含了编译脚本代码。查看/webrtc/build/ios/build_ios_libs.sh
➜ src git:(libwebrtc) ✗ ./webrtc/build/ios/build_ios_libs.sh -h
WebRTC iOS FAT libraries build script.
Each architecture is compiled separately before being merged together.
By default, the fat libraries will be created in out_ios_libs/.
The headers will be copied to out_ios_libs/include.
Usage: ./webrtc/build/ios/build_ios_libs.sh [-h] [-b build_type] [-c] [-o output_dir]
-h Print this help.
-b The build type. Can be framework, or static_only.
Defaults to framework.
-c Removes generated build output.
-o Specifies a directory to output build artifacts to.
If specified together with -c, deletes the dir.
-r Specifies a revision number to embed if building the framework.
-e Compile with bitcode.
➜ src git:(libwebrtc) ✗
官方已经准备好编译脚本,很方便的编译出静态库版本和Framework版本,另外也可以指定其他编译条件,如是否为debug版本,是否开启bitcode。也可以配置更多的其他gn配置参数。详情查看目录:/build, /build_overrides, /webrtc/build 三个目录下的.gni和BUILD.gn内的参数配置。
由于WebRTC项目既是Chrome的子项目又是可以作为独立项目。支持win,linux,android,chorome os,mac,ios。支持多种cpu架构。而且高度模块化,可定制化。所以配置参数特别多。
好消息是,大部分参数才是都已经为我们配置好了。我们无需修改或者修改很少的部分参数就可以使用了。
0x03 准备分离objc工程
小目标:WebRTC.framework的代码放到Xcode工程里面。而其余部分代码使用静态库的方式引用。这样我们只需关注objc部分的二次开发,而无需太多关注c++部分的其他代码。
生成libjingle_peerconnection_all
库
增加jingle_peerconnection_all
目标. 修改/webrtc/BUILD.gn文件。增加以下代码
# 增加新的目标,编译webrtc的c++接口库。(iOS版本还包含了rtc_sdk_common_objc的代码)
rtc_static_library("jingle_peerconnection_all") {
complete_static_lib = true
deps = [
"api:libjingle_peerconnection",
# 需要增加下面2项,参考rtc_sdk_framework_objc配置。
"//webrtc/system_wrappers:field_trial_default",
"//webrtc/system_wrappers:metrics_default",
]
}
修改/webrtc/build/ios/build_ios_libs.sh
脚本。增加编译这个目标的选项-b static_only_cpp
支持。具体见修改后的文件。
# Generate static or dynamic.
if [[ ${build_type} = "static_only" ]]; then
GN_TARGET_NAME="rtc_sdk_objc"
elif [[ ${build_type} == "static_only_cpp" ]]; then ## 增加的条件参数选项
GN_TARGET_NAME="jingle_peerconnection_all" ## 指定我们上面新增的目标
GN_ARGS="${GN_ARGS} enable_dsyms=true enable_stripping=true"
elif [[ ${build_type} == "framework" ]]; then
GN_TARGET_NAME="rtc_sdk_framework_objc"
GN_ARGS="${GN_ARGS} enable_dsyms=true enable_stripping=true"
fi
我们只需输入一下命令,就可以打包生成库了。
$ webrtc/build/ios/build_ios_libs.sh -o out/ios-libs -b static_only_cpp
增加WebRTC_OC工程
在webrtc/sdk/objc
目录增加一个空的iOS工程。对比webrtc/sdk/objc/BUILD.gn
文件中的rtc_sdk_common_objc
和rtc_sdk_framework_objc
目标的配置。选择性添加Framework文件夹的代码文件。
原工程使用gn文件进行配置。如前面所提的,大量配置变量分布在下面几个文件夹内。
/build
/build_overrides
/webrtc/build
以下是踩过的坑:
- 打包后
libjingle_peerconnection_all
包含了rtc_sdk_common_objc
。所以不能添加rtc_sdk_common_objc
的代码。注意导出的头文件,只有部分是公开头文件。 - 需要根据环境配置宏。指定各种编译配置和定义宏。
- 关闭bitcode。
2)关闭rtti。
3)增加-all_load
4)增加WebRTC_OC/Info.plist
5)指定module map: Framework/Modules/module.modulemap - 设置search path: 具体看工程。代码使用相对路径,需要添加好搜索路径。
7)增加prefix pch: $(SRCROOT)/WebRTC-Prefix.pch - 指定C++库版本:libc++
- 添加宏 WEBRTC_POSIX, WEBRTC_IOS, TARGET_OS_IPHONE=1
- 添加 libjingle_peerconnection_all 库。
- 关闭bitcode。
0x04 总结
接触WebRTC的代码,踩坑几天的感受。
- 工程非常庞大。完整代码库达到惊人的6G大小。
- 模块化程度高。分层,分模块。根据我们的需求,只需要关注API层就可以了。
- 感受到gn进行工程配置的强大能力。gn进行多系统,多cpu,多目标,多配置条件。
- ninja部分。模块化编译。增量编译,提高编译速度。
虽然已经分离出OC的工程,但现有工程对完整代码库的依赖:
- 头文件引用。源码是用的是相对位置引用,如果要完全分离头文件,需要改动源码。这个问题不解决,就不能完全分离出库和头文件。
- 头文件导出。需要修改头文件的对外部头文件引用方式。
现有的方式是不修改源码的方式,最小化修改,进行工程分离。
而完全分离,则需要对源码做大量的修改(头文件引用)。
延伸阅读:
What is GN?
GN Quick Start guide
GN Style Guide
The Ninja build system
Have a try on Ninja
WebRTC介绍
网友评论
1.我运行这个 /webrtc/src/tools_webrtc/ios/build_ios_libs.py 脚本
2.在 src/out_ios_libs 文件夹中生成了 arm64_libs文件夹
3.最后我通过 ninja -C out_ios_libs/arm64_libs AppRTCMobile 想要编译出这个App 从而得到Framework
在第三步 运行时候 报了好几个错 都是同一个类型的,请教一下 有办法解决吗?
ninja: build stopped: subcommand failed.
请问:Classes里面的RTCAVFoundationVideoSource+Private.h,RTCAVFoundationVideoSource.mm跟Headers里面的RTCAVFoundationVideoSource.h有什么区别?他们之间是怎么关联的呢?
1. 编译framework包含2部分: 头文件和库。
2. 头文件在工程中分2种:公开和私有。
3. 库:编译库需要头文件和实现文件。看BUILD.gn 中rtc_sdk_framework_objc是要依赖rtc_sdk_peerconnection_objc目标。而rtc_sdk_peerconnection_objc依赖rtc_sdk_common_objc。
所以,WebRTC.framework是由静态库rtc_sdk_peerconnection_objc+公开头文件组成。私有头文件在Xcode中Build Phases的Headers的project或者private就可以了。
Error: Command 'git -c core.deltaBaseCacheLimit=2g fetch origin' returned non-zero exit status 128 in /Users/wcq/src/third_party/gflags/src
博主大大知道什么原因吗