小小优酷ARM版Mac适配实践

2,141 阅读9分钟

背景

在WWDC20上,除了常规的iOS,macOS等系统升级以外,还有一个重量级消息同时宣布——Apple的Mac电脑将从x86架构转向ARM架构。

其实我们iOS开发对于ARM架构并不陌生,一直以来,iPhone和iPad的A系列处理器都是该种架构的芯片。而这一次苹果将Mac的CPU从x86迁移到ARM,不得不说也是其打造生态闭环,给用户一致体验的最后一块拼图。

一般而言,基于A架构编译的程序是不能跑在B架构的CPU上的,因此新架构第一步就要解决软件生态问题,不然大家买了新Mac没有程序可以运行岂不是相当于买了个大号板砖?但苹果到底是苹果,大家平常开发的iOS应用都是运行在A系列处理器上的,这可都是ARM架构。那只要稍微兼容一下,岂不是瞬间就把iOS的生态引入了Mac?

这也就是本篇文章要谈的,如何将你的iOS应用,适配运行在M1芯片的Mac,即ARM架构的Mac上。

设备样式

首先要确定,你希望此APP以何种设备样式运行在Mac上,具体而言就是iPhone还是iPad。

比如对于小小优酷而言,两者分别的运行效果如下(图片有点大,如果没显示出来点击放大查看):

Snip20210126_20.png

上图为以iPad样式运行

Snip20210126_21.png

上图为以iPhone样式运行

不难发现,在Mac这样的大屏设备上,iPhone样式实在是太小了,很难操作。因此除非你的应用强需求iPhone样式,不然都应该去适配iPad然后以iPad样式运行在Mac上。

如何让应用适配iPad,这个不是本文的范畴。只讲一下当你已经适配了iPad后,如何确保此APP是以iPad样式运行在Mac上的。

Snip20210126_6.png

如图所示,主要就是在target设置中,一定要勾选‘iPad’,这样你就会看到运行设备会变为‘Designed for iPad’,这样无论是你调试还是之后发布都会以iPad样式运行。

屏幕尺寸

当你确定样式之后,对于适配我们第一句想问的自然是:到底分辨率多少?

这个我可以直接在这里给出回答:当勾选Requires full screen后

设备样式

点尺寸

屏幕scale

备注

iPhone

375 * 667

1

无刘海和触控条

iPad

768 * 1024

1

无刘海和触控条

以上的表格可以看出,Mac上的iPhone和iPad样式在点尺寸方面还是很标准的,一个和iPhone6一致,另一个也和iPad6一致,都是常见机型,之前应用开发时都应该适配过。

但是还有一点需要我们注意——他们的屏幕scale都是1,和我们平时遇到的Retina屏幕为2或3不同。这会有两点影响:

1 我们常用scale是否大于1来判断Retina屏幕然后执行操作,这里要注意回归是否符合预期。

2 我们平常的资源因为不考虑非Retina屏幕,因此只会添加2x和3x图片。在Mac上,虽然苹果会帮我们去缩放,但是这不一定符合预期。因此也要注意回归各个本地图片,最好还是补上1x的图片

分屏

细心的读者可能发现,我在屏幕尺寸的表格前加上了一句限定——‘当勾选Requires full screen后’。这又是什么意思呢?

原来苹果自iOS9后,对与iPad应用提出了分屏的概念。即为了充分利用iPad的大屏幕,可以让多个应用同时运行在一个屏幕上:

fenping.jpg

如上图所示,此时对于其中的单个app,它的可使用尺寸肯定就不是屏幕大小了,而是用户给他分配的分屏大小。

因此,对于支持分屏的app,它可能运行的设备尺寸是千变万化的,不止局限于苹果发布的那些机型的屏幕尺寸。

当然,如果你觉得这些适配起来很复杂,你也不想搞什么分屏,那就直接在target上勾选‘Requires full screen’即可:

Snip20210126_7.png

这样你的app能保证一定全屏运行,可用尺寸和屏幕尺寸一致。反之,如果你想适配分屏,那么可以先按照网上的方法适配,然后这里不勾选即可。

那么分屏与否在Mac上是如何体现的呢?

以上是未勾选时的场景,可以发现能通过应用边缘的光标去调整app的尺寸,使之能有任意大小

以上是已勾选的场景,可以发现app边缘光标拖拽无效。

最终勾选与否,还是要看你实际的业务场景去决定。

转屏

一般而言,我们在APP上不同的页面有不同的方向,有的页面要竖屏,有的页面要横屏。因此我们的app需要能正确处理转屏。

如何处理转屏网上的文章有很多了,这里不多赘述。只说在Mac上转屏适配有一点不同:必须在target里勾选上适配的方向

Snip20210126_9.png

如上图,小小优酷是有横竖屏两种页面的,因此这里要对应都勾选上。

那如果没有勾选呢?这里以勾选Portrait与否为例:

注意上面是未勾选的情况,可以发现在转屏时发生了错误。但是不勾选时在iPhone和iPad上是可以正常转屏的,其实此时你在Mac上输出设配方向也是Portrait。暂时不知道这是否为Mac上运行iOSAPP的bug。

当勾选了Portrait后,可以发现此时转屏正常。

Metal

小小优酷具有视频播放功能,但是在Mac运行时,出现了视频播放bug。具体表现为播放黑屏但是声音正常,看上去是画面渲染有问题。因为小小优酷底层使用的并非AVPlayer而是aliplayer,因此第一感觉是底层播放器在Mac上运行时有一些坑没有注意到。

在调试过程中,对比在Mac上播放错误的log和iPhone上正常播放时的log,发现其中错误的log在播放中一直打印一句话:‘[CAMetalLayer nextDrawable] returning nil because device is nil.’

和播放器同学沟通后,拿到了他们的源码,发现他们有使用metal来渲染画面,而其中输出log的是一个CAMetalLayer,查看Apple对应源码后发现问题:

Snip20210126_10.png

对于CAMetalLayer这个类,其中有一个device属性,在注释中写的很清楚:对于iOS,它的默认值为defaultDevice,而对于macOS,它的默认值为nil。我们是在Mac上运行的APP,因此此时默认值和macOS一致,也是nil,这和在iPhone或iPad上运行是不一样的。

而当device为nil时,调用其nextDrawable方法,自然也会报‘’错误了

修复代码:

        if (!layer.device) {
            layer.device = MTLCreateSystemDefaultDevice();
        }

        [layer nextDrawable];

坑之coobjc

coobjc是阿里推出的一款面向iOS的协程库,小小优酷在之前的版本,看了一些宣推文档,有过引入以试图提升性能。

这个库在iPhone和iPad上表现还算良好,但是到了ARM版的Mac上直接必现崩溃。

这个我回看了它当时的一些宣推文章,发现它可能在CPU架构方面有一些trick操作,导致换了M1处理器就有问题。

不过好在这个库我们用的不是很多,而且都可以用dispatch的方式予以替换,最终解决该问题

这里附上coobjc的崩溃截图:

Snip20210126_11.png

杂项

这里是适配过程中的一些杂项处理:

判断APP是否在Mac上运行

+ (BOOL)isMacDevice
{
    if (@available(iOS 14.0, *)) {
        return [NSProcessInfo processInfo].isiOSAppOnMac || [NSProcessInfo processInfo].isMacCatalystApp;
    }
    if (@available(iOS 13.0, *)) {
        return [NSProcessInfo processInfo].isMacCatalystApp;
    }
    return NO;
}

版本判断

Snip20210126_13.png

可以发现,即便是在Mac上运行,返回的systemName和systemVersion也都是iOS的,而且可以通过@available的判断。

设备方向

Snip20210126_15.png

由上图可以看出,默认启动时,app的应用方向时横向的,而设备方向是未知(Unknown)。

而如果想改变默认的app启动方向,需要:

Snip20210126_14.png

想要改变应用默认的启动方向,需要在这里更改。

上架

经过一系列改造,我们终于可以尝试上架我们的iOS版MacApp了。但是需要注意的是:如果你已经开发了该app对应的Mac应用,是无法在同时上架iOS版APP的,只会显示Mac版。

上架需要我们去到该APP的苹果后台:

Snip20210126_16.png

在‘价格与销售范围’这一个tab下,勾选上如图所示的选项。

注意,这个勾选上后不是立即生效的,我这边大概过了一天多才能在Mac的AppStore上搜索到‘小小优酷’

Snip20210126_18.png

总结

上面关于适配的问题说了不少,这里可以做一个总结:

  • 除非有强需求,不然你的应用应该适配iPad样式,然后以iPad样式在Mac上运行

  • 注意Mac上iOS运行的屏幕scale为1,为非Retina屏幕

  • 如果不适配分屏,一定要记得勾选‘Requires full screen’

  • 一定要在target的设置中勾选上应用中可能出现的方向

  • 使用metal一定要注意,Mac上的默认device为nil,需要手动设置

  • 不要使用coobjc,使用dispatch代替

  • 上架iOSApp记得去苹果后台勾选,等大概一天左右即可搜索到。

结语

以上的章节,是我一个以小小优酷开发者去适配ARM版Mac走过的心路历程。也很荣幸我‘可能’是网上第一篇关于iOS应用如何适配ARM的Mac的文章,这里感谢一下组里的采购同学。

当然,囿于小小优酷毕竟是个相对小的APP,适配过程中肯定还有很多坑没有踩到,比如我这边编译都是一次成功的,并没有遇到Mac上的编译问题,因此如果你的APP出现了相关错误我暂时无法给出指导意见。

不过还是要赞一句苹果真牛,其实他已经帮我们做好了95%的事了,如果还有其他的问题,欢迎直接和我交流,一起总结适配Mac中的问题,完善这个亟待开发的领域。