场景一:Achieve 导出的AppStore包
DistributionSummary.plist
ExportOptions.plist
Packaging.log
xxx.ipa
DistributionSummary
包含ipa的支持架构、bitcode、证书、embeddedBinaries(非系统的动态库相关)、entitlements(apns环境、application-identifier等)、profile等相关信息ExportOptions
pp文件等Packaging.log
打包日志xxx.ipa
包内容
xxx.ipa
全称:iPhone Application
ipa 文件实质是一个 zip压缩包
ipa 大小 : 377.8MB
修改后缀 xxx.zip 解压缩,得到以下内容:
- payload 目录下的 xxx.app 大小:114.6MB
- BCSymbolMaps 符号文件 ,Xcode 对 BitCode 符号表进行混淆(Symbol Hiding)后生成的对照表,和 dSYM 文件会一一对应。
- SwiftSupport swift的支持库,ios12.2以前swift的标准库是放在app中的,导致包大小增加
分析 xxx.app
显示包内容: 该目下包含的内容比较多,整理如下:
- CodeResources 文件签名,这是一个plist文件,里面保存了app中每个文件(除了App的可执行文件)的明文哈希值
codesign这个命令对app进行签名后就会生成这个文件
- Assets.car 图片资源 334k + 1.7MB
Assets.car 查看方法 github.com/insidegui/A…
- embedded.mobileprovision 生产证书
- Frameworks 动态库(自己的和系统的)大小 373.5MB
- Info.plist
- PlugIns (today extension 等插件)大小 1.8MB
- 其他的图片资源和bundle
- xxx Unix可执行文件 大小 280.7MB
场景二:AppStore 下载 导出的ipa
手机:iPhone11Pro、6Pro
OS:iOS14.2、12.2
通过apple configure2 拿到的
xxx.ipa
全称:iPhone Application
ipa 文件实质是一个 zip压缩包
ipa 大小 : 88.6MB
修改后缀 xxx.zip 解压缩,得到以下内容:
- iTunesArtwork,实质是一个无后缀名的 png 图片
- iTunesMetadata.plist,记录购买者信息、售价等数据。
- 存储描述数据属性的信息,里面包含两个子文件: com.apple.FixedZipMetadata.bin、com.apple.ZipMetadata.plist
- payload 目录下的 xxx.app 大小:114.6MB
分析 xxx.app
显示包内容: 该目下包含的内容比较多,整理如下:
- CodeResources 文件签名,这是一个plist文件,里面保存了app中每个文件(除了App的可执行文件)的明文哈希值
codesign这个命令对app进行签名后就会生成这个文件
- Assets.car 图片资源 334k + 1.7MB
Assets.car 查看方法 github.com/insidegui/A…
- embedded.mobileprovision 生产证书
- Frameworks 动态库(自己的和系统的)大小 47.5MB
- Info.plist
- PlugIns (today extension 等插件)大小 0.54MB
- 其他的图片资源和bundle
- xxx Unix可执行文件 大小 46.7MB
- SC_Info
SC_Info 内容
Manifest.plist YourApp.sinf YourApp.supf myapp.supp myapp.supx
.sinf 为 metadata 文件 .supp 为解密可执行文件的密钥
场景一与场景二 xxx.ipa 比较明显的区别
名称 | 大小(单位MB) |
---|---|
场景一中的 ipa | 377.8MB |
场景二中的 ipa | 88.6MB |
场景一中的 Frameworks | 373.5MB |
场景二中的 Frameworks | 47.5MB |
场景一中的 xxx Unix可执行文件 | 280.7MB |
场景二中的 xxx Unix可执行文件 | 46.7MB |
App瘦身 App Slicing
手机:iPhone11Pro、6Pro 是通过apple configure2 拿到的,并不是越狱拿到的ipa
App Slicing 对于包中的Assets,没有起作用
我发现 App Slicing 对于包中的Assets,没有起作用,包中的Assets.car 依旧包含2x图。
同时我通过爱思助手拿到的ipa中App Slicing 结果相同
所以有点疑惑,关于App Slicing 是不是只有从appstore上下载的才有效果
App Slicing 对二进制 有明显效果
场景一:Mach-O 文件 是 280.7MB 场景二:Mach-O 文件 是 46.7MB
小240MB,是原来的6分之一
iOS默认指令集
armv7 | armv7s | arm64 | arm64e都是ARM处理器的指令集
模拟器:
i386:iphone5/iphone5c以下的模拟器
x86_64:iPhone5s以上的模拟器
真机:
armv6:iPhone、iPhone2、iPhone3G、iPod Touch(第一代)、iPod Touch(第二代)
armv7:iPhone3Gs、iPhone4、iPhone4s、iPad、iPad 2
armv7s:iPhone5、iPhone5c
arm64:iPhone5s、iPhone6、iPhone6p、iPhone6s、iPhone6sp、iPhone7、iPhone7p、iPhone8、iPhone8p、iPhoneX
arm64e:iPhone XS、iPhone XS Max、iPhone XR、 iPhone 11 、iPhone 11 Pro 、iphone 11 Pro Max
即:
模拟器32位处理器需要i386架构
模拟器64位处理器需要x86_64架构
真机32位处理器需要armv7,或者armv7s架构
真机64位处理器需要arm64,或者arm64e架构
作者:没脑子的程序员
链接:https://www.jianshu.com/p/5f1e87b82ecb
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
App瘦身 Bitcode
Bitcode是LLVM编译器的中间代码的一种编码,appstore服务端可以根据不同的cpu架构打包成不同的可执行机器指令数据,包括尚未开发的架构,似乎对用户下载的app体积大小没有真正作用。
开启bitcode后由于真正的用户下载的包是appstore服务端编译的,所以本地的符号表失效,需要去官网下载
App瘦身 Link-Time
通过修改Build Settings中的Link-Time Optimization=Incremental
分析 link map
Write Link Map File设置为Yes后,Build结束后,会在默认路径下生成一个Link Map File文件
/Users/a2020/Library/Developer/Xcode/DerivedData/myapp-hblkggblkurwjjacpdugtpzutctm/Build/Intermediates.noindex/myapp.build/BetaDebug-iphoneos/myapp.build/myapp_Beta-LinkMap-normal-arm64.txt
可执行文件的流程:
预处理 -> 编译 -> 汇编 -> 链接
汇编 后生成.o文件(目标文件、可执行文件)
myapp_Beta-LinkMap-normal-arm64.txt 用于记录链接相关信息
大小可能有几十兆
Link Map File 有什么用?
- 查看代码加载顺序
- 理解内存分段分区
- Crash 时通过 Symbols 定位源码的机制
- 分析可执行文件中类或库体积,优化包体积
参考链接!:www.jianshu.com/p/52e0dee35…
其大致内容如下:
# Path: /Users/a2020/Library/Developer/Xcode/DerivedData/myapp-hblkggblkurwjjacpdugtpzutctm/Build/Products/BetaDebug-iphoneos/myapp_Beta.app/myapp_Beta
# Arch: arm64
# Object files:
[ 0] linker synthesized
[ 1] dtrace
[ 2] /Users/a2020/Library/Developer/Xcode/DerivedData/myapp-hblkggblkurwjjacpdugtpzutctm/Build/Intermediates.noindex/myapp.build/BetaDebug-iphoneos/myapp.build/Objects-normal/arm64/AppDelegate+Net.o
[ 3] /Users/a2020/Library/Developer/Xcode/DerivedData/myapp-hblkggblkurwjjacpdugtpzutctm/Build/Intermediates.noindex/myapp.build/BetaDebug-iphoneos/myapp.build/Objects-normal/arm64/AppDelegate+Login.o
[ 4] /Users/a2020/Library/Developer/Xcode/DerivedData/myapp-hblkggblkurwjjacpdugtpzutctm/Build/Intermediates.noindex/myapp.build/BetaDebug-iphoneos/myapp.build/Objects-normal/arm64/AppDelegate+IM.o
[ 5] /Users/a2020/Library/Developer/Xcode/DerivedData/myapp-hblkggblkurwjjacpdugtpzutctm/Build/Intermediates.noindex/myapp.build/BetaDebug-iphoneos/myapp.build/Objects-normal/arm64/AppDelegate+Firebase.o
[ 6] /Users/a2020/Library/Developer/Xcode/DerivedData/myapp-hblkggblkurwjjacpdugtpzutctm/Build/Intermediates.noindex/myapp.build/BetaDebug-iphoneos/myapp.build/Objects-normal/arm64/Target_TabBar.o
[ 7] /Users/a2020/Library/Developer/Xcode/DerivedData/myapp-hblkggblkurwjjacpdugtpzutctm/Build/Intermediates.noindex/myapp.build/BetaDebug-iphoneos/myapp.build/Objects-normal/arm64/AppDelegate+BackgroundTask.o
[ 8] /Users/a2020/Library/Developer/Xcode/DerivedData/myapp-hblkggblkurwjjacpdugtpzutctm/Build/Intermediates.noindex/myapp.build/BetaDebug-iphoneos/myapp.build/Objects-normal/arm64/AppDelegate+Token.o
[ 9] /Users/a2020/Library/Developer/Xcode/DerivedData/myapp-hblkggblkurwjjacpdugtpzutctm/Build/Intermediates.noindex/myapp.build/BetaDebug-iphoneos/myapp.build/Objects-normal/arm64/AppDelegate+TPNS.o
[ 10] /Users/a2020/Library/Developer/Xcode/DerivedData/myapp-hblkggblkurwjjacpdugtpzutctm/Build/Intermediates.noindex/myapp.build/BetaDebug-iphoneos/myapp.build/Objects-normal/arm64/AppDelegate+Custom.o
[ 11] /Users/a2020/Library/Developer/Xcode/DerivedData/myapp-hblkggblkurwjjacpdugtpzutctm/Build/Intermediates.noindex/myapp.build/BetaDebug-iphoneos/myapp.build/Objects-normal/arm64/AppDelegate.o
[ 12] /Users/a2020/Library/Developer/Xcode/DerivedData/myapp-hblkggblkurwjjacpdugtpzutctm/Build/Intermediates.noindex/myapp.build/BetaDebug-iphoneos/myapp.build/Objects-normal/arm64/AppTabBarController.o
···
···
[2729] /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.3.sdk/usr/lib/swift/libswiftDarwin.tbd
[2730] /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.3.sdk/usr/lib/swift/libswiftCoreGraphics.tbd
# Sections:
# Address Size Segment Section
0x100007940 0x00E95C20 __TEXT __text
0x100E9D560 0x000071B8 __TEXT __stubs
0x100EA4718 0x00006018 __TEXT __stub_helper
0x100EAA730 0x000136D6 __TEXT __swift5_typeref
0x100EBDE08 0x0000E578 __TEXT __swift5_capture
0x100ECC380 0x000B772B __TEXT __cstring
0x100F83AAB 0x00068FF9 __TEXT __objc_methname
0x100FECAB0 0x00084720 __TEXT __const
0x1010711D0 0x00000A14 __TEXT __swift5_builtin
···
# Symbols:
# Address Size File Name
0x100007940 0x00000970 [ 2] _$s14myapp_Beta11AppDelegateC8setupNetyyF
0x1000082B0 0x00000040 [ 2] l_objectdestroy
0x1000082F0 0x0000015C [ 2] _$s14myapp_Beta11AppDelegateC8setupNetyyFySi_SDySSypGSgtcfU_
0x10000844C 0x00000008 [ 2] _$s14myapp_Beta11AppDelegateC8setupNetyyFySi_SDySSypGSgtcfU_TA
0x100008454 0x00000078 [ 2] ___swift_instantiateConcreteTypeFromMangledName
0x1000084CC 0x0000002C [ 2] _$sSSWOh
0x1000084F8 0x00000058 [ 2] ___swift_project_boxed_opaque_existential_1
0x100008550 0x00000070 [ 2] ___swift_destroy_boxed_opaque_existential_1
0x1000085C0 0x00000058 [ 2] ___swift_project_boxed_opaque_existential_0
0x100008618 0x00000070 [ 2] ___swift_destroy_boxed_opaque_existential_0
0x100008688 0x000005AC [ 2] _$s14myapp_Beta11AppDelegateC21ct_listeningErrorCode4code4dataySi_SDySSypGSgtF
0x100008C34 0x0000002C [ 2] _$ss26DefaultStringInterpolationVWOh
0x100008C60 0x0000002C [ 2] _$ss10debugPrint_9separator10terminatoryypd_S2StFfA0_
0x100008C8C 0x0000002C [ 2] _$ss10debugPrint_9separator10terminatoryypd_S2StFfA1_
0x100008CB8 0x00000030 [ 2] _$sypSgWOh
0x100008CE8 0x00000074 [ 2] _$sSNySiGSNyxGSXsWl
0x100008D5C 0x000000A0 [ 2] _$sSNySiGMa
0x100008DFC 0x00000044 [ 2] _$sSSSgWOc
0x100008E40 0x000000D8 [ 2] _$s14myapp_Beta11AppDelegateC21ct_listeningErrorCode4code4dataySi_SDySSypGSgtFTo
0x100008F18 0x00000308 [ 3] _$s14myapp_Beta11AppDelegateC21toLoginViewController6reasonySS_tF
0x100009220 0x0000002C [ 3] _$sSo8UIWindowCSgWOh
0x10000924C 0x00000250 [ 3] _$s14myapp_Beta11AppDelegateC22toTabbarViewControlleryyF
0x10000949C 0x00000264 [ 3] _$s14myapp_Beta11AppDelegateC31toPerfectUserInfoViewControlleryyF
0x100009700 0x000001E0 [ 4] _$s14myapp_Beta11AppDelegateC7setupIMyyF
0x1000098E0 0x0000056C [ 4] _$s14myapp_Beta11AppDelegateC7imLoginyyF
0x100009E4C 0x00000120 [ 4] _$s14myapp_Beta11AppDelegateC9imReLogin33_17381B2BC94020957961CA3A3A401E51LLyyF
0x100009F6C 0x00000088 [ 4] _$s14myapp_Beta11AppDelegateC9imReLogin33_17381B2BC94020957961CA3A3A401E51LLyyFySDySSypGSg_s5Error_pSgtcfU
···
0x1007E9BB0 0x0000003C [1354] ___68-[HWPanModalPresentableHandler setScrollableContentOffset:animated:]_block_invoke
0x1007E9BEC 0x000001A8 [1354] -[HWPanModalPresentableHandler configureViewLayout]
0x1007E9D94 0x000000B8 [1354] -[HWPanModalPresentableHandler gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:]
0x1007E9E4C 0x000000C8 [1354] -[HWPanModalPresentableHandler gestureRecognizer:shouldBeRequiredToFailByGestureRecognizer:]
0x1007E9F14 0x0000022C [1354] -[HWPanModalPresentableHandler gestureRecognizerShouldBegin:]
0x1007EA140 0x0000010C [1354] -[HWPanModalPresentableHandler addKeyboardObserver]
0x1007EA24C 0x00000050 [1354] -[HWPanModalPresentableHandler removeKeyboardObserver]
0x1007EA29C 0x000000CC [1354] -[HWPanModalPresentableHandler keyboardWillShow:]
0x1007EA368 0x000001E0 [1354] -[HWPanModalPresentableHandler keyboardWillHide:]
0x1007EA548 0x0000048C [1354] -[HWPanModalPresentableHandler updatePanContainerFrameForKeyboard]
0x1007EA9D4 0x000001F4 [1354] -[HWPanModalPresentableHandler findCurrentTextInputInView:]
0x1007EABC8 0x0000006C [1354] -[HWPanModalPresentableHandler transitionToState:]
0x1007EAC34 0x0000005C [1354] -[HWPanModalPresentableHandler cancelInteractiveTransition]
0x1007EAC90 0x0000005C [1354] -[HWPanModalPresentableHandler finishInteractiveTransition]
0x1007EACEC 0x00000074 [1354] -[HWPanModalPresentableHandler dismissPresentable:mode:]
0x1007EAD60 0x000000CC [1354] -[HWPanModalPresentableHandler isPresentedViewAnchored]
0x1007EAE2C 0x000000CC [1354] -[HWPanModalPresentableHandler isBeingDismissed]
0x1007EAEF8 0x000000CC [1354] -[HWPanModalPresentableHandler isBeingPresented]
0x1007EAFC4 0x000000CC [1354] -[HWPanModalPresentableHandler isPresentedViewControllerIn
···
0x1016C9480 0x00000008 [2681] _gXGPushExtendClass
0x1016C9488 0x0000001C [2707] _tpns_cipher_supported
# Dead Stripped Symbols:
# Size File Name
<<dead>> 0x00000004 [ 2] literal string: iOS
<<dead>> 0x00000001 [ 2] literal string:
<<dead>> 0x00000001 [ 2] literal string:
<<dead>> 0x00000001 [ 2] literal string:
<<dead>> 0x00000001 [ 2] literal string:
<<dead>> 0x00000001 [ 2] literal string:
<<dead>> 0x00000001 [ 2] literal string:
<<dead>> 0x00000001 [ 2] literal string:
<<dead>> 0x00000001 [ 2] literal string:
<<dead>> 0x00000001 [ 2] literal string:
<<dead>> 0x00000001 [ 2] literal string:
<<dead>> 0x00000001 [ 2] literal string:
<<dead>> 0x00000001 [ 2] literal string:
<<dead>> 0x00000001 [ 2] literal string:
<<dead>> 0x00000001 [ 2] literal string:
···
···
分析工具:
动态库和静态库
理论上来说:动态在汇编成可执行文件.o 时,仅仅“拷贝”一些重定位和符号表信息,真正的链接在程序运行时完成
同时明显『静态库链接的可执行文件』会比『动态的动态库的可执行文件』大的多
但是,不可忽略的是针对于app来讲,静态库链接的可执行文件的大小 < 动态库大小 + 动态库链接的可执行文件的大小
具体公式如下:
动态库大小 + 动态库链接的可执行文件的大小 - 重定位和符号表信息 = 静态库链接的可执行文件的大小
为什么ADHoc 比 appstore的包小?
adhoc包 大小 57MB appstore的包 大小 88MB
adhoc ipa解压缩后的目录:
AppThinning.plist
Payload
appstore ipa解压缩后的目录:
META-INF
Payload
iTunesArtwork
iTunesMetadata.plist
从目录上看 adhoc ipa 比 appstore ipa 缺少一切文件。
但iTunesArtwork、iTunesMetadata.plist比较小,加一起也就500k
真正的差距在 Payload中
adhoc包 Payload中 的xxx.app 大小为 136.6MB appstore包 Payload中 的xxx.app 大小为 114.6MB
莫非是因为adhoc包 Payload中 的xxx.app 压缩比很高?
而appstore包 Payload中 的xxx.app 压缩比较低?
实践
adhoc包 Payload中 的xxx.app zip压缩后大小为 54MB
appstore包 Payload中 的xxx.app zip压缩后大小为 89MB
结果如上,为何压缩率如此不同?疑惑中。。。