ToB企服应用市场:ToB评测及商务社交产业平台

标题: iOS APP包分析工具 [打印本页]

作者: 滴水恩情    时间: 2024-1-8 12:36
标题: iOS APP包分析工具
介绍

分享一款用于分析iOSipa包的脚本工具,使用此工具可以自动扫描发现可修复的包体积问题,同时可以生成包体积数据用于查看。这块工具我们团队内部已经使用很长一段时间,希望可以帮助到更多的开发同学更加效率的优化包体积问题。
工具下载地址
背景

APPAnalyze工具最早诞生主要是为了解决以下包体积管理的问题:
对于定位下沉市场的APP来讲,包体积是一个非常重要的性能指标,包体积过大会影响用户下载APP的意愿。但是在早期我们缺少一些手段帮助我们更高效的去进行包体积管理。
自动发现问题

数据指标量化

实现方式

我们选择了不依赖源码而是直接扫描二进制库的方式来实现这个能力,总体的执行流程一下:

提示:基于组件化工程的扫描方式内部支持,只是暂时不对外开放。
使用指南

安装

无需安装。通过下载链接直接下载终端可执行命令文件APPAnalyzeCommand到本地即可使用。
APPAnalyzeCommand 下载地址
使用
  1. $ /Users/Test/APPAnalyzeCommand --help
  2. OPTIONS:
  3.   --version <version>     当前版本 1.0.0
  4.   --output <output>       输出文件目录。必传参数
  5.   --config <config>       配置JSON文件地址。非必传参数
  6.   --ipa <ipa>             ipa.app文件地址。必传参数
  7.   -h, --help              Show help information.
复制代码
执行

打开终端程序直接执行以下shell指令,即可生成ipa的包体积数据以及包体积待修复问题。
提示:不能直接使用AppStore的包,AppStore的包需要砸壳。建议尽量使用XCodeDebug的包。
  1. /Users/Test/APPAnalyzeCommand --ipa ipas/JDAPP/JDAPP.app --output ipas/JDAPP
复制代码
提示:如果提示permission denied没有权限,执行sudo chmod -R 777 /Users/a/Desktop/ipas/APPAnalyzeCommand即可。
生成产物


指令执行完成以后,会在ouput参数指定的文件夹生成APPAnalyze文件夹。具体文件介绍如下:
包体积信息

提示:按照主程序和动态库进行粒度划分


提示:XCode生成Assets.car时会将一些小图片拼接成一张PackedAssetImage的大图片。

包体积待修复问题

提示:按照主程序和动态库进行粒度划分



提示:json数据可用于搭建自己的数据平台,扩展更多的能力。例如查看不同APP版本以及支持多个APP版本对比等。
规则介绍


包体积

未使用的类

定义了类没有被使用到,包含ObjC类和Swift类。
扫描规则
可选的修复方式
提示:删除类相对是一种安全的行为,因为删除后如果有被使用到会产生编译时错误。虽然有做字符串调用的扫描过滤,不过还是建议检查是否可能被Runtime动态创建调用
未使用的ObjC协议

定义了ObjC协议没有被类使用
扫描规则
可选的修复方式
Bundle内多Scale图片

Bundle内同一张图片包含多个Scale会导致更大的包体积。
扫描规则
可选的修复方式
大资源

文件大小超过一定大小的即为大资源,默认为20KB。
扫描规则
可选的修复方式
重复的资源文件

存在多个同样的重复文件。
扫描规则

可选的修复方式
未使用的类Property属性

ObjC类中定义的属性没有被使用到。
扫描规则
可选的修复方式
注意事项
未使用的ImageSet/DataSet

包含的Imageset/DataSet并没有被使用到。
扫描规则
可选的修复方式
注意事项
未使用的ObjC方法

定义的ObjCCategory 方法并未被使用到。
扫描规则
可选的修复方式
未使用的分类方法

定义的ObjCCategory 方法并未被使用到。
扫描规则
可选的修复方式
未使用的资源文件

包含的文件资源并没有被使用到。这里的资源不包含Imageset/DataSet。
扫描规则
可选的修复方式
注意事项
安全

动态反射调用ObjC类

存在类名和字符串一致,可能使用NSClassFromString()方法动态调用类。当字符串或类名变更时无法利用编译时检查发现问题,可能会导致功能异常。
扫描规则
可选的修复方式
提示:包含继承NSObject的 swift 类。
ObjC属性内存申明错误

一些特殊的NSObject类型的属性内存类型申明错误,可能会导致功能异常或触发Crash。
扫描规则
可选的修复方式
冲突的分类方法

ObjC同一个类的多个Category分类中存在多个相同的方法,由于运行时最终会加载方法可能是不确定的,可能会导致功能异常等未知的行为。
扫描规则
修复方式
重复的分类方法

ObjC原始类和类的Category分类中有相同的方法,分类中的方法会覆盖原始类的方法,可能会导致功能异常等未知的行为。
扫描规则
修复方式
未实现的ObjC协议方法

类实现了某个ObjC协议,但是没有实现协议的非可选方法。可能会导致功能异常或触发Crash。
扫描规则
可选的修复方式
重复的ObjC类

多个动态库和静态库之间存在同样的类。不会导致编译失败,但是运行时只会使用其中一个类,可能会导致功能异常或触发Crash。同时会增加包体积。
扫描规则
可能的修复方式
性能

使用动态库

使用动态库会增加启动耗时。
扫描规则
可选的修复方式
实现+load方法的类

APP启动后会执行所有+load方法,减少+load方法可以降低启动耗时。
扫描规则
可选的修复方式
自定义配置

重要配置

systemFrameworkPaths

可以基于自身项目进行系统库目录的配置,解析工程时也会对系统库进行解析。配置系统库目录对于未使用方法的查找可以提供更多的信息避免误报。但是配置更多会导致执行的更慢,建议至少配置Foundation/UIKit。
unusedObjCProperty-enable

unusedObjCProperty规则默认不开启。
unusedClass-swiftEnable

unusedClass-swiftEnable默认不开启。
提示:扫描macho的__TEXT段需要使用XCodeRun编译出的包,不能直接使用用于上架APP Store构建出的包。主要是Debug会包含更多的信息用于扫描。
配置属性
  1. /Users/Test/APPAnalyzeCommand -ipa /Users/Desktop/ipas/APPMobile/APPMobile.app -config /Users/Desktop/ipas/config.json --output /Users/Desktop/ipas/APPMobile
复制代码
可基于自身项目需要,添加下列规则可配置参数。在使用APPAnalyzeCommand指令时添加--config配置文件地址。
  1. {
  2.     "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",
  3.         "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/Foundation.framework/Foundation"
  4.     ], // 配置系统库。会极大增加未使用方法的误报
  5.     "rules": {
  6.         "dynamicCallObjCClass": { // 动态调`ObjC类
  7.             "enable": false, // 是否启用
  8.             "excludeClasslist": [ // 过滤类名
  9.                 "NSObject",
  10.                 "param"
  11.             ]
  12.         },
  13.         "incorrectObjCPropertyDefine": { // 错误的 ObjC 属性定义
  14.             "enable": false // 是否启动
  15.         },
  16.         "largeResource": { // 大资源
  17.             "maxSize": 20480 // 配置大资源判定大小。默认 20480Byte=20KB
  18.         },
  19.         "unusedObjCProperty": { // 未使用的 ObjC 属性
  20.           "enable": false, // 是否启用。默认不开启
  21.           "excludeTypes": ["NSString", "NSArray", "NSDictionary", "NSNumber", "NSMutableArray", "NSMutableDictionary", "NSSet"] // 过滤掉部分类型的属性
  22.         },
  23.         "unusedClass": { // 未使用的类
  24.             "swiftEnable": false, // 是否支持 Swift 类。默认不支持
  25.             "excludeSuperClasslist": ["JDProtocolHandler", "JDProtocolScheme"],// 如果类继承了某些类就过滤
  26.             "excludeProtocols": ["RCTBridgeModule"], // 如果类实现了某些协议就过滤
  27.             "excludeClassRegex": ["^jd.*Module$", "^PodsDummy_", "^pg.*Module$", "^SF.*Module$"] // 过滤掉名字符合正则表达式的类
  28.         },
  29.         "unusedObjCMethod": { // 未使用的 ObjC 方法
  30.             "excludeInstanceMethods": [""], // 过滤掉某些名字的对象方法
  31.             "excludeClassMethods": [""], // 过滤掉某些名字的类方法
  32.             "excludeInstanceMethodRegex": ["^jumpHandle_"], // 过滤掉名字符合正则表达式的对象方法
  33.             "excludeClassMethodRegex": ["^routerHandle_"], // 过滤掉名字符合正则表达式的类方法
  34.             "excludeProtocols": ["RCTBridgeModule"] // 如果类集成了某些协议就不再检查,例如 RN 方法
  35.         },
  36.         "loadObjCClass": { //  调用 ObjC + load 方法
  37.             "excludeSuperClasslist": ["ProtocolHandler"], // 如果类继承了某些类就过滤
  38.             "excludeProtocols": ["RCTBridgeModule"] // 如果类实现了某些协议就过滤,例如 RN 方法
  39.         },
  40.         "unusedImageset": { // 未使用 imageset
  41.             "excludeNameRegex": [""] // 过滤掉名字符合正则表达式的imageset
  42.         },
  43.         "unusedResource": { // 未使用资源
  44.             "excludeNameRegex": [""] // 过滤掉名字符合正则表达式的资源
  45.         }
  46.     }
  47. }
复制代码
组件化工程扫描

可以基于APPAnalyzeCore.framework定制实现自己的组件化工程扫描,或者添加基于自身组件化工程的检查规则。详情可以看Demo。
基于组件化扫描方式有以下优势:
提示:只有APP主工程无代码,全部通过子组件以framework的形式导入二进制库的方式的工程才适合这种模式。
其他

扫描质量如何

这套工具我们团队内部开发加逐步完善有一年的时间了。基于此工具修改了几十个组件的包体积问题,同时不断的修复误报问题。目前现有提供的这些规则检查误报率是很低的,只有极少数几个规则可能存在误报的可能性,总体扫描质量还是很高的。
和社区开源的工具有什么差异

我们在早期调研了社区的几个同类型的开源工具,主要存在以下几个问题:
开源计划

后续一定会开源。主要是希望调整一些内部结构再开源,开源后就不方便调整。顺便修复一些常见的问题。
开源带来的好处

开源带来的好处是,部分工程可以基于自身的业务需要,扩展定制自己的扫描工具。同时也可以将一些更好的想法实现添加进来。
后续规划

组件化工程支持

添加更多用于组件化工程的扫描
对于 Swift 更好的支持

对于Swift语言只要开启XCode编译优化以后就能在生成产物的时候支持无用代码的移除,包括未使用类型和未使用方法的自动移除,但是依然有部分场景不会进行优化。所以这一块也是后续完善的重点:
相关链接

作者:京东零售 何骁
来源:京东云开发者社区 转载请注明来源

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4