还记得苹果在14系列发布了灵动岛,着实吸引了一大波眼球。且不论灵动岛美不美观、实用性如何,至少对于客户端程序员来说,又多了一个需要进行屏幕适配的情况。在灵动岛发布完有较长一段时间了,由于其他事情比较忙,一直没得空去关注和优化这方面的问题,正好有空做优化,适配的事情提上了日程,正好记录一下适配的过程。
就Unity3d的iPhone适配而言,实际上Unity提供了Screen.safeArea这个API可以获取安全区域的数据,而且是Unity经过换算的像素点位,之前使用它来适配普通刘海屏其实是可以的。但是这里存在着一个主要的问题,Unity收录的iPhone设备的信息有限或者计算方式落后了,只能准确识别出Unity版本对应更新年限之前的iPhone设备,读出的尺寸是错误的,导致此处还需要关心灵动岛的适配(即也许更新到Unity2023甚至更新可能就不用关心这个适配问题了)。
在灵动岛出来之前,iPhone适配其实主要就是刘海屏的适配。
这里搜集了两篇关于尺寸描述的文章,具体详情大家可以参考:
iPhone 14 Screen Sizes (useyourloaf.com)https://useyourloaf.com/blog/iphone-14-screen-sizes/
图解iPhone iOS灵动岛UI设计尺寸规范 (360doc.com)http://www.360doc.com/content/12/0121/07/8772388_1067786520.shtml
看以下的示意图,灵动岛安全区域(SafeArea)的高度与普通刘海屏相比要高出一截。
(图片来自上述文章,侵删)
具体而言,普通刘海屏的高度为47 points,而灵动岛的安全区高度达到59 points。
在上述的示意图中,我们可以看到所有的尺寸标注都是points。
熟悉iOS原生开发的童鞋肯定都对这个points了如指掌。
但是这里的问题在于,Unity的API能给我们提供的数据只有Screen.size之类的像素尺寸,此时我们需要做的事情其实就是需要把points转换到像素值。
简单的说,这里涉及到一个概念就是苹果的屏幕缩放参数(Native Scale factor)的概念,当设备的屏幕缩放参数是2x的时候,则上述的59points = 59 x 2 = 118px,如果是3x则是59 points = 59 x 3 = 177px。
这里笔者没有查到Unity有提供任何比较靠谱的API能够获取到这个Native Scale factor。有一种说法是使用DPI除以一个系数。此方法经尝试不可行,主要有两个问题:
a、有少量设备实测有偏差,即计算结果错误。
b、通过Unity的Screen.dpi字段获取到的DPI数值,在新款iPhone上也是错误的。这个也很好理解,因为比如Unity2020及更早等旧Unity版本,压根就没有关于新iPhone的信息。
所以暂时只是枚举了iPhone设备的型号。使用SystemInfo.deviceName字段去匹配。
截止到2023年底为止,需要适配的异形屏列表如下:
NativeScaleFacotrs {
["iPhone8,4"] = 2, -- iPhone SE
["iPhone10,3"] = 3, -- iPhone X
["iPhone10,6"] = 3, -- iPhone X
["iPhone11,2"] = 3, -- iPhone Xs
["iPhone11,4"] = 3, -- iPhone Xs Max
["iPhone11,6"] = 3, -- iPhone Xs Max
["iPhone11,8"] = 2, -- iPhone XR
["iPhone12,1"] = 2, -- iPhone 11
["iPhone12,3"] = 3, -- iPhone 11 Pro
["iPhone12,5"] = 3, -- iPhone 11 Pro Max
["iPhone12,8"] = 2, -- iPhone SE 2
["iPhone13,1"] = 3, -- iPhone 12 mini
["iPhone13,2"] = 3, -- iPhone 12
["iPhone13,3"] = 3, -- iPhone 12 Pro
["iPhone13,4"] = 3, -- iPhone 12 Pro Max
["iPhone14,4"] = 3, -- iPhone 13 mini
["iPhone14,5"] = 3, -- iPhone 13
["iPhone14,2"] = 3, -- iPhone 13 Pro
["iPhone14,3"] = 3, -- iPhone 13 Pro Max
["iPhone14,6"] = 2, -- iPhone SE 3
["iPhone14,7"] = 3, -- iPhone 14
["iPhone14,8"] = 3, -- iPhone 14 Plus
["iPhone15,2"] = 3, -- iPhone 14 Pro
["iPhone15,3"] = 3, -- iPhone 14 Pro Max
["iPhone15,4"] = 3, -- iPhone 15
["iPhone15,5"] = 3, -- iPhone 15 Plus
["iPhone16,1"] = 3, -- iPhone 15 Pro
["iPhone16,2"] = 3, -- iPhone 15 Pro Max
}
适配过程中遇到的另一个问题是,如何识别灵动岛设备。这个问题也没有查到任何便捷的方式。在此列举现有的灵动岛设备型号:
DynamicIslandDevices = {
"iPhone15,2", -- : iPhone 14 Pro
"iPhone15,3", -- : iPhone 14 Pro Max
"iPhone15,4", -- : iPhone 15
"iPhone15,5", -- : iPhone 15 Plus
"iPhone16,1", -- : iPhone 15 Pro
"iPhone16,2", -- : iPhone 15 Pro Max
}
实际上,普通刘海屏完全可以还使用Screen.safeArea去获取尺寸。只需要在判断前面先识别出灵动岛屏幕,用上述的尺寸和缩放系数换算出像素值,再按工程里Canvas的比例去换算对应需要挪动的数值就可以了。
上述方式虽然实现了适配,但是充满了枚举,是不想更新Unity并且希望热更就可以实现的妥协之举。明年再出新的设备又要加枚举。如果有更合适的方式,欢迎留言指教。
此外,过程中收藏到一个宝藏GitHub仓库,可以方便的查看iPhone设备型号对应的设备,不用每次都去网上到处找了,在此推荐一下:
pluwen/apple-device-model-list: All Apple devices model name list. 通过内部编号判断 iOS 设备型号。(已更新iPhone15系列) (github.com)https://github.com/pluwen/apple-device-model-list