如何精简iOS SDK文件大小
栏目: Objective-C · 发布时间: 6年前
内容简介:我们的SDK项目随着各种功能的加入,SDK文件也越来越大。Objective-C的库最终会把用到的,没有用到类和方法都连接进App里,所以精简SDK大小很有必要,有助于减少最终App的size。库文件主要分动态库和静态库两种。动态库:
我们的SDK项目随着各种功能的加入,SDK文件也越来越大。Objective-C的库最终会把用到的,没有用到类和方法都连接进App里,所以精简SDK大小很有必要,有助于减少最终App的size。
iOS平台上库文件格式
库文件主要分动态库和静态库两种。
动态库:
文件后缀名有.dylib和.framework。 链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存。
静态库:
文件后缀名有.a和.framework。.framework是一个文件包,包含二进制文件、头文件及相关的资源文件。 链接时完整地拷贝至可执行文件中。
游戏SDK文件格式
现在游戏SDK是framework形式的静态库。framework文件夹中二进制文件是占比最大的部分,其格式为“ Mach-O universal binary ”,是一种Fat binary文件。
- Fat binary文件由多个cpu平台上的archive文件合并生成。
- archive文件是由多个.o文件及调试用的符号文件合并生成。
- .o文件即代码源文件编译后生成。
大致关系是 Fat binary包含多个.a文件,.a文件包含多个.o文件。
相关命令行 工具 使用
查看SDK的架构信息
查看SDK文件的架构信息可以使用 file命令 和 lipo命令
file TestSDK.framework/TestSDK TestSDK.framework/TestSDK: Mach-O universal binary with 2 architectures: [arm_v7:current ar archive] [arm64] TestSDK.framework/TestSDK (for architecture armv7): current ar archive TestSDK.framework/TestSDK (for architecture arm64): current ar archive
可以看到TestSDK.framework包含armv7和arm64两种cpu架构的archive文件。下面是lipo命令的使用:
lipo -info TestSDK.framework/TestSDK Architectures in the fat file: TestSDK.framework/TestSDK are: armv7 arm64
导出.a文件
在SDK文件中包含多种cpu架构的二进制文件,我们可以使用lipo命令导出。
#导出armv7架构的archive文件 lipo -thin armv7 -output TestSDK_armv7.a TestSDK.framework/TestSDK #导出arm64架构的archive文件 lipo -thin arm64 -output TestSDK_arm64.a TestSDK.framework/TestSDK
查看.a文件中.o文件大小
ar命令是建立或修改archive文件,或是从archive文件中抽取文件的命令。
ar -t -v TestSDK_armv7.a rw-r--r-- 501/20 416800 Jul 17 15:09 2018 __.SYMDEF rw-r--r-- 501/20 81488 Jul 17 15:09 2018 ImageViewController.o rw-r--r-- 501/20 58616 Jul 17 15:09 2018 PasswordViewController.o ......
查看.o文件中代码段、数据段等详细的大小信息
size TestSDK.framework/TestSDK __TEXT __DATA __OBJC others dec hex 15479 3040 0 28683 47202 b862 TestSDK.framework/TestSDK(ImageViewController.o) (for architecture armv7) 12043 2132 0 18722 32897 8081 TestSDK.framework/TestSDK(PasswordViewController.o) (for architecture armv7) ...... 16696 5772 0 32674 55142 d766 TestSDK.framework/TestSDK(ImageViewController.o) (for architecture arm64) 13020 4092 0 20627 37739 936b TestSDK.framework/TestSDK(PasswordViewController.o) (for architecture arm64) ......
使用size -m 可以显示更多的Mach-O segments 和 sections大小信息
size -m TestSDK.framework/TestSDK Segment : 47207 Section (__TEXT, __text): 10072 Section (__TEXT, __gcc_except_tab): 8 Section (__DATA, __objc_data): 40 Section (__DATA, __objc_superrefs): 4 Section (__TEXT, __objc_methname): 2395 Section (__DATA, __objc_selrefs): 424 Section (__TEXT, __cstring): 2274 Section (__DATA, __cfstring): 320 Section (__DATA, __objc_classrefs): 80 Section (__DATA, __objc_ivar): 44 Section (__TEXT, __ustring): 102 Section (__DATA, __const): 180 Section (__TEXT, __objc_classname): 122 Section (__TEXT, __objc_methtype): 506 Section (__DATA, __objc_const): 1648 Section (__DATA, __data): 260 Section (__DATA, __objc_protolist): 20 Section (__DATA, __objc_classlist): 4 Section (__LLVM, __bitcode): 1 Section (__LLVM, __cmdline): 1 Section (__DATA, __objc_imageinfo): 8 Section (__DWARF, __debug_str): 8277 Section (__DWARF, __debug_loc): 2969 Section (__DWARF, __debug_abbrev): 807 Section (__DWARF, __debug_info): 8129 Section (__DWARF, __debug_ranges): 0 Section (__DWARF, __debug_macinfo): 1 Section (__DWARF, __apple_names): 2852 Section (__DWARF, __apple_objc): 252 Section (__DWARF, __apple_namespac): 36 Section (__DWARF, __apple_types): 1351 Section (__DATA, __nl_symbol_ptr): 8 Section (__DWARF, __debug_line): 4007 total 47202 total 47207
可以看出size命令是可以直接显示Fat binary文件中各个cpu架构文件信息的,但ar命令不能操作Fat binary文件,只能是某个cpu架构下的archive文件。
如何比较SDK大小变化
结合上面介绍的几个命令行工具,就可以简单比较出SDK文件的大小增量。 思路大致如下:
-
使用“lipo -info”命令获取SDK中包含的cpu架构
lipo -info SDKFilePath | sed -En -e "s/^(Non-|Architectures in the )fat file: .+( is architecture| are): (.*)$/\\3/p"
-
使用“lipo -thin”命令抽取出各个cpu架构的.a文件
lipo -thin arm64 SDKFilePath -output SDKFilePath_arm64.a
-
使用“ar -t -v”命令获取SDK中.o文件的大小
ar -t -v SDKFilePath_arm64.a | awk '{printf \"%s:%s\\n\", $8, $3}'
-
比较SDK新旧版本中同一个.o文件大小
按照上述步骤能比对两个SDK中.o文件的变化。 这里有一个脚本 sdkdiff.py
使用方法
sdkdiff.py TestSDK_v1 TestSDK_v2 +1152 361088 Title.o +824 180032 Notice.o ..... -4232 260696 Login.o -5640 243032 Proxy.o -5856 335680 User.o ---------------------------------- -45288 80801624 Total
如何精简SDK包大小
通过上面命令可以看出,SDK二进制文件包含了不同cpu架构下.m .c .cpp等源码文件编译后生成的.o文件及对应的符号文件。
精简SDK二进制文件大小也主要是删除符号文件,删除没有用到的.o文件,删除无用代码。
删除符号文件
设置Xcode Target的Building Settings >> Deployment >> Deployment Postprocessing 为YES Building Settings >> Deployment >> Strip Style 有三种选项All Symbols、Non-Global Symbols和Debugging Symbols。其中默认是Debugging Symbols。 去掉debug symbols后,不能使用xcode断点调试SDK类的代码,这个对于已发布的release模式的SDK来说,可以去掉。
删除无用类
使用otool -v -s __DATA objc_classlist 可执行文件名, 逆向 DATA.__objc_classlist段,提取可执行文件里所有的OC类名,
使用otool -v -s __DATA objc_classrefs 可执行文件名, 逆向 DATA.__objc_classrefs段,提取可执行文件里所有的引用到的OC类名,
两者的差集就是代码中没有直接使用到的OC类,注意可以通过反射的方式来使用OC类,还需要搜索代码中有没有通过类的名字来使用该OC类。 这里的方法是针对可执行文件,所以在编译好SDK后,还应为SDK编译一个可执行的Demo,然后使用上面的方法来查找未使用到的类。
注意:OC是动态语言,是可以通过类名来调用类的方法的,所以查找到没有引用到的类后,还需要查看代码中有没有通过 NSClassFromString(@“OCClassName”) 方法使用该类。
下面是查找无用类的脚本
#!/bin/bash # 输出未在项目中使用的类名 # 使用说明 # unused_class <hex file> usage() { cat <<__EOF Summary output names of unused objc class. Usage $(basename $0) <hex file> __EOF } error_usage(){ local error=${1:-Undefined error} echo "$0:$LINE $error" usage exit 1 } if [[ $# -lt 1 ]] ;then error_usage "Error! No project directory was specified."; fi HEXFILE=$1 CLASSLIST=`otool -s __DATA __objc_classlist $HEXFILE | grep "^[0-9a-f]" | awk '{print $3$2"\n"$5$4}'|sort` CLASSREFS=`otool -s __DATA __objc_classrefs $HEXFILE | grep "^[0-9a-f]" | awk '{print $3$2"\n"$5$4}'|sort` nm $HEXFILE >./temp_all_symbols.txt for classname in $CLASSLIST do if [[ $CLASSREFS =~ $classname ]]; then : else grep $classname ./temp_all_symbols.txt fi done rm ./temp_all_symbols.txt
删除无用代码
使用otool -v -s __DATA objc_selrefs 可执行文件名,逆向 DATA. objc_selrefs段,提取可执行文件里引用到的方法名, 使用LinkMap文件的 TEXT.__text 提取当前可执行文件里所有objc类方法和实例方法,
两者的差集就是代码中没有直接使用到的方法,注意可以通过反射的方式来类方法和实例方法,还需要搜索代码中有没有通过方法名字来使用该方法。
精简SDK引用的第三方库
我们的SDK引用了微信,QQ等第三方库来提供第三方登录的功能,为了SDK接入方的方便,我们直接将微信,QQ等公用的第三方库打包进我们的SDK了。虽然这样减少了我们SDK接入方的工作,但是也导致我们SDK文件大小暴涨。另外也带来了一些其他的问题,比如接入方需要更新微信,QQ SDK版本时就麻烦了。
我们SDK去掉微信,QQ SDK,让接入方自己引入,这样可以减小我们SDK的大小。但是最后所有的接入方生成的App还是会包含微信,QQ的SDK,然而,并不是所有的接入方都需要接入微信,QQ登录。这样的话,对于这部分的接入方,App就包含并不需要的微信和QQ的SDK代码。 其实我们可以在我们的SDK中使用类反射的的方式来调用微信,QQ等第三方库的功能,这样对于没有接入微信登录功能的接入方,就没必要引入微信等第三方库。
+ (void)enableWeChat:(NSString *)appid class:(Class)cls { [NSClassFromString(@"WXApi") registerApp:appid]; }
接入方如果需要引入微信登录功能,需要引入微信SDK,然后再添加这样的代码
[TestSDK enableWeChat:@"1234567890" class:WXApi.class];
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
HTML5移动应用开发入门经典
凯瑞恩 / 林星 / 人民邮电出版社 / 2013-3 / 55.00元
《HTML5移动应用开发入门经典》总共分为24章,以示例的方式对如何使用HTML5及相关技术进行移动应用开发做了全面而细致的介绍。《HTML5移动应用开发入门经典》首先讲解了HTML5的起源以及它为什么适用于移动设备,然后讲解了HTML5的基本元素以及所做的改进、canvas(画布)、视音频、微格式、微数据、拖曳等新增特性,还讲解了WebSocket、WebWorkers、Web存储、离线Web应......一起来看看 《HTML5移动应用开发入门经典》 这本书的介绍吧!