大多数浏览器和
Developer App 均支持流媒体播放。
-
让适用于 Mac 的 iPad App 更上一层楼
macOS Catalina 可让您轻松地将自己的 iPad app 引入到 Mac,同时只需要维护单一代码库。了解您可通过哪些方式让 app 在默认行为的基础上加以拓展,以针对 Mac 优化其界面。概括了解您可以使用的 API,以及需要考虑的 macOS 设计准则。了解 iPad app 生命周期在 Mac 上的对应情况,并获取您的 app 的分发详情。
资源
相关视频
WWDC22
WWDC20
WWDC19
-
下载
(把对Mac引入iPad app 提升到一个新层级) 下午好
我是Jamie Montgomerie 我来自UIKit团队 我将和我的同事Glen、Nils 和Chris一起 与大家分享 把对Mac引入iPad app 提升到一个新层级
在我们的第一场演讲关于对Mac 引入iPad app的介绍中 我们讲了一些基本知识 我们讲了如何创建app 并讨论了一些你应该引起注意的 主要的API的不同点
在这场演讲中 我们会讲如何更进一步 并让你的app更好地 在Mac上运作 包括多平台之间的区别 再提一下设计注意事项 讲一下Mac上的app生命周期 有什么不用 讨论如何分配你的app (让你的app更进一步 app生命周期) (让你的UIKit app 成为更好的Mac app) 让我们讲一下让UIKit app 成为更好的Mac app
要记住的第一件事 就是iPad版app越好 Mac版app也越好
我们会讲你可以采取的一些措施 从而使你的app在iPad 和Mac上都变得更好 (iPad app越好 Mac app也越好)
在iPad上 你的app 可以在所有型号的设备上运行 从iPad Mini中侧拉到漂亮 的12.9英寸iPad Pro
但现在要在Mac上运行 还不止这些 你的app可以在27英寸的 iMac上全屏运行
它的屏幕尺寸比例因子是77%
事实上 27英寸显示屏 更像是一台35英寸的iPad
因此app非常适合那个窗口
因此使用最佳范例 支持动态类型并使用自动布局 最后请记住 app在Mac上 重新调整尺寸的速度很快 你的布局代码的运行速度 能达到每秒60帧吗? 如果不能 你应该使用我们的 仪器性能工具来检查一下
(实施强大的键盘支持) 接下来实施强大的键盘支持 所有Mac都配有键盘 且Mac用户的双手总放在键盘附近 现在iPad配有键盘的情况 越来越常见了 你可以用我们的UIKeyCommand类 来响应键盘捷径
你可以在你的视图控制器中 响应标准的响应器动作 比如剪切、复制和粘贴方法
并注意你的响应器ping 设置第一响应器 从而容纳键盘命令 这对于iPad也有帮助
如果你的app是个游戏app 对于你的iOS和Mac用户来说 考虑支持游戏控制器会让体验变得 更优秀
(充分利用拖放)
那么几年前 我们在UIKit中引入了 一些很棒的拖放API 现在iPad用户期待能使用拖放 而且Mac用户也期待很久了
充分利用UI拖拽交互 和UI释放交互 将取悦你的Mac和iPad用户
(使用最新的API) 这总是一个好建议 使用最新的API 如果你暂时还没有这样做 现在是时候检验你的app了 看看是否使用了弃用的API
我说过这总是一个好建议 但今年更是如此 正如我们在介绍演讲中所讨论的那样 许多弃用的iOS API 只是在Mac上不可用
因此请使用WKWebView 而不是UIWebView 使用Metal 而不是OpenGL ES 我们一直在努力开发这些 先进的替代方案 使用它们可以 让你在iPad和Mac上 充分利用我们所做出的努力
最后请支持我们的 新iOS 13功能
比如 如果你在iPad app中 支持多窗口 每个UI窗口场景在Mac上 都是一个窗口
在iPad上支持暗黑模式 那你在Mac上也同样支持暗黑模式
我本可以把它作为单独的一场演讲 但今年有太多场演讲了 请浏览一下演讲目录 并参加一些你感兴趣的演讲 请记住iPad版app越好 Mac版app也越好
(好的Mac app包含 针对MAC所做出的改善) 那么iPad版app越好 Mac版app也越好 但好的Mac app同时也包含 仅针对Mac所做出的改善
我们要了解一下你可以采取哪些措施 让你的UIKit app 在Mac上性能更好
这里包含很多东西 他们耗费了大量的精力 充分利用现有UIKit API 来实现独一无二的Mac功能
其中一些API 在Mac上是全新的功能 或至少对于UIKit开发人员来说 是全新的功能
我们要快速看一下 现在有多少API可用
那么提到Mac独有功能 你想到的第一件事是什么? 对我来说 是菜单栏
全局菜单栏是Mac所独有的功能 它们存储用户在一个地方可以采取的 所有可能的行动 并把它们在屏幕顶部整洁地隐藏起来
它们对于app来说是全局性的 并且其中的菜单项根据用户的行动 被启用或禁用
因此对于Mac上的 iPad app来说 你可以接受默认菜单栏 不需要任何额外的工作
你还可以在界面创建器中组建菜单栏 就像我们在第一场演讲中 所看到的那样
或者对于字段控件 你可以在代码中进行自定义
那么我之前讲过 UIKeyCommand了 如果你是个眼尖的API开发人员 你会注意到 今年出现了一个新的UI命令超类
与它一起的还有UIMenu 和UIMenuBuilder 功能是让你全权控制Mac菜单栏 我们一会将看到一个 与此有关的演示
关于这个API的一个好消息 就是你在菜单中使用的 UIKeyCommands也将在iPad上可用 当你按下Command键时 将在发现生成器中显示 UIKeyCommand
因此如果你使用这个API 以获得更好的Mac版app 你也可以用它来让你的 iPad版app变得更好
(情境菜单) 现在Mac中还有另一种菜单 情境菜单 点Control或右击显示 与主菜单不同 它的内容是动态的 它们基于鼠标指示下的内容
在iOS 2中我们有一个强大的 新UIKit API可用 UIContextMenuInteraction
它使用UICommand 以及它的兄弟UIAction UIAction是基于区块的 所以也许更适合这种菜单
这个跨平台API在Mac上的功能 独一无二 显示我们都经常使用的情境菜单
要了解更多关于这个API的信息 你应该查看我们的 针对iOS 13对你的UI 进行现代化处理演讲
(侧边栏) 我们讲了一些新UIKit API 这是一个老UIKit API UISplitViewController
Mac上的侧边栏 与iOS分屏中的非常类似 它们通常用于掌握UI的详情类型
在Mac上UISplitViewController 管理视图 自动调整拖动尺寸 从最小栏宽到最大栏宽 你可以使用我们的新 primaryBackgroundStyle属性 让左边的栏拥有Mac侧边栏的外观
当你使用侧边栏背景样式时 所嵌入的使用任意一个 群样式的表视图 将呈现一个源列表 比如外观 就像在Mac上一样 我们马上会在演示中看到这个
iPad上不存在悬停 但对于Mac用户来说却非常熟悉
我们添加了一个 使用手势识别器的新方式 UIHoverGestureRecognizer 它允许你在UIKit app中 使用悬停 在这个屏幕上 你可以看到我们的股票app 很好地利用了悬停 当用户在价格表上移动时显示价格
(Mac工具栏)
对于在Mac上完全不同的东西来说 我们已经有了一些 很棒的Mac API 其中一个例子就是工具栏 Mac app通常 在窗口顶部显示工具栏
因为这是只有Mac才拥有的功能 我们披露了仅适用于Mac的API NSToolbar 你可以通过UIWindowScene的 titlebar属性获取它
稍后也会有相关演示
(触控栏) 另一个Mac独有的栏是触控栏 触控栏在Mac上 在MacBook Pro上 它们位于键盘上方 与情境菜单不同 其中的内容取决于用户正在做的操作
为了让你支持触控栏 我们对UIKit app披露了 现有的NSTouchBar类 它通过新的UIResponder 和UIViewController API可用
(其它Mac功能) 当然还有其它 你可以采用的Mac功能 你可以控制窗口的尺寸调整 你可以使用iOS打印API 在Mac上实施打印支持
你可以出版一本帮助手册 让你的用户直接从帮助菜单访问帮助 并且你可以自定义 自己的资产和字符串 使你的app看起来 更像是Mac版的app
(Mac app图标) 现在 最后但并不是最不重要的 我要提一下app图标
如果你什么也不做 Mac版app 将使用你iPad版app的图标 但Mac的样式与 iPad的样式不同 因此你还可以给Mac版 创建一个app图标
这听起来很微不足道 但这是你用户看到的第一个元素 因此我鼓励你们花点时间和努力 创建Mac版图标
(演示) 现在我要向大家介绍 我的同事Glen 他会给大家演示如何让iPad版 app成为更好的Mac版app
谢谢Jaime
正如我的同事刚说过的 iPad版app越好 Mac版app也越好 让我们来看个例子
在这里我们有一个叫做 ChocolateChip的app 它是一款iPad app 显示美味的菜谱
在之前的演示中
我们所做的一切就是…
好的 让我们等待它加载出来 在之前的演示中 我们只勾选了这里的Mac复选框
修复所有的创建问题 并创建和运行app 就像这样
好的 要花一点时间
正如你所看到的 我们有了一个全新的Mac app 拥有你所期待的 Mac app的所有细节 比如 你可以四处拖动 窗口中所显示的所有内容
并且如果你支持不同的屏幕尺寸 以及优化绘制 就像Jamie所建议的那样 你也会获得窗口快速、 流畅地重调尺寸的功能 就像这样
现在如果你实施它 将在表视图控制器中回调现有移动 你还可以在表视图控制器中 进行重新排序 就像这样 而不需要进入单独的编辑模式 那么这是个Mac功能
接下来我们使用了新的 UIContextMenuInteraction API 是我们今年引入的API
给它配置正确的UIAction 和UICommand
然后就可以完美地把你的情境菜单 迁到Mac上
因此在这里我得到了添加到收藏夹 我可以把甜甜圈作为我的收藏 或我也可以取消收藏
现在谈谈菜单
你还可以得到一个默认菜单栏 拥有所有
你惯用的默认菜单项 比如剪切、复制、粘贴、取消和重做 这些项 菜单项的启用或禁用 取决于响应器链上的东西
最后如果你使用iOS中的 新暗黑模式API 并使用这些系统颜色 指定你自己的颜色
那么暗黑模式效果也会很不错
正如你所看到的 一切都变暗了
并且你所有的颜色都已经设置好了 而且你所有的突显 也都进行了正确的设置 而所有这一切 都不需要添加任何一行代码
是的 谢谢
但如果你想把你的app 提升到下一个层级该怎么做呢? 如果你想让它在Mac上看起来 或感觉起来更像是Mac app 我们要怎么做呢? 嗯 今天让我们修复三个功能
侧边栏、工具栏和菜单栏
那么看起来 今天我将是你们友好的酒保
是的 谢谢
好的 第一件事是… 请看这里的这个主视图 这是常规的分屏控制器的主视图 但它确实应该看起来像一个 Mac工具栏 那么让我们设置… 让我们看看如何设置工具栏的样式
首先我们进入 RecipeSplitViewController 我们需要钩住viewDidLoad… 委托调用
在这里 我们的调用必须针对Mac 对UIKit进行条件化
从而它只应用于Mac创建
我们只需要插入一个 primaryBackgroundStyle
以及你知道的 侧边栏的一个新枚举 那么通过这一行代码 我们现在有…
我们进行了快速重新创建
我们现在有侧边栏样式了
只是为了给你展示它的样子 并让你确信 它真的看起来像是个侧边栏 当我四处移动它时 你可以看到它有侧边栏的半透明性
你还可以设置侧边栏的其它特性 在通用偏好中 设置侧边栏图标尺寸 在这里我把它设置为小图标 你可以看到它进行了动态更新 你还可以把它设为大图标
我要把它设为中图标 跟以前一样 重排序…跟以前一样
好的
抱歉 返回到app中
接下来 我们应该有一个工具栏 我们有整合到标题栏中的许多小工具 因此…
用户可以点击他们常用的命令 现在这与iOS不同 工具栏一般处于app底部
我们有一个用于筛选菜谱的小工具 我们还有一个 用于添加新菜谱的小工具 因此让我们看看该如何实现
我们要进入场景委托 在这里在场景委托中 我们要钩住场景 willConnect回调
我们要对UIKitForMac 也进行条件化 从而使它只在Mac中应用
我们要深入到场景的对象模型中… 这里的windowScene 并获取这个叫做 titlebar的对象 Titlebar允许我们设置 工具栏以及修改标题栏是否可见 因此让我们创建一个新工具栏
请注意 现在我正在使用NS前缀 这实际上是一个AppKit对象
我需要给它赋予一个标识符
之前我已经设置好一个标识符了
现在我所需要做的就是标题栏 我想把工具栏设置到 我刚创建的工具栏 那么通过这两行代码 我现在已经创建了一个 附加到标题栏上的工具栏
但这个代码并不是特别有意思 或者结果并不是特别有意思 因为 我们实际上需要配置实际项的工具栏 让我们看看如何实现
我要让你来分配这个代码
首先 我们要获取…我们需要获取 rootViewController
然后我们把它传给 ToolbarDelegate的初始化工具 它是我们创建的一个类
然后我们设置委托 我们想让用户自定义工具栏 我们还想使 navigationItem居中 navigationItem 就是我刚才讲过的筛选器 最后我想把 titleVisibility设置为隐藏 从而标题不会覆盖…
我刚才所创建的导航项
通过迅速重编译和创建 我们现在有工具栏了
你可以看到工具栏有 针对各种膳食的筛选器 因此 你知道的 对于早餐 我觉得我想吃甜甜圈
对于午餐 我想吃披萨
对于晚餐 我想吃意面 对于甜点 我很可能不想再吃意面了
哇哦 是巧克力片饼干
是的 我们还有一个加号小工具 或添加菜谱项小工具 允许我们添加新菜谱
好的
最后我们实际上还应该自定义菜单栏 从而使用户们可以在便利的位置 找到他们想要的全部命令 你可以在菜单栏中放置 你想要放置的全部命令 系统会相应地启用或禁用它们 与此相对的是在工具栏中 你可能只想放一些常用的命令
在介绍演讲中 我们讲了如何在工具栏中放常用命令 通过从Xcode界面创建器中 拖出菜单栏实现 但有时你想在运行时 更好地控制你的菜单 因此我要告诉你如何通过代码实现
我们要做什么? 我们要移除格式按钮 因为格式按钮看起来用处不大
因为这个app没有 任何可编辑的文本 因此在字体菜单或甚至是文本对齐 用处都不大
我们还要向文件菜单中 添加两个菜单项 那么在这里 我想添加一个新菜谱命令 类似于这里的添加菜谱小工具
我们还要添加一个命令 用于添加或移除收藏状态 类似于这里的情境菜单
好了 让我们看看要如何实现
我们要进入app委托 在这里在app委托中 我们需要重写一个方法
这个方法是带有创建器的 buildCommands 它传递一个 UICommandBuilder 在后续的种子中 这将被叫做buildMenu 并且… buildMenu带有创建器 系统会给它传递一个UIMenuBuilder 因此请注意 如果你正在使用当前的种子
你需要做的第一件事就是 确保我们当前是在 创建主菜单 在这里我们要检查系统是否为主系统 有时候你会得到 一个.context 如果你创建的是情境菜单
于是我们需要与创建器沟通 那么创建器 我想移除
一个特定菜单 在这里我想要移除的这个菜单 是一个格式菜单 正如你所看到的 代码完成给你提供了许多帮助 并建议你实际上可以移除哪种菜单
快速创建和运行 你可以看到 我们已经从编辑和浏览中间 移除了格式菜单
让我们返回去看这个 创建器实际上非常灵活 你可以实现一切操作 从替换整个菜单结构 到做出选择性编辑 比如我所做的操作
好的 我要做的下一件事是 我实际上想插入内容 让我们与创建器沟通一下 比如说在开始插入一个子菜单 插入到这里的文件菜单中
这个内容怎么样?
在这里我有一些 要添加的命令 第一个是 newRecipeCommand 它是一个关键命令 钩住createRecipe方法
它是一个关键命令 因此它会取出输入 和命令及选项 因此如果你按命令选项f 你还可以调用 这个UIKeyCommand 拥有UIKeyCommand 的一个好处是
它是一个完美的跨平台命令 它还将出现在 你知道的 在iPad上可暴露性视图 或不可暴露性视图也有这个命令 因此不需要条件化任何代码 它在Mac和iOS上都能用
接下来我们可以创建 makeFavoriteCommand 这只是一个常规的命令 没有任何密钥等效
它会进入toggleSelected RecipeFavoriteState
最后我们要做一个菜单 它是一个结构 把新命令… newRecipeCommand和 makeFavoriteCommand聚集在一起
这里要突出一件事 就是我们传递displayInline的选项 因此菜单将被显示… 菜单中的内容将 与父菜单项的内容一起显示
如果你漏掉了这些选项 菜单项将被作为分层菜单显示 你可能会在Mac上使用分层菜单
好的 让我们看看它是什么样子的
我们把这个插入到… 插入文件菜单的开端
好的 我们进行了迅速的创建并运行
你可以看到 它现在有一个新菜谱命令 与那个加号小工具的功能一样
它还有一个添加收藏 它会给巧克力片添加一个心形 我们也可以移除收藏 总之 我给你们展示的是 仅通过在Mac上重新创建iPad app 你可以免费获得的东西 我还会给你们展示侧边栏、 工具栏和菜单栏 让你们都能把你们的app 提升到下一个层级 那么舞台交还给Jamie 讲一些设计考量
谢谢Glen
那么现在我们要讲一些技术细节 关于让你的iPad app 适应Mac 让我们先来看一些设计考量
首先是导航 思考一下用户如何在你的app中 进行导航 如果你还没有考虑过在Mac上 使用侧边栏 也许还没考虑过在iPad上 使用分屏显示
请重新考虑标签栏的使用 在Mac上 你应该考虑在工具栏中 使用分段控制来代替
(布局) 接下来是布局 我们已经讲过屏幕尺寸了 它在你的布局中应该具有灵活性 充分利用大窗口的优势
你还可以重新排版和重新设计 你的用户界面 并且你可以使用自定义资产 来改写硬件相关的内容 或只是为了利用空间
(排版)
iPad设计比Mac设计要大得多 它针对触摸进行了优化 因此基础字号不一样 在iOS上 大部分文本是17点 而在Mac上是13点
因此相对于它在 AppKit app上的显示来说 我们替你把UIKit内容缩小为 原来的77%
这意味着在屏幕上 UIKit点比AppKit点小 即使是UIKit app中的位图 也应该显示为 AppKit app 中位图尺寸的77%
因为缩放对于app来说是全局性的 在绝大部分情况下 你不需要担心它
如果你真的想要更直接的控制 特别是针对字体缩放 你应该了解一下 字体管理和文本缩放演讲 并学习如何去实现
(菜单栏) 菜单栏 我们讲了如何做菜单栏 但你应该在菜单栏中放什么呢?
我提到过菜单把所有可能的动作 都放在一个地方 对于app来说它是全局性的 并且根据用户正在执行的动作 启用或禁用菜单项 这意味着菜单中的内容 应该不会发生改变 你只需要在启动时进行一次性创建
你真的应该考虑你app的所有功能 并确保它们均可通过菜单栏可用
(输入)
我们刚讲了iPad 如何针对触摸进行优化 iPad所特有的一个功能是 直接多点触控 Mac并没有这个功能 但它却总是配有键盘和鼠标或触控板
你应该考虑要如何把 你app中所使用的手势 映像到这些输入设备中 在Mac上针对鼠标和触控板 进行重新实施 当你这样做时 请一定要考虑可访问性
那对于设计话题来说只是冰山一角 在Mac人机界面指南中 还有大量关于设备上的有用信息 当你设计你的app时 你应该参考它 并且我鼓励你们观看 Mac上iPad app设计演讲 它包含许多很不错的建议 关于如何让你的UIKit app 成为一个不错的Mac app (更多设计资源)
现在我们讲了把iPad app 变成一个更好的Mac app 我要向大家介绍Nils 他会讲Mac上UIKit app 的另一个独特功能 App生命周期 (app生命周期)
谢谢Jamie 大家下午好 我是Nils Beck 我是AppKit框架团队的工程师 今天我很激动 我要跟大家分享Mac版iPad app的app生命周期
当我们把iOS上app生命周期 与MacOS上app生命周期比较 我们发现它们有不同之处 一些iOS专有的行为 在UIKit API中有所体现
在Mac上运行iPad app时 这产生了一种挑战
我们要如何把macOS app 状态映像到iOS API中?
让我们首先回顾一下 iOS上的app生命周期状态 你可以顺着图表看 它会在右手边显示 (app生命周期状态) 当你的app出现在屏幕上时 人们通常会在iPad上 与你的app进行交互 它既处于前台又是激活状态
当有东西遮盖它时 你app是非激活状态但仍处于前台 因此它不会接收事件
这通常是暂时情况 比如当控制中心 在你app的上一层可见时
一旦你的app处于后台 用户就不再与之进行交互 比如他们可能使用了任务切换器 并侧滑到一个不同的app
但你仍然可以实施后台任务完成 并且当没有任何残余的后台任务时 你的app会被暂停使用
一旦被暂停使用 你的app就被冻住了 不再获得更多的CPU周期 此时 它可能在任一时刻就被系统终止 而不需要进一步的通知
最后 当它甚至都不处于内存中时 你的app就不再运行了
把这些总结在一起 让我们看看你能看到的 可能的状态变更 无论是在iOS或是 在macOS上运行 我马上会带你们具体看这些 但首先我要请你们注意… 但首先我要讲 对你们来说相对容易的事 Mac上的iPad app 将获得与iOS上 相同的委托调用和通知
你可能习惯在app委托方法中 处理这些状态变更 但它们还存在于这里所显示的 NSNotification
我们推荐使用这些通知 因为它们甚至当你 选择添加新的多窗口API时也可用 而在多窗口API中 会漏掉一些app委托调用
顺便提一下 这与iOS上相同
同时 多窗口app中 app的整体状态 取决于单个场景的激活状态
因此你很可能想按场景 处理状态变更
但在此演讲中 我们只关注app的整体生命周期
除了委托调用和通知 在macOS上这些状态变更的顺序 也与iPad上一样
我刚刚承诺过 让我们具体看看 状态变更通知的顺序
启动时 你会看到didFinishLaunching 和didBecomeActive
退出时你会看到 willResignActive 和didEnterBackground
你还会得到 willTerminate 如果我们确定app正在退出 并且你的app 还没有被暂停使用的话
最后 在从后台状态返回时 你会看到willEnterForeground 和didBecomeActive
因为通知和顺序在两个平台上都相同 当这些转换发生在macOS上时 我们确实发生了改变
我们稍后再讲这个
现在返回到iOS中 我们建议你的代码应该 以某种方式响应这些状态变更 比如当你通过 willResignActiveNotification 了解你的app的钝化时 你希望在其它东西之间 减少在屏幕上的内容的帧频 停止各种不必要的工作 比如计时器、队列和查询
可能还有其它副作用 比如你可能希望暂停游戏 (响应状态变更) 类似地 当你的app 通过didEnterBackgroundNotification 进入后台状态时 在iOS上 你的app 会停止所有的渲染 把CPU的使用减少为最小 并释放尽可能多的内存
可能还有其它副作用 比如 如果屏幕上的内容是私密内容 你可能想在屏幕截图之前 把它隐藏起来
(你的iPad app 现在是Mac app了) 现在当你把iPad app 引入到macOS时 我们不希望你修改 所有的状态变更处理代码
但运行在macOS上的iPad app现在是一个Mac app了
那会发生什么改变?
这是一些针对Mac的考量
许多Mac app 同时共享屏幕很常见
其中一个app是处于最前的app 那意味着它接收关键事件 并且显示它的菜单栏 (Mac OS考量)
许多事都会影响 app的内容是否可见 比如一个窗口可能被另一个窗口挡住 或窗口可能最小化到程序坞 或它甚至可能完全处于另一个空间
app还可能由于其它原因 不在屏幕上显示内容 比如整个app可能隐藏起来了 或它可能目前只是没有任何窗口显示 或你的app甚至可能 在后台登录会话中运行 那仅存在于虚拟屏幕上 在其中一个深夜调试会话中 你可能正在通过VNC进行访问
(状态变更对 Mac app影响较小) 不管它们的最前状态和内容可用性 Mac app通常不希望 像iOS app一样 彻底改变它们的行为
所有运行的app都要做 对用户有价值的工作
同时 你希望处于最前的app 仍能接收滚动事件、点击和悬停事件
当Mac用户切换到 一个不同的app时 他们不一定希望游戏暂停 或当他们尝试在虚拟屏幕上 通过其中一个VNC会话 使用你的app时完全禁用渲染
我之前告诉过你 相较于iOS上的状态变更 当这些状态发生变更时 我们已经进行了改动 就是这些 根据我刚讲过的内容 我们决定在macOS上 几乎所有时间 我们都将保持 所有iPad app 处于前台并激活
在app终止和后台启动过程中 我们只进入前台非激活状态 和后台状态
换句话说 只要用户感觉到你的app正在运行 它就处于前台激活状态 以避免任何非Mac意愿的副作用
让我再重复一遍 将不调用UIKit状态变更通知 比如当你的app 获得或失去菜单栏时 或有窗口遮挡住app时
那意味着你的app 不会像在iOS上那样 急切地减少它的资源消耗 然而AppNap启发算法适用于 所有mac app 包括你的iPad app
AppNap是 macOS的一个功能 系统不间断地观察app的各个属性 用于显示它是否不在使用中 比如它是否可见 主动绘图 播放音频等等
然后当AppNap 认为节流没问题时 它会自动应用节流
(app终止) 我刚才提到过 我们在终止和后台启动过程中 确实会进入其他app状态
让我们从app终止开始讲
开发人员需要注意的是 当把他们的iPad app 迁到macOS上时 iOS中app之间的切换 与macOS上完全不一样 比如 在iOS上切换到另一个app时 后台音频仍继续播放 像把处于最前的Mac app变成 让另一个Mac app处于最前 因为你的app 被用户认为是继续运行
但在iOS上 当用户不返回到你的app中 并且也没有任何播放的音频时 这可能更类似于 在macOS上终止Mac app 因为你的app不在视线内并且用户 也不记得它了 它最终会退出
在macOS上 用户发起了对你的 iPad app的app终止 得到了与在iOS中切换到一个 不同的app时相同的状态转换 比如通过使用任务切换器
状态变更通知会让你从前台激活状态 变成前台非激活状态 最后是后台状态
然而对于用户来说 app将立即显示为不再运行 app的残余窗口将立即不可见 它再也不会控制菜单栏 程序坞中也不会再有任何指示灯 且你的app也不会再在macOS 命令标签任务切换器中可用了
但在幕后 我们为后台任务提供了一个 完成任务的机会 如果它们是通过我在这里所展示的 UIApplication上的 常用API创建的话
就像在iOS中一样 迅速结束你的后台任务 否则就要承担任务过期的风险
但有一种例外情况 后台音频播放列表项被忽略了 无论后台是否有音频请求 都将终止进程 毕竟对于用户来说 app看起来已经被终止了
因此你的媒体框架要暂停你的… 一旦进入后台状态 我们的媒体框架将替你暂停你的播放
然而请记住 macOS上不需要后台音频 即使当用户切换到不同的app中时 你的app也将保持前台激活状态
此外 如果用户尝试启动 仍处于后台状态的app时 我们会简单地让你的app 返回到前台激活状态
这类似于从iOS任务切换器 返回到你的app
这种重新启动 只有当你的app仍在处理 后台任务时才可能发生 而不是一旦willTerminate 的同步处理开始时
因此尝试最小化这个阶段 就是你的app忽略用户 重新启动它的尝试的阶段
一旦最后一个后台任务完成或过期 进程立即退出而不会暂停
我之前提过 你会得到与iOS上相同的 委托调用和通知
在这种情况下 那意味着你会看到 willResignActive didEnterBackground 和willTerminate 因为我们会退出进程 而不仅仅是像iOS上一样暂停它
(后台app启动) 这就是Mac上 iPad app的终止
正如我刚才提到过的那样 让你的iPad app在Mac上 进入后台状态的另一种方式 是当它直接在后台启动时
iOS有相当一部分API 允许你为你的app 选择加入某些形式的后台启动 要了解关于这个话题的更多信息 请参考今年的 关于app后台执行的改进演讲
这些API的子集 支持Mac版的iPad app
针对后台下载配置的URL会话
在APS字典中 指定了带有可用内容的远程用户通知 你可以用它 比如说 更新你app的内容 当新内容到达服务器端时
同时 当我们的用户调用 未指定前台选项的通知动作时 比如他们可能希望通过用户通知 发送帖子 并且我们可以后台启动你的app 从而让服务器了解这个情况
最后 我们还支持 新BackgroundTasks框架 包括新 BGProcessingTask 以及BGAppRefreshTask 用于传统的后台app重刷新
请注意 对于Mac版iPad app 仅通过这个新API 支持app重刷新功能
常见的后台运行时间限制 和所应用的进程优先权 与iOS上的相同 因此如果你的任务占用太长时间 你的app将面临被暂停使用 或甚至是被终止的危险
当app仍然在后台运行时 如果用户尝试启动它 我们将简单地把它转换为 前台激活状态 类似于之前讨论过的 在终止过程中重新启动
对于后台启动也一样 所有状态转换都将与 iOS上的相匹配
在这种情况下 那意味着你只能看到 didFinishLaunching 以及针对后台启动 所使用的任何回调
只有在用户所执行的完全启动过程中 你才可额外看到willEnterForeground 和didBecomeActive
(暂停使用) app暂停使用 相较于iOS 在macOS上 iPad app很少被暂停使用
在常规的终止过程中 app将直接退出 而没有任何暂停
在macOS上的app切换过程中 这不会导致后台状态或暂停
但如果app直接在后台启动的话 你仍可能看到发生暂停
现在在iPad上 当其它地方需要资源的话 你的app可能会被终止 特别是如果它已经被暂停使用的话 但在macOS上 如果你的iPad app 被暂停使用了 它总是会立即终止 即使不存在任何内存压力
提到内存 Mac内容模型应用 意味着没有任何强制的内存限制 你的app不会面临在执行 极耗内存的工作时被终止的风险
但这是把双刃剑 因为你的app运行时间越长 由于堆积泄露 用户越可能注意到系统性能下降
特别是 如果它在基于硬盘的系统上 导致VM置换的话
因此请使用分配分析模板 和仪器来发现并修复泄露 这也会让iPad版app受益颇多
现在我们讲了大量信息 让我们回顾一下
在macOS上 你的iPad app将在前台激活 状态中度过它的绝大部分时间
虽然app终止和后台启动 确实允许你的app 获取进入前台非激活状态 和后台状态
当你的app处于后台时 不要期待音频会继续播放 即使你发出请求也不可以
最后 你可以继续以在iOS上相同的方式 响应这些状态变更
现在我要把舞台交给Chris 他会讲把你的iPad app 发布到Mac 谢谢
谢谢Nils
你一直都在创建iOS app
你知道如何在 App Store上进行发布 如何使用TestFlight 如何使用开发签名、点对点 或企业号发布自己
但现在… 你正在Mac上 创建和销售第二个app 全部来源于同样的代码基
你要如何实现呢? 对于Mac来说有什么不同呢?
你如何确保你的客户们 在使用两个版本的app时 拥有无缝体验呢? 这就是我们接下来要讲的内容
让我们回到开始
你在Xcode中打开了项目编辑器 你启动了Mac支持 你一直都很努力地在开发它 你已经对app进行了完美的调整 并且你自己想 “天啊 我再也不用担心代码签名了”
嗯 那很棒 但如果你想了解更多 关于签名是如何运作的信息 你可以参加签名和性能讨论会
在那里你可以看到 要签署你的iOS和Mac app 有许多事情要做 让我们具体看一下
首先 如果你启动自动签名 代码签署的所有维护 都将由Xcode执行 这会让转换变得非常简单 我高度推荐使用自动签名
现在使用自动签名 Xcode将为Mac 创建一个必要的配置文件 同时也为iOS 创建一个必要的配置文件
我们进行了一点现代化处理 我们不使用iOS证书和Mac证书 而是使用一个统一的 Apple开发人员证书 这是一个很不错的进步
现在当你添加Mac支持时 Xcode将使用自动签名 为你的app注册一个 预定的捆绑标识符 你的Mac版app标识符有一个前缀 UIKit for Mac 这很重要 如果你一直在代码中 或在entitlements中 使用捆绑标识符的话 你需要考虑那会如何影响两个app
entitlements文件 就是你一直对iOS app使用的 entitlements文件 当注册Mac版时被共享出来 因此那没有任何问题
当你启用Mac支持时 Xcode将添加Mac上所要求的 那些功能 强化运行时间和app沙盒 因此比如说如果你已经针对摄像头 在info.plist中 提供了使用描述 Xcode将更新 你的entitlements文件 从而使你的app 可以在Mac上使用摄像头
如果你正在使用 iCloud默认容器 那是基于你的捆绑标识符 因此Xcode将调整你的 entitlements文件 从而使你的iOS app 和Mac app 明确指向现有容器 如果你一直使用默认容器API 你可以继续这么做
现在Xcode将为替进行大量迁移 但如果你想在你的iOS app 和Mac app之间 共享功能 你可能需要做一些手动操作
如果你在app中使用钥匙串 你应该在Xcode中添加 钥匙串共享功能
iCloud钥匙串 在iOS上默认可用 但在Mac上 你需要声明你使用它的意图 通过这个功能实现
如果你使用推送通知 请继续向你的iOS app 发送通知 这些通知将被iOS 和Mac app收到
好的 这就是你需要了解的 关于如何恰当地设置你的项目 用于开发
现在当你已经与其他人共享了 你的app之后 你要开始在Xcode中 创建一个存档 在iOS上 你使用那个存档将存储导出为IPA 但这在Mac上有那么一点不一样
当Xcode把你的app 上传到App Store中时 它在后台把它作为Mac程序包发送
现在上传到App Store 与上传到iOS非常类似 让我来给你展示一下
当你打开项目后 你可以使用产品菜单 把运行目的地切换为 我的Mac 然后就存档 那将打开管理器 并显示全新的Mac app存档
然后你可以点击发布app按钮 按照你所熟悉的同样的上传流程做
当然了 你可以从命令行来实现这一切
包括从Xcode创建进行上传
要了解更多关于 如何自动化这一切操作的信息 我建议你们查看 2017年的一场演讲 关于签署Xcode 和Xcode服务器的新功能
(Mac App Store) 好的 那么你已经创建好app了 但把app发到App Store 之前 还有几个步骤
首先这是一个新Mac app 因此需在App Store连接中 创建一个新app记录 就像你对iOS版app所做的那样 然后以前和现在各一次
当你这么做时 你正在把app记录与 Xcode替你合成的app标识符 关联在一起 就是那个带有 UIKit for Mac前缀的标识符
无论何时当你把app上传到 App Store时 你应该总是增加你的版本号 这与iOS有一些不同 MacOS使用版本号 来决定发布顺序
如果你完成了所有这些操作 你就可以从Xcode上传app 并把app发布到 App Store了
现在关于Mac有一件事很酷 就是你对如何安装app 有更多的控制
当客户从App Store 下载你的app时 能把该app复制到另一台Mac上 并运行的话会非常完美
那涉及到一些事
macOS上没有app瘦身
你的app总要包含 在任意Mac上运行所必需的 全套资源
因为你的app可以被拖放到 任意Mac上 由你决定是否向app中 添加收据验证逻辑 因此无论何时当你的app启动时 都应该检查 是否为合法购买以及是否被允许运行
要了解更多关于如何向app中 添加收据验证的信息 我推荐你参考2017年的 先进的StoreKit演讲
好消息是一旦你的app 被发布到App Store上 你就可以使用同样的强大工具 比如App Store Connect、 App分析用于追踪销售和营销 还有Xcode崩溃管理器 用于归类可能会影响你客户的 所有崩溃
你的app可以使用同样的 StoreKit和GameKit API
现在如果你使用那些API 需在App Store Connect上 做一些额外的设置
如果你使用app内购买或订阅 你需要在 App Store Connect中 对新Mac app 重新创建app内购买或订阅 如果你想在两个版本的app之间 共享同样的购买历史 你必须维护自己的端对端同步方案
如果你是游戏app 你应该从使用游戏中心群 共享积分榜和成就数据开始 在两个版本的app之间
并且如果你的app是多玩家游戏 你应该在App Store Connect中 更新多玩家兼容性部分 那会确保你的玩家 与相应的iOS和 Mac版app相匹配
好的 有了这些操作 你就可以 开始玩了 但有个事先警告 暂时 App Store不接受 带UIKit for Mac前缀的上传 你仍可以创建app记录 同时体验StoreKit 和GameKit API
过了今年夏季 我们将开始接受带有前缀的上传 这正是实践上传app的好时候
最后当发布Xcode 11时 你就可以开始提交进行app审查了
这就是在 App Store上的发布
现在 在App Store之外 你还可以有其它发布选项 你可以直接向客户提供app
如果你用Developer ID 证书签署你的app 并由Apple进行公证的话
公证app是一个伟大的改革 对于Mac来说很安全
我们都会感到很宽慰 因为我们下载 并在Mac上运行的app 已经由写它的开发人员签名 且签名已经由Apple进行了审查
对于这些app来说 没有任何app评论 但我们强制实行良好的政策 比如要求打开 你app中的硬化运行时间 (已公证的app) 要签署和公证你的app 可以使用强大的命令行工具
且与你的团队分享一个已公证的 app也可代替TestFlight 因为TestFlight 在Mac上不可用 但有一个警告 这样签署将不允许你使用 那些基于App Store的功能 如GameKit和StoreKit
现在签署一个已公证的app 并不像听起来那么吓人 一切都可以从Xcode中实现 你的第一步是向 Apple上传你的app
在这个过程中 Xcode将用Developer ID证书 签署你的app 并且Apple将扫描 是否为恶意软件
几分钟之后 Xcode将收到一个通知 公证app 那时你可以导出它 你可以把它打包 或把它放在磁盘映像中 并让它在你的服务器上可用
如果你想了解更多 关于安全模型的信息 或如何在app中使用安全模型 我建议你参考今年的一场演讲 关于公证的一切信息
好的 这些是你向客户发布app时 所拥有的选择方案
值得一提的还有第三种发布方式 就是开发签名
现在开发签名与你在iOS上 所熟悉的一模一样 它对于与团队共享一个app创建 以进行测试来说非常棒 请记住 当你与新Mac共享时 请记得在开发者门户网站上 注册新设备
开发签名是你用于测试 那些StoreKit和 GameKit API的工具 你可以…当你使用开发签名时 你可以使用沙盒测试账户 而不是花自己的钱练习收据验证
这些就是在Mac上 发布app的选择方案
现在当然…
有大量信息需要接受
但请考虑一下你是否愿意跟我们一起 跨出一大步
也许你像我一样 你开始是一名iPhone开发人员
你精通表视图和屏幕旋转
然后你就升级到一些更大的设备上
你在iPad上寻求机遇
你挑战自己使用新形状因数 添加多任务以及拖放
你的下一个挑战将是Mac
你将克服重调窗口尺寸和菜单栏
我很高兴看到 你们会给Mac带来什么 我们都将在它的发展中受益颇多 现在去勾选那个复选框吧
请参加我们的讨论会 请观看相关演讲 请度过一个美妙的WWDC 谢谢
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。