🐻 探究分析ipa包

3,896 阅读10分钟

场景一: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)
场景一中的 ipa377.8MB
场景二中的 ipa88.6MB
场景一中的 Frameworks373.5MB
场景二中的 Frameworks47.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: 
···
···

分析工具:

github.com/huanxsd/Lin…

动态库和静态库

理论上来说:动态在汇编成可执行文件.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

结果如上,为何压缩率如此不同?疑惑中。。。