写点什么

组件化:动态库实战续

  • 2019-09-20
  • 本文字数:3178 字

    阅读完需:约 10 分钟

组件化:动态库实战续

上篇文章中我们已经完美的解决了使用 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 或者混编。


Q:动态库过多启动较慢问题 A: 上面说到的问题(麻烦)其实是带给开发者的麻烦,但是动态库多了会给用户带来麻烦(APP 启动耗时)。用了混编的项目我们在 Podfile 里面势必要写 use_framework!,上篇文章中我们也说到用了这个指令。


CocoaPods 会帮我们把所有的库全部编译为动态库。这些动态库是在 APP 启动时做去加载的。我们在组件化的时候,自己的业务组件马上接近上百个。可以预想到以后随着组件化的越来越深入,这些库会越来越多。这个时间可能会达到 1s 的量级。对于用户这是不可接受的。关于动态库过多导致的启动慢的问题请参考文后的参考链接。

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

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


1. 不使用 Swift,包括第三方库和混编组件


2. 部分组件(含有 Swift )动态库化,其他部分仍旧整合进 app 的二进制中


首先来看办法


直观感觉是不合适。首先很多公司的项目在做组件化的时候项目已经达到一定程度(没有一定规模也没必要做组件化),这就意味着大部分 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 无法加载。



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




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

未解决的问题

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



我们知道 podspec 和 Podfil e 其实都是 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" ifconfig.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'# endendpost_install do |installer| projects= [ "SwiftConfig" ] projects.eachdo |proj| path= "%s.xcodeproj"% [proj] single_project= Xcodeproj::Project.open(path) single_project.targets.eachdo |target| target.build_configurations.eachdo |config| printpath, ' ', target.name, ' ', config.name puts"" update_configconfig end target.attributes.methods.eachdo |xx| putsxx end end single_project.save endend
复制代码


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


本文转载自公众号贝壳产品技术(ID:gh_9afeb423f390)。


原文链接:


https://mp.weixin.qq.com/s/6xDlSnxug51g3ThYoM-gcA


2019-09-20 09:571388

评论 1 条评论

发布
暂无评论
发现更多内容

《Operating System Concepts》阅读笔记:p512-p527

codists

操作系统

反向海淘代购中二次付款难题的深度解析与解决之道

代码忍者

天下拍-艺术品拍卖经典案例分享

至存网络

埋点 拍卖 用户画像 艺术品拍卖 资产拍卖

Flink批处理自适应执行计划优化

Apache Flink

大数据 flink 实时计算 批处理

C 语言宏定义原来可以玩出这些花样?高手必看!

伤感汤姆布利柏

为什么 Apache Doris 是比 Elasticsearch 更好的实时分析替代方案?

SelectDB

搜索引擎 全文检索 elasticsearch 日志分析 Doris

电竞革命!电选对平台狂省90%硬件费:ToDesk云电脑、网易云游戏等终极评测

小喵子

云电脑 ToDesk云电脑 云电竞

通义灵码 Rules 来了:个性化代码生成,对抗模型幻觉

阿里云云效

阿里云 云原生

「高盛」最新人形机器人研报:主流人形机器人公司梳理和商业化瓶颈(附报告)

机器人头条

机器人 科技 大模型 人形机器人 具身智能

C 语言内存布局深度剖析:从栈到堆,你真的了解吗?

不在线第一只蜗牛

C#

HarmonyOS NEXT 中级开发笔记:电器管家应用的数据库设计与操作实践

bianchengyishu

HarmonyOS NEXT

开源最强!DeepClaude使用方案,内含DeepsSeek无门槛部署方法

ModelWhale

#人工智能 #大数据 #大语言模型 DeepSeek

突破公网瓶颈的专线选择:IPLC专线

Ogcloud

企业组网 IPLC 国际专线 国际网络专线 国际IPLC专线

Databend 产品月报(2025年3月)

Databend

EviMed:左手综述内容,右手参考文献!三步产出可溯源的万字医学综述!

科技汇

API 安全之认证鉴权

阿里巴巴云原生

阿里云 云原生 API

时序数据库 IoTDB 荣获第八届中关村国际前沿科技大赛工业互联网领域赛 Top3

Apache IoTDB

通义灵码 Rules 来了:个性化代码生成,对抗模型幻觉

阿里巴巴云原生

阿里云 云原生

HarmonyOS NEXT 中级开发笔记:电影票务应用的数据库设计与实践

bianchengyishu

HarmonyOS NEXT

字节开源轻量级 TTS 模型 MegaTTS3,中英切换自如;面壁首个纯端侧智能助手「上车」,支持多模态交互丨日报

声网

数据分析与AI丨基于AI的电子元件焊接质量优化

Altair RapidMiner

机器学习 AI 数据分析 制造业 RapidMiner

卧槽!C 语言宏定义原来可以玩出这些花样?高手必看!

不在线第一只蜗牛

C#

看过智谱现场演示,我觉得AI要开始卷“动手能力”了

Alter

AI

开发提测流程优化思考:如何在质量控制与效率间寻找平衡?

TechLead Studio

内网即时聊天软件推荐,哪款更适合企业的即时通讯需求?

BeeWorks

IM 企业即时通讯平台 即时通讯IM 私有化部署 局域网视频软件

跨国企业组网方案: IPLC专线的优势和应用场景

Ogcloud

组网 企业组网 IPLC 国际网络专线 跨国企业组网

昇腾+DeepSeeK | 博云联合昇腾打造满血版一体机

BoCloud博云

博云 DeepSeek AI一体机

HarmonyOS NEXT 中级开发笔记:电竞直播应用的数据库设计与实践

bianchengyishu

HarmonyOS NEXT

BeeWorks:企业级即时通讯和协同办公软件

BeeWorks

即时通讯 IM 企业即时通讯平台 私有化部署 局域网视频软件

C 语言内存布局深度剖析:从栈到堆,你真的了解吗?

伤感汤姆布利柏

HarmonyOS NEXT 中级开发笔记:出行地图应用中的数据库设计与实践

bianchengyishu

HarmonyOS NEXT

组件化:动态库实战续_文化 & 方法_姜沂_InfoQ精选文章