大型大型网站建设方案ppt,制定 网站改版优化方案,制作动漫的软件,测字算命网站开发介绍
分享一款用于分析iOSipa包的脚本工具#xff0c;使用此工具可以自动扫描发现可修复的包体积问题#xff0c;同时可以生成包体积数据用于查看。这块工具我们团队内部已经使用很长一段时间#xff0c;希望可以帮助到更多的开发同学更加效率的优化包体积问题。
工具下载…介绍
分享一款用于分析iOSipa包的脚本工具使用此工具可以自动扫描发现可修复的包体积问题同时可以生成包体积数据用于查看。这块工具我们团队内部已经使用很长一段时间希望可以帮助到更多的开发同学更加效率的优化包体积问题。
工具下载地址
背景
APPAnalyze工具最早诞生主要是为了解决以下包体积管理的问题
对于定位下沉市场的APP来讲包体积是一个非常重要的性能指标包体积过大会影响用户下载APP的意愿。但是在早期我们缺少一些手段帮助我们更高效的去进行包体积管理。
自动发现问题 提升效率- 人工排查问题效率低对于常见的问题尽可能自动扫描出来。并且对于组件化工程来讲很多外部组件是通过Framework方式提供没有仓库源码权限用于分析包体积问题。 流程化- 形成自动化的质量流程添加到CI流水线自动发现包体积问题。
数据指标量化 包体积问题- 提供数据化平台查看每个组件的包体积待修复问题 包体积大小- 提供数据化平台查看每个组件的包体积占比包括总大小单个文件二进制大小和每个资源大小。可以针对不同的APP版本进行组件化粒度的包体积数据对比更方便查看每个版本的组件大小增量。
实现方式
我们选择了不依赖源码而是直接扫描二进制库的方式来实现这个能力总体的执行流程一下 提示基于组件化工程的扫描方式内部支持只是暂时不对外开放。 使用指南
安装
无需安装。通过下载链接直接下载终端可执行命令文件APPAnalyzeCommand到本地即可使用。
APPAnalyzeCommand 下载地址
使用
$ /Users/Test/APPAnalyzeCommand --help
OPTIONS:--version version 当前版本 1.0.0--output output 输出文件目录。必传参数--config config 配置JSON文件地址。非必传参数--ipa ipa ipa.app文件地址。必传参数-h, --help Show help information.
执行
打开终端程序直接执行以下shell指令即可生成ipa的包体积数据以及包体积待修复问题。 提示不能直接使用AppStore的包AppStore的包需要砸壳。建议尽量使用XCodeDebug的包。 /Users/Test/APPAnalyzeCommand --ipa ipas/JDAPP/JDAPP.app --output ipas/JDAPP 提示如果提示permission denied没有权限执行sudo chmod -R 777 /Users/a/Desktop/ipas/APPAnalyzeCommand即可。 生成产物 指令执行完成以后会在ouput参数指定的文件夹生成APPAnalyze文件夹。具体文件介绍如下
包体积信息
app_size.html- 展示ipa每个framework的包体积数据可直接用浏览器打开。 提示按照主程序和动态库进行粒度划分 framework_size.html- 展示单个framework所有的包体积数据二级页面不要直接打开。 提示XCode生成Assets.car时会将一些小图片拼接成一张PackedAssetImage的大图片。 package_size.json-ipa包体积 JSON 数据
包体积待修复问题
app_issues.html- 展示ipa每个framework的包体积待修复问题数量可直接用浏览器打开。 提示按照主程序和动态库进行粒度划分 framework_issues.html- 展示单个framework所有的待修复问题详细数据二级页面不要单独打开。 issues.json-ipa待修复包体积问题 JSON 数据 提示json数据可用于搭建自己的数据平台扩展更多的能力。例如查看不同APP版本以及支持多个APP版本对比等。 规则介绍 包体积
未使用的类
定义了类没有被使用到包含ObjC类和Swift类。
扫描规则 没有查到到对应的ObjC类被引用 没有被当做父类使用 没有使用的字符串和类名一致 没有被当做属性类型使用 没有被创建或调用方法 没有实现load方法
可选的修复方式 移除未使用的类 Swift类如果只是用了static方法考虑修改成Enum类型 如果只是在类型转换时使用了也会检测出是未使用的类例如(ABCClass *)object;。建议检查是否真的有没有到相关类后删除 对于ObjC如果只是作为方法参数类型使用也会被检测出是未使用的类。建议删除相关方法即可。 提示删除类相对是一种安全的行为因为删除后如果有被使用到会产生编译时错误。虽然有做字符串调用的扫描过滤不过还是建议检查是否可能被Runtime动态创建调用 未使用的ObjC协议
定义了ObjC协议没有被类使用
扫描规则
对应的协议没有被类引用
可选的修复方式
移除未使用的协议
Bundle内多Scale图片
Bundle内同一张图片包含多个Scale会导致更大的包体积。
扫描规则
同一个Bundle内存在同名但是scale不同的图片。例如a2x.png/a3x.png
可选的修复方式
移除Scale更低的图片
大资源
文件大小超过一定大小的即为大资源默认为20KB。
扫描规则
某个文件超过设置的大资源限额
可选的修复方式 移除资源动态下发 使用更小的数据格式例如使用更小的图片格式
重复的资源文件
存在多个同样的重复文件。
扫描规则
多个文件MD5一致即判定为重复文件。
可选的修复方式
移除多余的文件
未使用的类Property属性
ObjC类中定义的属性没有被使用到。
扫描规则 对应的属性没有被调用 set/get 方法同时也没有被_的方式使用 不是来自实现协议的属性 不是来自Category的属性 不存在字符串使用和属性名一致
可选的修复方式 移除对应的属性 如果是接口协议的属性需要添加类实现此接口
注意事项
可能存在部分动态使用的场景需要进行一定的检查。例如一些继承NSObject的数据模型类可能存在属性没有被直接使用到但是可能会被传唤成JSON作为参数的情况。例如后台下发的数据模型
未使用的ImageSet/DataSet
包含的Imageset/DataSet并没有被使用到。
扫描规则
未检测到和Imageset同样名字的字符串使用
可选的修复方式
移除ImageSet/DataSet
注意事项 某些Swift代码中使用的字符串不能被发现所以会被当做未使用。 使用字符串拼接的名字作为imageset的名字。 被合成到PackedAssetImage里的Imageset不能被扫描出来
未使用的ObjC方法
定义的ObjCCategory 方法并未被使用到。
扫描规则 不存在和此方法一样的方法名使用 不存在使用的字符串和方法名一致 不是来自父类或Category的方法 不是来自实现接口的方法 不是属性 set/get 方法
可选的修复方式
移除对应方法
未使用的分类方法
定义的ObjCCategory 方法并未被使用到。
扫描规则 不存在和此方法一样的方法名使用 不存在和方法名一致的字符串使用 不是来自父类或Category的方法 不是来自实现接口的方法
可选的修复方式 移除未使用的方法 如果是接口协议的方法需要添加类实现此接口
未使用的资源文件
包含的文件资源并没有被使用到。这里的资源不包含Imageset/DataSet。
扫描规则
未检测到和文件名同样名字的字符串使用
可选的修复方式
移除资源
注意事项 某些Swift代码中使用的字符串不能被发现所以会被当做未使用 使用字符串拼接的名字作为资源的名字
安全
动态反射调用ObjC类
存在类名和字符串一致可能使用NSClassFromString()方法动态调用类。当字符串或类名变更时无法利用编译时检查发现问题可能会导致功能异常。
扫描规则
存在使用的字符串和NSObject子类类名相同
可选的修复方式 使用NSStringFromClass()获取类名字符串 使用Framework外部的类应该使用方法封装除了少部分功能不应该使用反射去调用类 提示包含继承NSObject的 swift 类。 ObjC属性内存申明错误
一些特殊的NSObject类型的属性内存类型申明错误可能会导致功能异常或触发Crash。
扫描规则 NSArray/NSSet/NSDictionary类型的属性使用strong申明 NSMutableArray/NSMutableSet/NSMutableDictionary类型的属性使用copy申明
可选的修复方式
修改strong/copy申明
冲突的分类方法
ObjC同一个类的多个Category分类中存在多个相同的方法由于运行时最终会加载方法可能是不确定的可能会导致功能异常等未知的行为。
扫描规则
NSObject类的多个Category分类中存在多个相同的方法
修复方式
移除多余的分类方法
重复的分类方法
ObjC原始类和类的Category分类中有相同的方法分类中的方法会覆盖原始类的方法可能会导致功能异常等未知的行为。
扫描规则
NSObject原始类和类的Category分类中有相同的方法
修复方式
移除重复的分类方法
未实现的ObjC协议方法
类实现了某个ObjC协议但是没有实现协议的非可选方法。可能会导致功能异常或触发Crash。
扫描规则
类和分类未实现NSObject协议的非可选方法
可选的修复方式 对应的类实现缺失的非可选协议方法 将对应的协议方法标识为optional可选方法
重复的ObjC类
多个动态库和静态库之间存在同样的类。不会导致编译失败但是运行时只会使用其中一个类可能会导致功能异常或触发Crash。同时会增加包体积。
扫描规则
多个动态库和静态库之间存在同样的NSObject类符号
可能的修复方式
移除重复的类
性能
使用动态库
使用动态库会增加启动耗时。
扫描规则
Macho为动态库
可选的修复方式 使用静态库 使用Mergeable Library
实现load方法的类
APP启动后会执行所有load方法减少load方法可以降低启动耗时。
扫描规则
实现load方法的NSObject类
可选的修复方式 移除load方法 使用initialize替代
自定义配置
重要配置
systemFrameworkPaths
可以基于自身项目进行系统库目录的配置解析工程时也会对系统库进行解析。配置系统库目录对于未使用方法的查找可以提供更多的信息避免误报。但是配置更多会导致执行的更慢建议至少配置Foundation/UIKit。
unusedObjCProperty-enable
unusedObjCProperty规则默认不开启。
开启未使用属性检查以后会扫描macho的__TEXT段会增加分析的耗时。
unusedClass-swiftEnable
unusedClass-swiftEnable默认不开启。 开启Swift类检查以后会扫描macho的__TEXT段会增加分析的耗时。 未使用Swift类的项目建议不要开启如果考虑执行性能的话Swift使用相对比较多的再开启。 提示扫描macho的__TEXT段需要使用XCodeRun编译出的包不能直接使用用于上架APP Store构建出的包。主要是Debug会包含更多的信息用于扫描。 配置属性
/Users/Test/APPAnalyzeCommand -ipa /Users/Desktop/ipas/APPMobile/APPMobile.app -config /Users/Desktop/ipas/config.json --output /Users/Desktop/ipas/APPMobile
可基于自身项目需要添加下列规则可配置参数。在使用APPAnalyzeCommand指令时添加--config配置文件地址。
{systemFrameworkPaths: [/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/UIKitCore.framework/UIKitCore, /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation,/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/Foundation.framework/Foundation], // 配置系统库。会极大增加未使用方法的误报rules: {dynamicCallObjCClass: { // 动态调ObjC类enable: false, // 是否启用excludeClasslist: [ // 过滤类名NSObject,param]},incorrectObjCPropertyDefine: { // 错误的 ObjC 属性定义enable: false // 是否启动},largeResource: { // 大资源maxSize: 20480 // 配置大资源判定大小。默认 20480Byte20KB},unusedObjCProperty: { // 未使用的 ObjC 属性enable: false, // 是否启用。默认不开启excludeTypes: [NSString, NSArray, NSDictionary, NSNumber, NSMutableArray, NSMutableDictionary, NSSet] // 过滤掉部分类型的属性},unusedClass: { // 未使用的类swiftEnable: false, // 是否支持 Swift 类。默认不支持excludeSuperClasslist: [JDProtocolHandler, JDProtocolScheme],// 如果类继承了某些类就过滤excludeProtocols: [RCTBridgeModule], // 如果类实现了某些协议就过滤excludeClassRegex: [^jd.*Module$, ^PodsDummy_, ^pg.*Module$, ^SF.*Module$] // 过滤掉名字符合正则表达式的类},unusedObjCMethod: { // 未使用的 ObjC 方法excludeInstanceMethods: [], // 过滤掉某些名字的对象方法excludeClassMethods: [], // 过滤掉某些名字的类方法excludeInstanceMethodRegex: [^jumpHandle_], // 过滤掉名字符合正则表达式的对象方法excludeClassMethodRegex: [^routerHandle_], // 过滤掉名字符合正则表达式的类方法excludeProtocols: [RCTBridgeModule] // 如果类集成了某些协议就不再检查例如 RN 方法},loadObjCClass: { // 调用 ObjC load 方法excludeSuperClasslist: [ProtocolHandler], // 如果类继承了某些类就过滤excludeProtocols: [RCTBridgeModule] // 如果类实现了某些协议就过滤例如 RN 方法},unusedImageset: { // 未使用 imagesetexcludeNameRegex: [] // 过滤掉名字符合正则表达式的imageset},unusedResource: { // 未使用资源excludeNameRegex: [] // 过滤掉名字符合正则表达式的资源}}
}
组件化工程扫描
可以基于APPAnalyzeCore.framework定制实现自己的组件化工程扫描或者添加基于自身组件化工程的检查规则。详情可以看Demo。
基于组件化扫描方式有以下优势 细化数据粒度- 可以细化每个模块的包体积和包体积问题更容易进行包体积优化。 更多的检查- 例如检查不同组件同一个Bundle包含同名的文件不同组件包含同一个category方法的的实现。 检查结果更准确- 例如ObjC未使用方法的检查只要存在一个和方法名同样的调用就表示方法有被使用到。但是整个ipa中可能存在很多一样的方法名但是只有一个方法有真正被调用到如果细分到组件的粒度就可以发现更多问题。 提示只有APP主工程无代码全部通过子组件以framework的形式导入二进制库的方式的工程才适合这种模式。 其他
扫描质量如何
这套工具我们团队内部开发加逐步完善有一年的时间了。基于此工具修改了几十个组件的包体积问题同时不断的修复误报问题。目前现有提供的这些规则检查误报率是很低的只有极少数几个规则可能存在误报的可能性总体扫描质量还是很高的。
和社区开源的工具有什么差异
我们在早期调研了社区的几个同类型的开源工具主要存在以下几个问题 扩展性不够- 无法支持项目更好的扩展定制能力例如添加扫描规则、支持不同类型扫描方式、生成更多的报告类型。 功能不全- 只提供部分能力例如只提供未使用资源或者未使用类。 无法生成包体积数据- 无法生成包体积完整的数据。 检查质量不高- 扫描发现的错误数据多或者有一些问题不能被发现。
开源计划
后续一定会开源。主要是希望调整一些内部结构再开源开源后就不方便调整。顺便修复一些常见的问题。
开源带来的好处
开源带来的好处是部分工程可以基于自身的业务需要扩展定制自己的扫描工具。同时也可以将一些更好的想法实现添加进来。 扩展解析方式- 目前只支持ipa模式扫描很快会开放支持project组件化工程的扫描方式。基于组件化工程的扫描可以更加准确但是不同的公司组件化工程的构建方式可能是不一样的有需要可以在上层定制自身组件化工程的扫描解析。 扩展扫描规则- 虽然现在已经添加了比较多的通用性的规则同时提供了一定的灵活性配置能力。但是不同的项目可能需要定制一些其他的规则这些规则没办法通过在现有规则上添加配置能力实现。 扩展数据生成- 默认包里只包含两种数据生成包体积数据还有包体积待修复问题数据。可以扩展更多的数据生成格式例如我们自身的项目就有添加基于组件的依赖树格式。
后续规划
组件化工程支持
添加更多用于组件化工程的扫描
对于 Swift 更好的支持
对于Swift语言只要开启XCode编译优化以后就能在生成产物的时候支持无用代码的移除包括未使用类型和未使用方法的自动移除但是依然有部分场景不会进行优化。所以这一块也是后续完善的重点 未使用属性- 编译器不会对于未使用属性进行移除包括class和struct的属性。 未使用方法- 对于class的方法编译器并不会进行移除即使没有申明[objc](https://my.oschina.net/TnhqVdFXL8vnu)进行消息派发。
相关链接
Github地址 作者京东零售 何骁 来源京东云开发者社区 转载请注明来源