iOS 15 如何让 App 启动更快?

部署在 macOS 12 或 iOS 15 及更高版本操作系统上的所有程序及 dylibs现在都使用链式修复格式。这种格式使用不同的加载命令和 LINKEDIT 数据,不能在低版本的操作系统上运行或加载。

% xcrun dyldinfo -rebase -bind Snapchat.app/Snapchatrebase information (from compressed dyld info):segment section address type__DATA __got 0x10748C0C8 pointer...bind information:segment section address type addend dylib symbol__DATA __const 0x107595A70 pointer 0 libswiftCore_$sSHMp


一种新的格式
% otool -l iOS14Example.app/iOS14Example | grep LC_DYLDcmd LC_DYLD_INFO_ONLY% otool -l iOS15Example.app/iOS15Example | grep LC_DYLDcmd LC_DYLD_CHAINED_FIXUPScmd LC_DYLD_EXPORTS_TRIE

let bytes = (try! Data(contentsOf: url) as NSData).bytesbytes.processLoadComands { load_command, pointer inif load_command.cmd == LC_DYLD_EXPORTS_TRIE {let dataCommand = pointer.load(as: linkedit_data_command.self)bytes.advanced(by: Int(dataCommand.dataoff)).readExportTrie()}}extension UnsafeRawPointer {func readExportTrie() {var frontier = readNode(name: "")guard !frontier.isEmpty else { return }repeat {let (prefix, offset) = frontier.removeFirst()let children = advanced(by: Int(offset)).readNode(name: prefix)for (suffix, offset) in children {frontier.append((prefix + suffix, offset))}} while !frontier.isEmpty}// Returns an array of child nodes and their offsetfunc readNode(name: String) -> [(String, UInt)] {guard load(as: UInt8.self) == 0 else {// This is a terminal nodeprint("symbol name \(name)")return []}let numberOfBranches = UInt(advanced(by: 1).load(as: UInt8.self))var mutablePointer = self.advanced(by: 2)var result = [(String, UInt)]()for _ in 0..<numberOfBranches {result.append((mutablePointer.readNullTerminatedString(),mutablePointer.readULEB()))}return result}}

链

struct dyld_chained_ptr_64_rebase{uint64_t target : 36,high8 : 8,reserved : 7, // 0snext : 12,bind : 1; // Always 0 for a rebase};


% xcrun dyldinfo -rebase Snapchat.app/Snapchat > rebases% ruby -e 'puts IO.read("rebases").split("\n").drop(2).map { |a| a.split(" ")[2].to_i(16) / 16384 }.uniq.count'1554% xcrun dyldinfo -bind Snapchat.app/Snapchat > binds450

减少动态框架的数量
减少应用程序大小,从而减少内存页面的使用(这就是我制作 Emerge 的原因!)
将代码移出 +加载以及静态初始化程序
使用 更少的类
将工作推迟到绘制第一个框架后
参考链接:
[1] The symbol from dyldinfo is mangled, you can get the human readable name with xcrun swift-demangle '_$sSHMp'. [2] Exports are the second piece of a bind. One binary binds to symbols exported from its dependencies. [3] The same goes for binds, a pointer is actually a union of rebase and bind (dyld_chained_ptr_64_bind) with a single bit used to differentiate the two. Binds also require the imported symbol name which isn’t discussed here. [4] https://asciiwwdc.com/2016/sessions/406
iOS 15 内置原生壁纸下载 优酷 iOS 插件化页面架构方法 这也行?iOS后台锁屏监听摇一摇 189.31G iOS 学习资料分享 iOS APP图标版本化
评论

