iOS 应用瘦身 - App Thinning

1 App Thinning

App Thinning 是一种优化移动应用程序以减小其安装包大小并提高性能的技术。它是苹果公司为iOS应用程序开发的一种方法,目的是使应用程序更适合各种不同类型的iOS设备。

App Thinning 主要包括技术:

  • Slicing (iOS, tvOS)
  • Bitcode
  • On-Demand Resources (iOS, tvOS)

1.1 Slicing

iOS 9.0 及更高版本的设备支持切片 App。

Slicing 是为不同的目标设备和操作系统版本创建和交付 app bundle 变体的过程。当用户安装 App 时,系统会下载并安装用户设备和操作系统版本的变体。

Xcode 在开发过程中模拟切片,当在设备或模拟器中构建和运行应用时,Xcode 会对应用进行切片;当创建归档时,Xcode 会包含 App 的完整版本,但允许从归档中导出变体。

工作流程:

  1. 在 Xcode 中,指定目标设备并且使用资源目录(Asset Catalogs)提供多种分辨率的图片。资源只有使用 Asset Catalogs 才能正确使 Slicing 作用于资源文件
  2. 编译并运行到模拟器或者真机设备。Xcode 针对运行设备自动构建”变体App“,减少编译时间,同时支持在本地测试不同的变体
  3. Archieve,为目标设备在本地导出一个变体。可在本地导出多种“变体App“,测试并修复配置错误
  4. 上传到 App Store Connect。App Store 根据上传的 .ipa 归档文件创建“变体App“,“变体App“的数量取决于 Xcode project 配置的 architecture 和资源
  5. 上传在 App Store Connect 中发布一个预览版进行测试。通过 TestFlight 下载预览版,TestFlight 为目标设备下载合适的“变体App“
  6. 发布 App。App Store 为用户设备下载合适的“变体App“

1.2 Bitcode

Bitcode 是编译程序的中间表示形式。上传到 App Store Connect 且包含位码的 App 将在 App Store 上重新进行编译和链接。

在未来 Apple 新推出了新的 CPU 架构或者以后 LLVM 推出了一系列优化,Apple Store 会自动重新优化应用程序二进制文件,而无需再次提交新版本提交到 App Store。

开启步骤:Build Settings -> Enable Bitcode -> YES

启用 Bitcode 注意事项:

  • App 依赖的静态库、动态库、Cocoapods 管理的第三方库,都需要开启 Bitcode
  • 最终生成的可执行文件是 Apple 自动生成的,同时会产生新的符号表文件(dSYMs),需要符号重映射以确保正确地解析崩溃日志和调试信息

1.3 On-Demand Resources

按需加载(On-Demand Resources,ODR)

App Store 将部分资源托管在 Apple 服务器上,并为您管理下载。App Store 还对按需资源进行切片,进一步优化了 App 的变体。

注意事项:

  • 当用户进入到某个业务时,根据需要在后台下载按需资源。
  • 当不再需要按需资源且磁盘空间不足时,操作系统会清除这些资源。

按需加载配置 & 请求资源

使用按需加载功能:

  1. 开启步骤:Build Settings -> Enable On-Demand Resources -> YES
  1. 选中 Resources Tag 标签 -> Download Only On Demand -> 新增“+”并命名资源标签

Resources Tag 介绍:

  • Initial install tags:初始安装标签。资源会随着 App 从 App Store 下载而下载,会影响 ipa 的大小
  • Prefetch tag order:预取标签顺序。会在 App 下载后,开始下载相应的资源,此种资源并不会影响 ipa 的大小。适用于游戏场景
  • Dowloaded only on demand:仅按需下载。资源会在必要的时候主动触发下载,开发者控制下载时机
  1. 下载按需资源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
objectivec复制代码- (void)onDemandDownload {

// 创建资源请求,指定需要的资源标签
NSArray<NSString *> *tags = @[ @"ImageAssets" ];
NSBundleResourceRequest *request = [[NSBundleResourceRequest alloc] initWithTags:tags];

// 开始访问资源
[request beginAccessingResourcesWithCompletionHandler:^(NSError * _Nullable error) {
if (error) {
// 处理异常情况
[self handleResourceRequestError:error];
return;
}

// 资源下载完成,可以开始使用资源
dispatch_async(dispatch_get_main_queue(), ^{
// 在主线程中更新 UI 或执行其他操作
// 加载资源,例如显示图像
NSBundle *bundle = request.bundle;
UIImage *image = [UIImage imageNamed:@"exampleImage" inBundle:bundle compatibleWithTraitCollection:nil];
self.imageView.image = image;

// 使用完成后释放资源请求
[request endAccessingResources];
});
}];
}

- (void)handleResourceRequestError:(NSError *)error {
if (error.code == NSBundleOnDemandResourceOutOfSpaceError) {
// 处理空间不足错误
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Error"
message:@"Insufficient space on device. Please clear some space and try again."
preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
[self presentViewController:alertController animated:YES completion:nil];
} else if (error.code == NSBundleOnDemandResourceExceededMaximumSizeError) {
// 处理资源超出最大内存限制错误
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Error"
message:@"Resource exceeds maximum memory limit. Please remove some resources and try again."
preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
[self presentViewController:alertController animated:YES completion:nil];
} else if (error.code == NSBundleOnDemandResourceInvalidTagError) {
// 处理无效资源标签错误
NSLog(@"Invalid resource tag: %@", error.localizedDescription);
// 可以进一步确认正确的标签名称并修复 Bug
}
}

@end

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%