iOS 新机适配原理及更新三方应用——让 TIM 适配 Xs Max

背景

自从买了 iPhone Xs Max,就一直处于等待应用适配新设备的状态。不过本次增加的新屏幕(Xs Max)与 iPhone X 的屏幕比例相似,所以即使应用没有第一时间适配 Xs Max 机型,iOS 也会把应用的窗口以 iPhone X 为基础拉伸到满屏,以便最大限度的展示应用界面。相比之前推出 X 和 Plus 系列时,用户的过度成本降低了许多。

但是在苦苦等待过程中,腾讯的 TIM 一直没有得到更新。即便是等待苹果开售 iPhone Xr(Xr 在 Xs 开售后一个月才开售,所以开发者可能会等到 Xr 开售后才一起适配 Xs Max 和 Xr),还是等待苹果修复新的 Assets 压缩算法在 iOS 9 下闪退的 bug,微信也在年底前完成了 Xs Max 的适配,并且推出了微信 7.0。然而直到作者编写此文(2019年01月26日)时,TIM 依旧没有更新,粗糙的 UI 元素让人觉得不是一个 1 万块钱手机该有的界面。处于强迫症考虑,能否在没有三方应用源码的情况下让三方应用适配新的机型呢?

本文将通过以下几点的研究,来学习苹果的应用适配之道。

  • 在发布新设备之后,苹果如何让没有适配新设备的应用正常运行在新的设备上
  • 在发布新设备之后,开发者如何让自己的应用适配新的设备
  • 在发布新设备之后,如何让三方应用适配新的设备(以 TIM 为例)

另外简单介绍一下 TIM:

TIM 是腾讯推出的一款精简版的 QQ。腾讯已推出多个版本的QQ,如:QQ、国际版、HD 版、TIM。TIM 是一个面向工作、白领的一款产品。拥有强大的文件管理,以及精简的 UI 界面。由于他使用简单,办公高效,得到极多喜欢简约风格的用户(包括作者)一致好评。

PS:本文只探讨 iPhone,不探讨 iPad。

iPad 原理如同 iPhone。

iOS 如何兼容没有适配新屏幕的应用

即使苹果在开发者协议中注明:任何时候,开发者上传到 App Store 的应用必须适配最新的设备,否则被拒(你爸爸还是你爸爸)。苹果也无法保证在开售新设备的时候,已经在 App Store 上的应用全部都已被更新过。所以每当新设备(新屏幕)发布时,苹果都要在新的 iOS 系统中让新的设备兼容旧的应用。

先回忆一下苹果发布的几款机型(主要探讨屏幕),以及用户过渡期的处理方式(兼容已经在 App Store 上还未适配新设备的应用)。

从 2007 年第一代 iPhone 发布一直到 2018 年的 iPhone Xs Max,苹果一共发布了 8 款 iPhone 屏幕,它们分别如下(以搭载该屏幕的第一款设备命名,以发布时间及市场定位排序):

Name Pixel Size PPI Scale 过渡期的自适配方式
iPhone 320 x 480 320 x 480 326 1 iPhone 祖宗,无需适配
iPhone 4 640 x 960 320 x 480 326 2 宽度拉伸,高度拉伸,无黑边
iPhone 5 640 x 1136 320 x 568 326 2 宽度不变,垂直居中,上下黑边
iPhone 6 750 x 1334 375 x 667 326 2 宽度拉伸,垂直居中,上下黑边
iPhone 6 Plus 1242 x 2208 414 x 736 401 3 宽度拉伸,垂直居中,上下黑边
iPhone X 1125 x 2436 375 x 812 458 3 宽度拉伸,垂直居中,上下黑边
iPhone Xr 1242 x 2688 414 x 896 326 2 宽度拉伸,高度拉伸,无黑边
iPhone Xs Max 828 x 1792 414 x 896 458 3 宽度拉伸,高度拉伸,无黑边

如果新的设备的长宽比和旧的设备相同(Size 相同,或者 Size.width / Size.height 近似相同),如:iPhone 到 iPhone 4,iPhone X 到 iPhone Xs Max,就单纯的按照旧的设备来渲染(UIScreen.mainScreen.bounds 还是旧的设备的值),并且等比例拉伸到全屏,所以会变得有的线条有点粗犷 = =。

如果新的设备的长款比和旧的设备不同,如:iPhone 4 到 iPhone 5(脸被拉长了),iPhone 5 到 iPhone 6 和 Plus(不仅脸长了,还胖了)。就以宽度为基准尽可能的等比例放大,长度不够的黑边凑,同时整体垂直居中(这样就导致上下留有黑边)。

以上两种处理虽然最终都不能完美解决问题,但是至少保证旧的应用在渲染 UI 的时候不会因屏幕分辨率而导致布局错乱。

为什么有 Autolayout 还不能完美自适应呢?

因为你 Autolayout 再怎么牛逼,也躲不过无刘海到有刘海的变化。。。

应用开发者如何适配新的屏幕

对于使用 UIKit.framework 提供的几个常用接口来开发 UI 的应用,在适配新屏幕时就非常的简便,一般只有以下三步骤:

  1. 下载新的 Xcode
  2. 加入新屏幕对应大小的启动图
  3. 重新构建应用

对于大量自定义 UI 框架的应用(如自己重写了 UINavigationController),需要在代码中加入新设备的判断(此文不考虑这种情况)。

在这里必须吐槽一下,每当有新屏幕出现,网络上就有大量的博客:《教你如何适配新的 iPhone》,《适配新的 iPhone 看我就够了》,《你真的适配新的 iPhone 了吗》。。。
甚至有的公司为了适配新的 iPhone 花了至少一个工作日的时间。

如果应用使用苹果标准 API 构建界面,真的只需要添加一个启动图然后重新打包即可解决问题。

我们对每一个步骤进行一次分析:

1. 使用最新的 Xcode

使用最新的 Xcode 无疑是正确的。最新的 Xcode 可以给我们带来两个功能:

  • 新的 iOS SDK
  • 新屏幕的启动图坑位

这两个功能在适配新的设备时给了很大的帮助。新的 SDK 能够让应用在新的 iOS 系统上完美运行。新的启动图能够让应用获取到正确的屏幕大小。

2. 加入屏幕对应大小的启动图

如果某个应用使用纯代码开发(没有使用 Storyboardxib),那么这个应用的启动代码应该如下:

- (BOOL)application:(UIApplication *)application didFinishLaunchedWithOptions:(NSDictionary *)launchOptions {
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.window.rootViewController = [[ViewController alloc] init];
    [self.window makeKeyAndVisible];
}

适配新的屏幕,本质就是这个 self.window 对象的大小等于新的屏幕,然后子元素根据新的窗口大小来创建布局约束。

代码中动态使用 [UIScreen mainScreen].bounds 的大小来创建 window 对象,似乎是完美适配了任何大小的屏幕。但实际上,如果没有添加新的设备的启动图,UIScreen 获取到的屏幕大小并非真实设备的屏幕大小,而是 iOS 兼容模式所用的旧设备的屏幕大小。这是 iOS 兼容模式的一种优化,防止新的屏幕分辨率的出现导致应用 UI 控件布局错乱(宁愿等比例拉伸)。

3. 重新构建应用

不用多说了。

猜测——判断应用是否需要在兼容模式

首先有一个客观事实:

当新的设备发布后,如果使用旧的 Xcode 打包的 ipa 一样无法适配新机
如果使用新的 Xcode 并且没有加入新的启动图的 ipa 一样无法适配新机。

因此是否适配取决于 Xcode 版本号以及是否包含启动图,与打包的时间无关。

之前说明,开发者适配新设备的方法是:使用最新的 Xcode,加入新的设备的启动图后重新打包应用。所以 iOS 只需判断这个应用是否经过这样方式处理,就可以知道这个应用是否需要兼容模式下运行。

1. 判断是否包含启动图

判断是否是启动图是一件很简单的事情,只需要判断当前屏幕分辨率对应的图片是否存在在 .app 文件夹中即可,这个判断会经历从 Info.plist 读取启动图配置、查找启动图的几个阶段,此文不在阐述。

总之肯定会多一个 [email protected] 图片文件,并且分辨率和别的启动图不同。

2. 判断是否是新的 Xcode 打包

如何判断这个 ipa 是用什么版本的 Xcode 打的包呢?

在一个 ipa 包中有几个特殊文件:

  • Binary
  • Info.plist
  • _CodeSignature

clang 中不包含有 Xcode 版本信息,同时在编译的脚本中也没有将 Xcode 的版本信息作为参数传递给 clang,所以二进制(Binary)文件中不含有有关 Xcode 信息的数据。

_CodeSignature 是签名产物,签名时也没有 Xcode 信息,所以也不可能有 Xcode 信息的数据。

Info.plist 是 App 的 Manifest 文件,包含 App 的各种信息。这是我们着重考虑的方向。

分析 Info.plist 文件

打开一个自己做的 app 的 Info.plist 文件,可以查看到一下内容:

iOS 新机适配原理及更新三方应用——让 TIM 适配 Xs Max_第1张图片
Info.plist

其中红色标记的就是作者查找出来带有编译环境的信息:

  • DTSDKName 开发所用的 SDK 名称
  • DTXcode 开发所用的 Xcode 版本号(Xcode 10.1.0)
  • DTSDKBuild 开发所用的 SDK Build 号(SDK 内部版本号)
  • BuildMachineOSBuild 开发所用的机器 Build 号(Mac 的内部版本号)
  • DTPlatformVersion 开发所用的平台版本号
  • DTXcodeBuild 开发所用的 Xcode Build 号(Xcode 内部版本号)
  • DTPlatformBuild 开发所用的平台 Build 号(平台的内部版本号)

已经很完美了,Xcode、MacOS、SDK 版本号全都在。

同时我们也可以看见,如果应用使用的是启动图,而不是 Storyboard,在 Info.plist 文件中会包含一项 UILaunchImages:

iOS 新机适配原理及更新三方应用——让 TIM 适配 Xs Max_第2张图片
使用启动图的 Info.plist

由此我们可以猜测苹果的兼容方案。

苹果的兼容方案

当 iOS 要启动一个 App 时,会先读取 Info.plist 对应编译环境版本号,判断是否是新版 Xcode 打的包。如果是新版本的 Xcode,再判断是否包含启动图。如果包含启动图,则说明该 ipa 适配了新机,无需兼容。反之,使用兼容模式运行此 app。

iOS 新机适配原理及更新三方应用——让 TIM 适配 Xs Max_第3张图片
iOS 兼容模式

验证——将三方应用适配新机(以 TIM 为例)

鉴于以上的分析,只需要将 Info.plist 中的对应版本号提高,并且加入新的启动图即可实现三方应用适配新机。

1. 砸壳

由于所有在 App Store 上的应用均被苹果加壳,并且我们将来需要修改 Info.plist 文件,所以必须要重签名。因此我们所修改的 TIM 需要砸壳处理。

砸壳方式有很多种,此文不阐述。

参考:Clutch、frida-ios-dump 等等。

2. 修改 Info.plist 中的版本号

由于 Info.plist 中版本号有点复杂,有部分为内部版本号(需要查询),所以我将已经适配好 Xs Max 的应用拿来做参考,进行数据覆盖。

此处使用的是 WeChat 7.0.0 的 Info.plist 作为参考依据。将上述提到的 7 个字段的值,从微信的 Info.plist 文件里提取出来,覆盖到 TIM 的 Info.plist 文件中。分别是:DTSDKNameDTXcodeDTSDKBuildBuildMachineOSBuildDTPlatformVersionDTXcodeBuildDTPlatformBuild

除版本号外,Info.plist 也包含支持设备的硬件号,字段为 UISupportedDevices

通过助手类软件可以读出 Xs Max 设备号为 iPhone11,6,将其加入到 UISupportedDevices 字段中,防止安装时报错(不支持此设备)

3. 添加启动图

经过与微信的比较,发现 Xs Max 和 Xr 的启动图分别是:

名称 大小 机型
[email protected] 828 x 1792 Xr
[email protected] 1242 x 2688 Xs Max

终于祭出了自己的美工技术了。提取 X 的启动图,修改为上述两个文件,并添加到包中。

打开 Info.plist 文件,比较后在 UILaunchImages 的数组里添加两项启动图配置:


    UILaunchImageOrientation
    Portrait
    UILaunchImageName
    LaunchImage-1200-Portrait-2688h
    UILaunchImageSize
    {414, 896}
    UILaunchImageMinimumOSVersion
    12.0


    UILaunchImageOrientation
    Portrait
    UILaunchImageName
    LaunchImage-1200-Portrait-1792h
    UILaunchImageSize
    {414, 896}
    UILaunchImageMinimumOSVersion
    12.0

保存。

4. 重签名

重签名的方式有很多种,此文不再详述。

至于重签名后无法正常推送,不在此文的探讨范围,我就不详细说明了。

对比图

左侧为适配前,右侧为适配后

iOS 新机适配原理及更新三方应用——让 TIM 适配 Xs Max_第4张图片
聊天列表
iOS 新机适配原理及更新三方应用——让 TIM 适配 Xs Max_第5张图片
文件管理
iOS 新机适配原理及更新三方应用——让 TIM 适配 Xs Max_第6张图片
好友列表

适配后的 UI 变得非常的细腻。舒服~~

总结

Xcode 在打包的时候讲打包环境信息(各种版本号)保存到 Info.plist 中。iOS 运行应用时,通过 Info.plist 中的版本号进行比较,来判断开发者是否适配了新设备,从而判断是否需要兼容模式运行此应用。

你可能感兴趣的:(iOS 新机适配原理及更新三方应用——让 TIM 适配 Xs Max)