组件化-动态库实战续

原文地址 ,此简书只做备份,强烈推荐原文,毕竟格式比简书好看,还清晰

回忆之前

上篇文章中我们已经完美的解决了 使用swift第三方库 ,使用混编的组件,使用use_framework!,但是会带来别的问题。
果然是生命不息,折腾不止啊。

不建议在组件化的项目中使用Swift来写业务。

Q: C++/C 静态库依赖问题
A: 回想下我们在做C或者C++开发的时候。如果一个静态库依赖另外一个静态库(A依赖B)。那么被依赖库B升级的时候A用重新编译吗? 不一定,如果是一些方法的新增,维护,不一定会让A重复编译;但是如果修改了B里面的数据结构,A里面又用到了这些数据结构,那么很大可能性我们就要重新编译A了。
Q: Objective-C 静态库依赖问题
A: 回想下我们在iOS中出现上述的依赖问题,貌似也没有见到要重新编译A的情景。主要是Objc2.0引入了 non-fragile特性,同时OC是严重依赖于Runtime的,只要接口兼容,就算你修改了B中的数据结构,一般也是不需要重新编译A的。如果你不明白non-fragile 请看文后的参考链接
Q: Swift中库依赖问题
A: 由于Swift不和OC一样,所有的OC方法都是通过Runtime动态调度的。Swift对于方法是存在静态调度和动态调度2种的。所以Swift的库依赖极易引起二进制兼容性问题。更多关于Swift库二进制接口(ABI)兼容性问题,请参考文后链接。

Q: 为什么不建议在组件化的项目中使用Swift或者和OC混编来写业务?
A: 首先在组件化初期的时候,我们能做到的一般是基础库抽离,业务组件分离这些。但是一般来说我们这时候的壳工程,接入这些分离的组件的时候都是使用源码接入,这时候问题暂时显现不出来。
第二步。当我们的组件化的脚步越走越远的时候,我们出于多方面的考虑可能有以下需求。

  1. 开发时重复编译是痛点。我们可能更希望提供的是二进制版本,节省下大量的编译耗时;
  2. 我们可能要做权限管理。有时候一个公司业务和人员规模都非常庞大。我们基础库设计到跨业务,跨APP使用。我们希望不同团队有不同基础组件的读写权限。那么我们更可能偏向提供二进制库加文档的形式。

综上: 由于使用Swift开发ABI不兼容问题更易出现。在组件化的项目中,不建议使用Swift或者混编。

动态库过多问题

上面说到的问题(麻烦)其实是带给开发者的麻烦,但是动态库多了会给用户带来麻烦(APP启动耗时)。用了混编的项目我们在Podfile里面势必要写use_framework!,上篇文章中我们也说到用了这个指令。CocoaPods会帮我们把所有的库全部编译为动态库。这些动态库是在APP启动时做去加载的。我们在组件化的时候,自己的业务组件马上接近上百个。可以预想到以后随着组件化的越来越深入,这些库会越来越多。这个时间可能会达到1s的量级。对于用户 这是不可接受的。关于动态库过多导致的启动慢的问题请参考文后的参考链接。

结合公司目前的情况的解决方案

我们公司目前的情况: Swift第三方库个别,混编组件个别。既然都是个别的,我们总不能因为这些个别的特殊case让APP原本的1个二进制文件变成 1个二进制文件+上百个动态库framework。这肯定是不合理的。
解决办法

  1. 不使用Swift,包括第三方库和混编组件
  2. 部分组件(含有Swift)动态库化,其他部分仍旧整合进app的二进制中
    首先来看办法1直观感觉是不合适。首先很多公司的项目在做组件化的时候项目已经达到一定程度(没有一定规模也没必要做组件化),这就意味着大部分APP是有历史包袱的。首先重写这些已有的组件或者功能肯定是有风险的,在公司业务多。用户量大的情况下,影响面会更大,虽然这样是一劳永逸的,但是同时风险是更大的。我们在做组件化的工作中,改善大家开发的痛点,提高开发效率才是主要目标。至于重构甚至重写则是业务方的重心。
    第二种办法就是做到部分组件动态库化。
    我们来回忆下静态库的特点。静态库和主工程链接的时候会把库里面的代码复制到可执行文件中。对于这部分符号在APP启动时会省去load,rebase ,binding的时间。那么在iOS平台中嵌入式动态库的特点是不把库里面的代码复制到可执行文件中,而是单独复制到APP里面的frameworks路径下。所以通常来说动态库节省内存。在iOS平台上做不到。静态库的缺点是会让APP安装包增大。那么我们自己做的嵌入式动态库也会有这个问题。并且还会导致APP启动变慢。那岂不是优点变成了缺点~~.
    以上讨论只在正常项目且上架到APP Store渠道,越狱开发和企业版证书发布不做讨论

组件化部分动态库实战

上篇文章中我们知道 只要你的组件库中使用到了Swift。以源码的方式提供给壳工程使用的时候一定要加上use_framework!, 那么就变成前文说到了上百个动态库了。 那么我们如果不以源码的形式引入呢。对于这些含有Swift的下层组件是无依赖的。我们直接将其编译为动态库提供二进制。那么我们在主工程使用的时候就不需要加入use_framework!.

#use_frameworks!

source 'https://github.com/ValiantCat/LJWXSDK'
source 'https://github.com/CocoaPods/Specs.git'  #官方仓库的地址



target 'LJA_Example' do
  pod 'LJA', :path => '../'
  pod 'LJB', :path => '../'

    pod 'LJCharts'
end

那么我们拉下来的项目结构是这样的

项目结构

但是我们运行发现libswiftCore.dylib无法加载。
swift库加载失败

出现这个原因呢是因为Xcode不知道你使用了Swift代码,所以并没有把Swift的运行时环境(也就是swift运行的动态库)复制进APP目录。那么解决办法其实很简单。我们在壳工程新建一个swift空文件即可。
以下是主工程是否有swift文件APP目录下动态库的对比
没有swift文件

有Swift文件

到这里其实这篇文章就好了。剩下的其他组件就继续使用静态库即可。我们可以愉快的玩耍了。

未解决的问题

前面说的问题文中已经解决。但是我觉得有一点不爽。那就是我还需要手动得在壳工程添加空的Swift文件。那么我们能不能这一步也自动化呢。
首先我建了一个空工程,往里面添加了一个空的Swift文件。然后diff了一下两次的project文件。
以下是diff结果


工程文件对比结果

我们知道podspec和Podfile其实都是ruby代码。Xcode如何知道我们是否有swift其实也是通过工程的配置来知晓的。那么我们其实可以在Podfile去写ruby代码修改工程文件。这样的话使用方就不需要疑惑为什么要加个空的swift文件了。
以下是代码

# Pod设置 =================================

def update_config (config)

  config.build_settings['CLANG_ENABLE_MODULES'] = 'YES'
  config.build_settings['SWIFT_VERSION'] = '3.0'

  # config.target_attributes["LastSwiftMigration"] = "0830"

   if config.name == "Debug" then
      config.build_settings['SWIFT_OPTIMIZATION_LEVEL'] = '-Onone'
   end

#    elsif config.name == "Release" then
#    config.build_settings['CLANG_ENABLE_MODULES'] = 'YES'
#    config.build_settings['SWIFT_VERSION'] = '3.0'
#    end
end

post_install do |installer|


    projects = [
    "SwiftConfig"
    ]

    projects.each do |proj|
        path = "%s.xcodeproj" % [proj]

        single_project = Xcodeproj::Project.open(path)

        single_project.targets.each do |target|

            target.build_configurations.each do |config|
                print path, ' ', target.name, ' ', config.name
                puts ""

                update_config config
            end
            target.attributes.methods.each do |xx|
              puts xx
            end
        end

        single_project.save
    end
end

不过加入这段代码后发现。我虽然确实成功的修改了工程文件。但是发现Xcode依旧没有把Swift运行时的库给我复制进APP里面。
所以这还算是一个不完美的地方。后续有结果的话更新此文。

参考

  1. 文中的示例代码
  2. Objective-C类成员变量深度剖析
  3. Swift库二进制接口(ABI)兼容性研究
  4. Swift 性能相关
  5. 今日头条iOS客户端启动速度优化实践
  6. 将Swift代码编译为静态库
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容

  • 原文地址 ,此简书只做备份,强烈推荐原文,毕竟格式比简书好看,还清晰 起因 去年,链家网iOS端,之前由于所有的业...
    南栀倾寒阅读 12,258评论 29 130
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,022评论 4 62
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,498评论 25 707
  • 摄影之于我,可能是记录回忆。可能是浪迹天涯的手段。 我记性不好,回来家和朋友说起小时候,她说我们一起趴...
    远方的雨季阅读 251评论 1 0
  • 楔子 七是个神秘的数字,和七有关,总会发生不好的事,七个人的事。 第一章 夜黑风高,飒飒的风胡乱的吹着,硬逾精钢的...
    莫亘离荒阅读 1,849评论 0 0