Skip to content

Instantly share code, notes, and snippets.

@d1y
Last active June 19, 2026 04:49
Show Gist options
  • Select an option

  • Save d1y/2edb8a504b1e24cfd9141f9d0204a52e to your computer and use it in GitHub Desktop.

Select an option

Save d1y/2edb8a504b1e24cfd9141f9d0204a52e to your computer and use it in GitHub Desktop.
x.ipa 体积分析报告

分析对象:x.ipa(X / 原 Twitter iOS 客户端)

分析方式:对解压后的 Payload/Twitter.app 做目录体积、Mach-O 段/节(segment/section)和加密状态分析

日期:2026-06-19


一、结论速览(TL;DR)

x.ipa 大的根本原因不是图片/资源,而是「代码量本身」——一个超大型「超级 App」把海量一方代码 + Kotlin 跨端共享层 + 一大堆身份核验/支付/风控/实时音视频第三方 SDK 全部静态打进了同一个包。

维度 数值
x.ipa(压缩后) 408 MB
Twitter.app(解压后) 510 MB
其中 Frameworks/ 367 MB(占 72%)
其中 PlugIns/(扩展) 71 MB(14%)
其中 Assets.car(图片资源) 23 MB(4.5%)
仅前 4 个 framework ≈ 280 MB(占整包 55%)
仅前 4 个 framework 的纯机器码(__text) ≈ 166 MB

一句话:体积 ≈ 巨量编译后代码(__text,而且整包还处于 App Store FairPlay 加密状态(cryptid=1),加密段几乎不可压缩,所以 510 MB 压成 ipa 也只能压到 408 MB(仅缩 20%)。


二、被分析的包是什么

应用 X(原 Twitter)
Bundle ID com.atebits.Tweetie2
版本 12.1(build 11)
最低系统 iOS 15.0
CPU 架构 仅 arm64(已做 App Store thinning,不是肥二进制)
主可执行文件 Twitter(3.2 MB)

说明:Chirp 不是二进制,而是字体目录(X 自有 Chirp 字族 + 一个 3.6 MB 的 emoji 覆盖可变字体)。


三、体积构成(自顶向下)

3.1 App bundle 顶层(510 MB)

组件 体积 占比 说明
Frameworks/ 367 MB 72% 绝对大头,57 个动态库
PlugIns/ 71 MB 14% 4 个 App 扩展
Assets.car 23 MB 4.5% 图标/图片资源编译产物
Localization_*.bundle 9.3 MB 本地化资源
Chirp/(字体) 5.3 MB 自有字体 + emoji 字体
Grok_Grok.bundle 4.6 MB Grok(AI)资源
XIcons / TwitterAppearance 等 bundle 各 ~4 MB 图标/主题资源
其余几十个资源 bundle + lproj 余下

3.2 Frameworks Top(367 MB 的来源)

Framework 体积 性质
TwitterAppSPMMigration 87 MB 一方 Swift 主体代码(模块化迁移中)
TwitterSPMMigration 81 MB 一方 Swift 主体代码(模块化迁移中)
XKotlin 78 MB Kotlin 跨端共享业务逻辑(Kotlin/Native 编译)
T1Twitter 42 MB 遗留 ObjC/Swift 核心("T1"=Tweetie 血统)
XCoreLibraries 16 MB 一方基础库
WebRTC 11 MB 实时音视频
LiveKitWebRTC 11 MB 实时音视频(与上面重复
Persona2 8.6 MB 身份核验 / KYC
SocureDocV 7.7 MB 证件文档核验
PalmAPISaas 5.9 MB 掌纹 / 生物识别
LinkKit (Plaid) 4.8 MB 银行账户连接
PinwheelSDK 4.4 MB 收入 / 银行数据
VeryAILiveness 3.0 MB 活体检测
MarkdownView / SwiftProtobuf / MobileIntelligence / CastleSDK … 1–2 MB 一档 长尾

前 4 个 framework 合计 ≈ 280 MB,占整包的 55%。


四、根因分析:为什么这么大

根因 1(最主要):一方代码量极其庞大 —— 体积几乎全是「机器码」

对最大的几个二进制做 Mach-O 段/节剖析,结果非常明确:大头是 __text(编译后的机器指令),不是数据、不是资源

TwitterAppSPMMigration(87 MB)段内构成:

Section 大小 含义
__text 53.3 MB 纯机器码 ← 主体
__eh_frame 3.0 MB C++/异常展开表
__objc_methname 1.6 MB ObjC 方法名字符串
__swift5_typeref 1.1 MB Swift 类型元数据
__cstring 1.1 MB C 字符串
__objc_methlist 1.1 MB ObjC 方法列表
其余 Swift/ObjC 元数据 分散数 MB 反射/字段/协议元数据

TwitterSPMMigration 同型:__TEXT 段就有 61 MB

两个名字里带 "SPMMigration" 的巨型 framework 是关键信号:X 正处于从单体工程向 Swift Package Manager 模块化迁移的中途,绝大部分一方业务代码被塞进了这两个「迁移过渡壳」里(一个 App 层、一个非 App 层)。它们没有被拆细,所以各自高达 80+ MB。这部分是「业务复杂度 + 迁移中间态」共同导致的,纯代码体积,无法靠压缩资源解决

根因 2:XKotlin —— Kotlin 跨端共享层(Kotlin/Native)

XKotlin.framework(78 MB)是用 Kotlin Multiplatform 写的、给 iOS/Android 复用的共享业务逻辑,经 Kotlin/Native 编译成原生 framework:

Section 大小 含义
__text 41.2 MB Kotlin 编译出的机器码
__LINKEDIT 23.7 MB 符号表 / 导出符号(Kotlin/Native 导出极多符号)
__DATA_CONST.__const 8.6 MB Kotlin/Native 运行时常量数据

Kotlin/Native 的产物天生偏大:它要自带运行时和 GC,并生成大量符号与反射元数据(这就是 23.7 MB __LINKEDIT 的由来)。一个共享层就吃掉 ~78 MB。

根因 3:T1Twitter —— 遗留 Objective-C/Swift 核心(42 MB)

__text 18.8 MB,且 ObjC 元数据特别多(__objc_methname 1.56 MB、__objc_const 1.44 MB)。这是 Tweetie 时代延续下来的老 Twitter for iOS 核心代码,和上面的 SPMMigration 新代码并存——新旧两套同时在包里,是迁移期的典型现象。

根因 4:第三方 SDK 的「超级 App」化堆叠

X 要做「万能 App / X Money」,因此集成了大量重型 SDK,集中在三类:

  • 身份核验 / KYC / 活体:Persona2(8.6M) + SocureDocV(7.7M) + PalmAPISaas(5.9M) + VeryAILiveness(3M) + AmazonFaceLiveness + XPalmLiveness + XFaceLiveness ≈ 30+ MB
  • 支付 / 银行:LinkKit·Plaid(4.8M) + PinwheelSDK(4.4M) + Payments ≈ 10+ MB
  • 风控 / 反欺诈:CastleSDK + MobileIntelligence + DeviceRisk + IOSSecuritySuite

这些功能多数用户从不触达,但代码全部静态打进主包。

根因 5:重复打包与冗余(可优化但非主因,约 35+ MB)

  1. 两套 WebRTCWebRTC.framework(11.0 MB)和 LiveKitWebRTC.framework(10.8 MB)几乎是同一套实时音视频栈的两份独立构建,≈ 21 MB 重复能力

  2. 扩展重复嵌入资源 bundleShareExtension.appex(42 MB)把主 App 已有的资源 bundle 又打了一份:

    资源 bundle 主 App ShareExtension
    TwitterAppearance 4.0 MB 4.0 MB
    XIcons 3.9 MB 3.9 MB
    DMV2Assets 2.3 MB 2.3 MB
    Periscope 系列 4.2 MB 4.2 MB
    TwitterUIResources 0.7 MB 0.7 MB

    仅此一项 ShareExtension 就重复了约 15 MB。(其本体二进制还另有 22 MB。)

  3. 7 个 *_PackageProduct.framework:SPM 产物残留的薄壳 framework,属于打包链路的边角冗余。

根因 6:为什么 ipa 文件本身也压不下去(510→408 仅缩 20%)

检查加密状态发现 cryptid = 1——不仅主二进制,连 framework 也是 FairPlay 加密的:

主 Twitter 二进制 : LC_ENCRYPTION_INFO_64  cryptid 1  cryptsize 2,392,064
TwitterAppSPMMigration : LC_ENCRYPTION_INFO_64  cryptid 1  cryptsize 70,238,208 (≈70MB)

这说明该 ipa 是未脱壳的 App Store 原始包。加密后的代码段是高熵数据,几乎不可被 zip 压缩。普通 App 通常能压掉 50%+,而这里 510 MB 只压到 408 MB(仅 20%),正是因为大量 __text 处于加密态。换句话说:代码多 + 代码被加密,双重导致 ipa 文件体积下不来。


五、不是问题的部分(排除项)

常见怀疑 实测 结论
肥二进制(多架构) 仅 arm64 ✅ 已 thinning,无问题
本地化语言太多 43 种语言,仅 172 KB ✅ 可忽略
图片资源爆炸 Assets.car 23 MB ✅ 对这个体量的 App 算克制
字体 5.3 MB(含 3.6 MB emoji 字体) 一般

资源不是元凶,代码才是。


六、优化方向(按性价比排序)

  1. 拆分 SPMMigration 巨壳 + 完成模块化迁移:把 TwitterAppSPMMigration/TwitterSPMMigration(合计 168 MB)真正拆成可按需/可裁剪的模块,是体积优化的最大盘子。
  2. 统一 WebRTC:LiveKit 与裸 WebRTC 二选一或共用底层,省 ~10–20 MB。
  3. 第三方 SDK 按需化:身份核验/支付/活体类 SDK 改为 On-Demand Resources / App Clips / 动态下发,绝大多数用户无需在首装时下载这 40+ MB。
  4. 消除扩展资源重复:ShareExtension 通过 App Group / 共享 framework 复用主 App 资源,省 ~15 MB。
  5. XKotlin 瘦身:开启 Kotlin/Native 的死代码消除、-Xg0/release 符号裁剪,压缩 23.7 MB 的 __LINKEDIT
  6. 清理 7 个 PackageProduct 残壳

注意:第 1、5 项(一方代码与 Kotlin 层)是体积主体但最难动;第 2、3、4、6 项是「低风险、可立即回收」的约 50–60 MB。


附录:关键命令与原始数据

# 架构确认(全部 arm64)
lipo -archs Twitter / *.framework → arm64

# 段构成(最大二进制)
size -m TwitterAppSPMMigration → __text 53.3MB / __TEXT 段 70MB
size -m XKotlin                → __text 41.2MB / __LINKEDIT 23.7MB / __const 8.6MB
size -m T1Twitter              → __text 18.8MB(ObjC 元数据密集)

# 加密状态
otool -l ... | grep LC_ENCRYPTION_INFO → cryptid 1(主二进制与 framework 均加密)

# 体积
du -sh Frameworks = 367M;前 4 framework ≈ 280M;整包 510M;ipa 408M
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment