Descubrir problemas automáticamente
-
Mejore la eficiencia: la resolución manual de problemas es ineficiente. Los problemas comunes deben analizarse automáticamente tanto como sea posible. Y para los proyectos en componentes, muchos componentes externos se proporcionan a través del marco y no existe ningún permiso de código fuente del almacén para analizar problemas de volumen de paquetes. -
Procesamiento: forme un proceso de calidad automatizado y agréguelo al proceso de CI para detectar automáticamente problemas de volumen de paquetes.
Cuantificación de indicadores de datos.
-
Problema de volumen de paquetes: proporciona una plataforma basada en datos para ver el volumen de paquetes de cada componente que se va a reparar. -
Tamaño del paquete: proporciona una plataforma basada en datos para ver la proporción del tamaño del paquete de cada componente, incluido el tamaño total, el tamaño binario de un solo archivo y el tamaño de cada recurso. Los datos del volumen del paquete en la granularidad del componente se pueden comparar para diferentes versiones de la aplicación, lo que facilita ver el incremento del tamaño del componente de cada versión.
Consejo: El método de escaneo basado en la ingeniería de componentes es compatible internamente, pero no está abierto al público por el momento.
Instalar
usar
$ /Users/Test/APPAnalyzeCommand --help
OPTIONS:
--version <version> 当前版本 1.0.0
--output <output> 输出文件目录。必传参数
--config <config> 配置JSON文件地址。非必传参数
--ipa <ipa> ipa.app文件地址。必传参数
-h, --help Show help information.
implementar
Consejo: No puedes utilizar los paquetes de la AppStore directamente. Los paquetes de la AppStore deben ser desgranados. Se recomienda utilizar el paquete XCodeDebug tanto como sea posible.
/Users/Test/APPAnalyzeCommand --ipa ipas/JDAPP/JDAPP.app --output ipas/JDAP
Consejo: si dice permiso denegado, simplemente ejecute sudo chmod -R 777 /Users/a/Desktop/ipas/APPAnalyzeCommand.
Generar productos
Información del volumen del paquete
-
app_size.html: muestra los datos del volumen del paquete de cada marco en ipa, que se pueden abrir directamente con un navegador.
Consejo: divida la granularidad según el programa principal y la biblioteca dinámica
-
framework_size.html: muestra todos los datos del volumen del paquete de un solo marco. No abra la página secundaria directamente.
Consejo: cuando XCode genera Assets.car, unirá algunas imágenes pequeñas en una imagen grande de PackedAssetImage.
-
package_size.json - datos JSON del volumen del paquete ipa
Problemas con el tamaño del paquete por solucionar
-
app_issues.html: muestra el volumen del paquete de cada marco en ipa y la cantidad de problemas que se solucionarán. Se puede abrir directamente con un navegador.
Consejo: divida la granularidad según el programa principal y la biblioteca dinámica
-
framework_issues.html: muestra datos detallados sobre todos los problemas que se deben solucionar en un solo marco. No abra la página secundaria por separado.
-
issues.json: datos JSON de problemas de volumen del paquete ipa que se van a reparar
Consejo: los datos json se pueden utilizar para crear su propia plataforma de datos y ampliar más capacidades. Por ejemplo, vea diferentes versiones de aplicaciones y admita la comparación de múltiples versiones de aplicaciones.
Introducción a la regla
Volumen de paquetes
clase no utilizada
Reglas de escaneo
-
No se encontró referencia a ninguna clase ObjC correspondiente. -
No se utiliza como clase principal -
Las cadenas no utilizadas y los nombres de clases son consistentes -
No se utiliza como tipo de atributo -
No se creó ni llamó ningún método -
El método +load no está implementado
Métodos de reparación opcionales
-
Eliminar clases no utilizadas -
Si la clase Swift solo usa métodos estáticos, considere cambiarla al tipo Enum. -
Si solo se usa durante la conversión de tipos, también se detectará como una clase no utilizada, como (ABCClass *)object;. Se recomienda comprobar si existen clases realmente relevantes y luego eliminarlas. -
Para ObjC, si solo se usa como tipo de parámetro de método, también se detectará como una clase no utilizada. Se recomienda eliminar los métodos relevantes.
Consejo: Eliminar una clase es relativamente seguro porque se producirá un error en tiempo de compilación si se usa después de eliminarla. Aunque se escanean y filtran llamadas de cadenas, se recomienda verificar si Runtime puede crearlas y llamarlas dinámicamente.
Protocolos ObjC no utilizados
Reglas de escaneo
-
La clase no hace referencia al protocolo correspondiente.
Métodos de reparación opcionales
-
Eliminar protocolos no utilizados
Múltiples imágenes a escala en paquete
Reglas de escaneo
-
El mismo paquete contiene imágenes con el mismo nombre pero a diferentes escalas. Por ejemplo [email protected]/[email protected]
Métodos de reparación opcionales
-
Eliminar imágenes con escala más baja
Grandes recursos
Reglas de escaneo
-
Un determinado archivo excede el límite máximo de recursos establecido
Métodos de reparación opcionales
-
Eliminar la entrega dinámica de recursos -
Utilice formatos de datos más pequeños, como formatos de imagen más pequeños.
Archivos de recursos duplicados
Reglas de escaneo
-
Si varios archivos tienen el mismo MD5, se determina que son archivos duplicados.
Métodos de reparación opcionales
-
Eliminar archivos redundantes
Atributo de propiedad de clase no utilizada
Reglas de escaneo
-
El atributo correspondiente no se ha llamado método set/get y no se ha utilizado de la manera _. -
No es una propiedad del protocolo de implementación. -
No es un atributo de la categoría -
No hay ningún uso de cadena coherente con el nombre del atributo.
Métodos de reparación opcionales
-
Eliminar el atributo correspondiente -
Si es un atributo de un protocolo de interfaz, debe agregar una clase para implementar esta interfaz
Precauciones
-
Puede haber algunos escenarios de uso dinámico que requieran ciertas comprobaciones. Por ejemplo, algunas clases de modelos de datos que heredan NSObject pueden tener atributos que no se usan directamente, pero pueden denominarse JSON como parámetros. Por ejemplo, el modelo de datos emitido en segundo plano.
Conjunto de imágenes/conjunto de datos no utilizados
Reglas de escaneo
-
No se detectó la cadena con el mismo nombre que Imageset.
Métodos de reparación opcionales
-
Eliminar conjunto de imágenes/conjunto de datos
Precauciones
-
Algunas cadenas utilizadas en el código Swift no se pueden encontrar y se tratan como no utilizadas. -
Utilice el nombre de la concatenación de cadenas como nombre del conjunto de imágenes. -
El conjunto de imágenes sintetizado en PackedAssetImage no se puede escanear
Método ObjC no utilizado
Reglas de escaneo
-
No existe ningún nombre de método idéntico a este método. -
La cadena utilizada no coincide con el nombre del método. -
Método que no pertenece a la clase principal o categoría -
No de un método que implementa una interfaz. -
No es un método de conjunto/obtención de atributos
Métodos de reparación opcionales
-
Eliminar el método correspondiente
Método de clasificación no utilizado
Reglas de escaneo
-
No existe ningún nombre de método idéntico a este método. -
No hay ningún uso de cadena coherente con el nombre del método. -
Método que no pertenece a la clase principal o categoría -
No de un método que implementa una interfaz.
Métodos de reparación opcionales
-
Eliminar métodos no utilizados -
Si es un método de un protocolo de interfaz, debe agregar una clase para implementar esta interfaz
archivos de recursos no utilizados
Reglas de escaneo
-
No se detectó ningún uso de cadena con el mismo nombre que el nombre del archivo.
Métodos de reparación opcionales
-
Eliminar recursos
Precauciones
-
Las cadenas utilizadas en algunos códigos Swift no se pueden encontrar y se tratan como no utilizadas -
Utilice concatenación de cadenas como nombre del recurso
Seguridad
Llamada de reflexión dinámica clase ObjC
Reglas de escaneo
-
La cadena utilizada es la misma que el nombre de la clase de subclase NSObject.
Métodos de reparación opcionales
-
Utilice NSStringFromClass() para obtener la cadena del nombre de la clase -
Las clases fuera del Framework deben encapsularse mediante métodos y, excepto algunas funciones, no se debe utilizar la reflexión para llamar a la clase.
Consejo: contenga clases rápidas que hereden NSObject.
ObjC属性内存申明错误
扫描规则
-
NSArray/NSSet/NSDictionary类型的属性使用strong申明 -
NSMutableArray/NSMutableSet/NSMutableDictionary类型的属性使用copy申明
可选的修复方式
-
修改strong/copy申明
冲突的分类方法
扫描规则
-
NSObject类的多个Category分类中存在多个相同的方法
修复方式
-
移除多余的分类方法
重复的分类方法
扫描规则
-
NSObject原始类和类的Category分类中有相同的方法
修复方式
-
移除重复的分类方法
未实现的ObjC协议方法
扫描规则
-
类和分类未实现NSObject协议的非可选方法
可选的修复方式
-
对应的类实现缺失的非可选协议方法 -
将对应的协议方法标识为optional可选方法
重复的ObjC类
扫描规则
-
多个动态库和静态库之间存在同样的NSObject类符号
可能的修复方式
-
移除重复的类
性能
使用动态库
扫描规则
-
Macho为动态库
可选的修复方式
-
使用静态库 -
使用Mergeable Library
实现+load方法的类
扫描规则
-
实现+load方法的NSObject类
可选的修复方式
-
移除+load方法 -
使用+initialize替代
自定义配置
重要配置
systemFrameworkPaths
unusedObjCProperty-enable
-
开启未使用属性检查以后,会扫描macho的__TEXT段,会增加分析的耗时。
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
{
"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 // 配置大资源判定大小。默认 20480Byte=20KB
},
"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": { // 未使用 imageset
"excludeNameRegex": [""] // 过滤掉名字符合正则表达式的imageset
},
"unusedResource": { // 未使用资源
"excludeNameRegex": [""] // 过滤掉名字符合正则表达式的资源
}
}
}
组件化工程扫描
-
细化数据粒度 - 可以细化每个模块的包体积和包体积问题,更容易进行包体积优化。 -
更多的检查 - 例如检查不同组件同一个Bundle包含同名的文件,不同组件包含同一个category方法的的实现。 -
检查结果更准确 - 例如ObjC未使用方法的检查,只要存在一个和方法名同样的调用就表示方法有被使用到。但是整个ipa中可能存在很多一样的方法名但是只有一个方法有真正被调用到,如果细分到组件的粒度就可以发现更多问题。
提示:只有APP主工程无代码,全部通过子组件以framework的形式导入二进制库的方式的工程才适合这种模式。
扫描质量如何
和社区开源的工具有什么差异
-
扩展性不够 - 无法支持项目更好的扩展定制能力,例如添加扫描规则、支持不同类型扫描方式、生成更多的报告类型。 -
功能不全 - 只提供部分能力,例如只提供未使用资源或者未使用类。 -
无法生成包体积数据 - 无法生成包体积完整的数据。 -
检查质量不高 - 扫描发现的错误数据多,或者有一些问题不能被发现。
开源计划
开源带来的好处
-
扩展解析方式 - 目前只支持ipa模式扫描,很快会开放支持project组件化工程的扫描方式。基于组件化工程的扫描可以更加准确,但是不同的公司组件化工程的构建方式可能是不一样的,有需要可以在上层定制自身组件化工程的扫描解析。 -
扩展扫描规则 - 虽然现在已经添加了比较多的通用性的规则,同时提供了一定的灵活性配置能力。但是不同的项目可能需要定制一些其他的规则,这些规则没办法通过在现有规则上添加配置能力实现。 -
扩展数据生成 - 默认包里只包含两种数据生成,包体积数据还有包体积待修复问题数据。可以扩展更多的数据生成格式,例如我们自身的项目就有添加基于组件的依赖树格式。
后续规划
组件化工程支持
对于 Swift 更好的支持
-
未使用属性 - 编译器不会对于未使用属性进行移除,包括class和struct的属性。 -
未使用方法 - 对于class的方法,编译器并不会进行移除,即使没有申明@objc进行消息派发。
相关链接
本文分享自微信公众号 - 京东云开发者(JDT_Developers)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。