iOS代码瘦身实践之怎么删除无用的类

  介绍

这篇文章将为大家详细讲解有关iOS代码瘦身实践之怎么删除无用的类,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

<强>前言

本文将提供一种静态分析的方式,用于查找可执行文件Mach-o中未使用的类,源码链接:xuezhulian/classunref (本地下载)。

Mach-o文件中__DATA __objc_classrefs段记录了引用类的地址,__DATA __objc_classlist段记录了所有类的地址,取差集可以得到未使用的类的地址,然后进行符号化,就可以得到未被引用的类信息。

<强>引用类地址

可以通过Mac自带的工具otool打印Mach-o中的段信息,需要注意的是模拟器和真机对应的可执行文件,数据的存储方式不同需要加以区分。

可以通过文件命令获取到拱门。

# binary_file_arch: distinguish  Big-Endian 以及低位优先   # file  -b  output 例如:,Mach-O  64 - bit  executable  arm64   binary_file_arch =, os.popen (& # 39; file  -b  & # 39;, +,路径).read () .split (& # 39;, & # 39;) [1] .strip ()

在取类地址的时候区分x86_64和手臂。

def  pointers_from_binary(线,,binary_file_arch):=,行,line  [16:] .strip () .split (& # 39;, & # 39;)=,pointers 设置()==,if  binary_file_arch  & # 39; x86_64 # 39;:   #才能untreated  line 例如:00000001030 cec80 d8  75年,15,03年,01,00,00,00,68,77,15,03年,01,00,00 00   pointers.add才能(& # 39;& # 39;. join(线[4:8][::1],+,行[0:4][::1]))   pointers.add才能(& # 39;& # 39;. join(线[12:16][::1],+,行[8:12][::1]))   return 才能指针   ,# arm64 证实,armv7  arm7s 未经证实   ,if  binary_file_arch.startswith(& # 39;手臂# 39;):   #才能untreated  line 例如:00000001030 bcd20 03138580  00000001, 03138878, 00000001   pointers.add才能([1]行,+,行[0])   pointers.add才能(行[3],+,行[2])   return 才能指针   ,return 没有

通过otool - v - s __DATA __objc_classrefs获取到引用类的地址。

def  class_ref_pointers(路径,binary_file_arch):   ref_pointers =,才能设置()   lines 才能=,os.popen (& # 39;/usr/bin/otool  -v  -s  __DATA  __objc_classrefs  % & # 39;, %,路径). readlines ()   for 才能;line 拷贝:   ,,,pointers =, pointers_from_binary(线,,binary_file_arch)   ,,,ref_pointers =, ref_pointers.union(指针)   return 才能ref_pointers

<强>所有类地址

通过otool - v - s __DATA __objc_classlist获取所有类的地址。

def  class_list_pointers(路径,binary_file_arch):   list_pointers =,才能设置()   lines 才能=,os.popen (& # 39;/usr/bin/otool  -v  -s  __DATA  __objc_classlist  % & # 39;, %,路径). readlines ()   for 才能;line 拷贝:   ,,,pointers =, pointers_from_binary(线,,binary_file_arch)   ,,,list_pointers =, list_pointers.union(指针)   return 才能list_pointers

<>强取差集

用所有类信息减去引用类的信息,此时我们可以拿到未使用类的地址信息。

unref_pointers =, class_list_pointers(路径,binary_file_arch),安康;class_ref_pointers(路径,,binary_file_arch)

<强>符号化

通过纳米纳米命令可以得到地址和对应的类名字。

def  class_symbols(路径):   symbols 才能=,{}   #才能class  symbol  format 得到纳米:,0000000103113 f68  (__DATA __objc_data), external  _OBJC_CLASS_ _EpisodeStatusDetailItemView美元   re_class_name 才能=,re.compile (& # 39; (\ w {16}),。*, _OBJC_CLASS_ \ $ _ (+) & # 39;)   lines 才能=,os.popen (& # 39; nm  -nm  % & # 39;, %,路径). readlines ()   for 才能;line 拷贝:   ,,,result =, re_class_name.findall(线)   ,,,if 结果:   ,,,,,(地址,符号),[0]=,结果   ,,,,,符号(地址),=,象征   return 才能;符号

<>强过滤

在实际分析的过程中发现,如果一个类的子类被实例化,父类未被实例化,此时父类不会出现在__objc_classrefs这个段里,在未使用的类中需要将这一部分父类过滤出去。使用otool ov可以获取到类的继承关系。

def  filter_super_class (unref_symbols):   re_subclass_name 才能=,re.compile (“\ w {16}, 0 x \ w {9}, _OBJC_CLASS_ \ $ _ (+)“)   re_superclass_name 才能=,re.compile (“\ s * superclass  0 x \ w {9}, _OBJC_CLASS_ \ $ _ (+)“)   # subclass 例如:才能,0000000102 bd8070  0 x103113f68  _OBJC_CLASS_ _TTEpisodeStatusDetailItemView美元   # superclass 例如:才能,superclass  0 x10313bb80  _OBJC_CLASS_ _TTBaseControl美元   时间=lines 才能;os.popen (“/usr/bin/otool  -oV  % s", %,路径). readlines ()   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null

iOS代码瘦身实践之怎么删除无用的类