问题背景

Linphone 是一个基于 Sip 协议开源的音视频通话开源软件,其 LinphoneCoreLinphone 的核心库,我们的项目中用到了 Linphonecore 以及基于其封装的 LinphoneManagerlinphone 原有的项目文件比较乱,而且其 linphoneManager 有很多自己的 APP 的业务逻辑,甚至还有部分页面的逻辑。涉及到Linphone 源码的修改,编译一次需要的时间也比较长,我们项目本身有 Cocoapods 私有库的支持,如果能将经过进一步封装后的代码通过其管理起来,使用者将非常方便。

编译 Linphone

通过 Git 克隆源码

1
git clone git://git.linphone.org/linphone-iphone.git linphone-iphone

下载完毕后,检出 4.0.1 版本,仔细阅读其 readme.md 文档,安装 brew ,修改源码(如果不需要可以跳过),我们需要修改两处源码:

  • 修改 Useragent 格式 查找 linphonecore.c,找到方法 linphone_core_set_user_agent 将默认的useragent格式占位由%s/%s改为%s%s,注释代码lc->sal->appendStackStringToUserAgent();

  • 修改被叫编码默认为 g729,将下列代码添加 \linphone\src\sal\call-op.cpp 文件下 void SalCallOp::sdpProcess()这个函数里面。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    bctbx_list_t * pt_it;
    bctbx_list_t * pt_g729;
    bool_t find_g729 = false;

    for (pt_it = mResult->streams[0].payloads; pt_it != NULL; pt_it = pt_it->next)
    {
    PayloadType* pt= ( PayloadType* ) pt_it->data;
    if (payload_type_get_number(pt) == 18)
    {
    PayloadType *matched = payload_type_clone(pt);
    pt_g729 = bctbx_list_new(matched);
    find_g729 = true;
    break;
    }
    }
    if (find_g729)
    {
    bctbx_list_free_with_data(mResult->streams[0].payloads,(void (*)(void *))payload_type_destroy);
    mResult->streams[0].payloads = pt_g729;
    }

    截图如下:

    Screen Shot 2019-03-13 at 6.17.30 PM

  • 注意!iOS12 以上这版本直接编译会报错

    根据提示查看 config.log 我们可以看到错误为

    1
    2
    3
    4
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.1.sdk -m64 -arch x86_64 -o /var/folders/bn/56s0mw415fq19vwqshrf6psr0000gn/T//vpx-conf-75453-12579.x /var/folders/bn/56s0mw415fq19vwqshrf6psr0000gn/T//vpx-conf-75453-12579.o -lpthread
    clang: warning: libstdc++ is deprecated; move to libc++ with a minimum deployment target of iOS 7 [-Wdeprecated]
    ld: library not found for -lstdc++
    clang: error: linker command failed with exit code 1 (use -v to see invocation)

    修改路径下/submodules/cmake-builder/configs/config-ios.cmake,找到 # vpx这一行增加编译配置如下

    1
    2
    3
    4
    # vpx
    lcb_builder_linking_type(vpx "--enable-static" "--disable-shared")
    lcb_builder_extra_cxxflags(vpx "-stdlib=libc++") # not use lstc++
    lcb_builder_extra_ldflags(vpx "-stdlib=libc++") #
  • 编译设置 ./prepare.py

  • 修改环境变量 export PATH=/usr/local/bin:$PATH

  • 编译SDK ./prepare.py -c && ./prepare.py && make

    经过漫长的等待后,可以在 linphone 的目录下找到 liblinphone-sdk 目录,里面有编译好的各个平台版本的 SDK。

    Screen Shot 2019-03-13 at 8.44.59 PM

    选版本apple-darwin,可以看到 Frameworks 里面打好的架包,拷贝出来作为下面的备用文件。

抽离逻辑

LinphoneManager 中有大量Linphone本身app业务逻辑,删除他们,只保留最核心的代码。精简完后,只剩下这些文件

Screen Shot 2019-03-13 at 6.25.41 PM

编写框架的 Cocoapodspec

LiphoneManager 依赖了 framworks,我们新建一个框架库的 cocoapodspec 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Pod::Spec.new do |s|
s.name = "LinphoneDependency"
s.version = "0.1.2"
s.summary = "Linphone dependency frameworks"
#s.description = ""
s.homepage = "http://192.168.40.32:8000/PrivateCocoapods/linphoneSDKDependency"
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'youname' => '***@111.cc' }
s.source = { :git => 'ssh://git@192.168.40.32:10022/PrivateCocoapods/linphoneSDKDependency.git',:tag => s.version.to_s}
s.requires_arc = true
s.ios.deployment_target = '8.0'
# s.source_files = 'LinphoneDependency/*'
s.vendored_frameworks = 'LDependency/*.framework'
end

完成后将其push到私有库

1
pod repo push privateSpecs

目录结构如下

Screen Shot 2019-03-14 at 11.10.45 AM

  • 创建 LinphoneManager的私有库,其实本身 linphoneManager 的封装是比较烂的,即使去除了很多代码,但是上层还是有需要直面 liphonecore API 的尴尬问题,所以自己使用的话最好是对 linphoneManger 做一次封装。

  • 执行命令 pod lib create linphone

  • 修改 podspec 如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    Pod::Spec.new do |s|
    s.name = 'LinphoneSDK'
    s.version = '0.1.2'
    s.summary = 'LinphoneSDK(4.1.0) for iOS'

    # This description is used to generate tags and improve search results.
    # * Think: What does it do? Why did you write it? What is the focus?
    # * Try to keep it short, snappy and to the point.
    # * Write the description between the DESC delimiters below.
    # * Finally, don't worry about the indent, CocoaPods strips it!


    s.homepage = 'http://192.168.40.32:8000/PrivateCocoapods/LinphoneSDK'
    s.license = { :type => 'MIT', :file => 'LICENSE' }
    s.author = { 'youname' => '**@email.com' }
    s.source = { :git => 'ssh://git@192.168.40.32:10022/PrivateCocoapods/LinphoneSDK.git', :tag => s.version.to_s }

    s.ios.deployment_target = '9.0'

    s.source_files = 'LinphoneSDK/Classes/*.{h,m}'

    s.public_header_files = 'LinphoneSDK/Classes/*.h'
    s.frameworks = 'UIKit','AVFoundation','SystemConfiguration','AudioToolBox','CoreTelephony','AssetsLibrary'
    s.libraries = 'sqlite3'
    s.xcconfig = {
    'VALID_ARCHS' => 'arm64 x86_64',
    }
    s.pod_target_xcconfig = {'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES'}
    s.dependency 'LinphoneDependency'

    end

    这里的重点是 s.dependency 可以指定依赖的库。

    • 执行 pod lib lint --sources=ssh://git@192.168.40.32:10022/PrivateCocoapods/SpecRepository.git --verbose --use-libraries 如果出现问题增加 --no-clean 参数,可以看到对应路径下 pod 生成的 xcode project,更能准确定位稳定,注意因为 linphoneManager 必须在头文件中引用 linphone/linphonecore ,必须指定 --use-libraries 参数,这个参数是打包为静态包,不是打包为 framworks,指定 --sources 是因为依赖库是放在私有库的,不是 cocoapods 官方库。
    • 执行通过后,将完成的代码提交到 git 仓库,并打好 Tag
    • podspec 提交到私有库 pod repo push privateSpecs LinphoneSDK.podspec --use-libraries --allow-warnings

    完成测试

    在你的 podfile 顶部中增加私有库源

    1
    2
    source 'https://github.com/CocoaPods/Specs.git'  # 官方库
    source 'ssh://git@192.168.40.32:10022/PrivateCocoapods/SpecRepository.git' #私有库 库

    添加依赖pod 'linphone' 执行就可以了。