WebRTC入门:iOS工程

作者: kim4apple | 来源:发表于2017-01-06 11:43 被阅读3695次

    刚进到新的项目组,就接到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/

    1. 获取depot tools, 并且配置好环境。http://dev.chromium.org/developers/how-tos/install-depot-tools

    2. 获取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_objcrtc_sdk_framework_objc目标的配置。选择性添加Framework文件夹的代码文件。

    原工程使用gn文件进行配置。如前面所提的,大量配置变量分布在下面几个文件夹内。

    • /build
    • /build_overrides
    • /webrtc/build

    以下是踩过的坑:

    1. 打包后libjingle_peerconnection_all包含了rtc_sdk_common_objc。所以不能添加rtc_sdk_common_objc的代码。注意导出的头文件,只有部分是公开头文件。
    2. 需要根据环境配置宏。指定各种编译配置和定义宏。
      1. 关闭bitcode。
        2)关闭rtti。
        3)增加-all_load
        4)增加WebRTC_OC/Info.plist
        5)指定module map: Framework/Modules/module.modulemap
      2. 设置search path: 具体看工程。代码使用相对路径,需要添加好搜索路径。
        7)增加prefix pch: $(SRCROOT)/WebRTC-Prefix.pch
      3. 指定C++库版本:libc++
      4. 添加宏 WEBRTC_POSIX, WEBRTC_IOS, TARGET_OS_IPHONE=1
      5. 添加 libjingle_peerconnection_all 库。

    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介绍

    相关文章

      网友评论

      • UninhibitedSoul:楼主 你好
        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
        在第三步 运行时候 报了好几个错 都是同一个类型的,请教一下 有办法解决吗?
        UninhibitedSoul:如果可以的话 我们可以 微信或者qq 交流一下这个问题吗?
        UninhibitedSoul:error: unknown warning option '-Wno-null-pointer-arithmetic'; did you mean '-Wno-null-arithmetic'? [-Werror,-Wunknown-warning-option]
        ninja: build stopped: subcommand failed.
      • 810cd68e3fc5:你好,请问下,可以在ubuntu上下载代码,然后拷贝到mac上编译吗???我要编译旧的分支M58,是直接fetch下来,然后checkout到该分支,再同步,这样的操作流程正确吗,急急急,望回复!
        kim4apple:@810cd68e3fc5 代码库是一样的
      • Kaiserfeng:在webrtc/sdk/objc目录下,对比webrtc/sdk/objc/BUILD.gn文件中的rtc_sdk_common_objc和rtc_sdk_framework_objc目标的配置。选择性添加Framework文件夹的代码文件。
        请问:Classes里面的RTCAVFoundationVideoSource+Private.h,RTCAVFoundationVideoSource.mm跟Headers里面的RTCAVFoundationVideoSource.h有什么区别?他们之间是怎么关联的呢?
        kim4apple:@Kaiserfeng
        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就可以了。
      • 张芳涛:git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git就是这一行命令 报这个错误:unable to access 'https://chromium.googlesource.com/chromium/tools/depot_tools.git/': Failed to connect to 127.0.0.1 port 1080: Connection refused 请问有谁遇到过么?我看网上几乎所有的教程都一样,难道你们都没有遇到过这个问题么?
        kim4apple:@张芳涛 你看我上面 下载源码步骤。因为用了vpn 所以要加curl代理设置。我vpn代理端口是1235。你的是怎么设置的不清楚。 1080是怎么来的?和vpn对上了吗?
        张芳涛:@kim4apple 端口都不是我设置的,就一个命令行我怎么设置端口?
        kim4apple:@张芳涛 端口设置对吗?
      • 张芳涛:为什么我的就连接不上。。。翻墙也没用。。。。
      • Amy莫莫:请问一下这样编译出来的库直接是.a了么?
      • KeepMoveingOn:我设置了代理之后 下载依赖库出现了
        Error: Command 'git -c core.deltaBaseCacheLimit=2g fetch origin' returned non-zero exit status 128 in /Users/wcq/src/third_party/gflags/src

        博主大大知道什么原因吗
      • 0141b3a30678:我的/webrtc/build/ios/build_ios_libs.sh文件不存在,build_ios_libs.sh的实际路径在webrtc/tools-webrtc/ios/下,请问是哪里出了问题?
        tjfeng88:这个路径(webrtc/tools-webrtc/ios/)是对的 直接cd到这个目录 然后执行build_ios_libs.sh就行了 编译过程中出问题 可以贴出来一起讨论
      • Django_Monstar:楼主能不能分享下整理后的库 我这下载了几天了没下好
        kim4apple:@Murphy 我的是1月份的代码了,最新代码已经移动到这个文件夹。
        kim4apple:@tony_Stark 需要翻墙才能下代码。
      • venture0033:OC牛人!!
      • 7aab148ad169:大神!

      本文标题:WebRTC入门:iOS工程

      本文链接:https://www.haomeiwen.com/subject/jpitbttx.html