大多数浏览器和
Developer App 均支持流媒体播放。
-
适用于 Mac 的 iPad App 简介
通过适用于 Mac 的 iPad App,您可以轻松地将自己的 iPad app 引入到 Mac,同时只需要维护单一代码库。了解能够自动为您实施的常见 Mac 功能。掌握如何使用仅限 iOS 的框架,以及使用这些框架可能对您 app 带来的影响。了解包括如何使用第三方框架在内的一些常见使用模式,以及一些设置方面的技巧和窍门。体验如何通过整合平台专有功能,让您的新 Mac app 用起来像个 Mac app。
资源
相关视频
WWDC21
WWDC20
- 优化 Mac Catalyst app 的界面
- Apple Silicon Mac 上的 iPad 与 iPhone App 运行
- Mac Catalyst 的新功能
- Mac Catalyst 的辅助功能设计
WWDC19
-
下载
(把iPad App引入Mac)
谢谢
欢迎大家参加演讲 很高兴能在这里看到你们 我叫Ali Ozer 稍后会有我的同事 Jake和Jason加入我 我们今天会介绍 把iPad app引入Mac
我们将举办两场演讲 在这第一场演讲中 我会介绍一些基本信息 关于这是什么技术 以及如何使用 哪些功能可以免费使用 还有你应该了解的一些 重要的API差异 第二场演讲是把iPad App 引入Mac提升到下一个层级 时间是在本周稍后一些时间 我们会介绍高级内容 比如让你的app成为一个 更好的Mac app 以及app发布的注意事项
那么到底什么是 把iPad app引入Mac呢? 嗯 它是一种可以让你 原生地在Mac上 重建并运行iPad app的方式 让我具体说一下 (原生地在Mac上重建 并运行iPad App) Mac是一个稳健的开发平台 承载了各种各样的app 我们拥有强大的桌面app 基于网络的体验以及图形密集型游戏 并且这些体验都有特定的框架 用于支持它们 但我们漏掉了一个东西 就是UIKit 它是iOS app所使用的技术
把UIKit作为Mac上 其它框架的本地对等体 你就可以把iPad app 引入Mac并获得头等体验
让我们谈谈如何实现
我们有丰富的技术栈 在iOS上和macOS上共享 并且我们会尽可能地利用它
我们还引入了 Mac上不存在的iOS框架 并把它们完美地引入到Mac上 与Mac和基础结构以及 与Mac UI设计准则完美融合 最后但并不是最不重要的 我们把实现方式变简单了
我会讲前两点 然后Jake会上台来继续 演示并讨论第三个话题 (平衡我们的共享技术栈 整合OS框架) (用XCODE为MAC 创建iPAD项目) 好的 那么让我来展示一下 我所说的技术栈是什么意思 这就是Mac的技术栈 我们有macOS app 它们创建于框架之上 UI框架 以及你在这里看到的低层级的框架 这些只是一些具有代表性的框架 我们 当然了 在技术栈中有几百个框架 除了框架 我们还有数据库 诸如用户的相册数据库、情境、 偏好等等之类的东西 现在有服务 包含诸如用于复制粘贴 和文件协调的剪贴板服务一样的东西 然后我们还有一个 爷爷级的服务Kernel 就是我们的 Darwin Kernel 现在iOS技术栈看起来很相似 在iOS上我们有iOS app 然后有框架栈 下面是数据库和服务栈 你可以从这里看到一些差异 我马上就会讲到这个
现在你们中有许多人还没有意识到 我们已经暂时可以 在Mac上的模拟器中 运行iOS app了
在模拟器自己的环境中运行的技术栈 与众不同 那么它有它自己的框架、 数据库和服务 模拟器的主要目标是复制iOS环境 以便你调试和测试iOS app 好像它们在iOS上运行一样 在这方面模拟器做得不错 然而与Mac用户体验完美整合 并不是模拟器的目标 它的目标也不是以最优方式 为终端用户运行
因此把iOS app 原生地引入Mac中的一种方式是 我们在Mac上增强了框架 既支持AppKit app 又支持UIKit app的需要
我们结合并统一了 在两个平台上都存在的 低层级的框架的功能 框架比如CoreGraphics、 Foundation、libSystem 用于创建单一拷贝 可以服务全部两个技术栈
现在请注意在这张图中 我们并没有统一 依赖于UIKit 和AppKit的框架 我要稍微谈谈这一点 同时请注意那边的ARKit 因为Mac上没有增强现实功能 因此我们没有引入那个框架 那么好了 不要误解我们 我们喜欢ARKit 只是不能在Mac上用 最后是中间的 UserNotifications 我们不仅把这个框架引入了Mac 我们还在Mac给它做了公共API 这只是其中一个例子 去年我们就这样做了 在这个技术刚出来时 我们就在众目睽睽之下实现了 并且我们还统一了服务和数据库 Photos和Contacts 以及Preferences 仅一次复制就既能用于AppKit app又能用于UIKit app 对于服务也一样 只有一种复制粘贴服务 一种文件协调服务 等等 这就是Mac上 iPad app的环境 看起来与AppKit app的 环境很像 并具有原生性能特征
在离开这个话题之前 让我再谈谈AppKit 和UIKit的框架
当然了 并不只是 WebKit和SceneKit 还有许多其它框架 我要给你们展示其中两个 就是这样 因为AppKit 和UIKit不统一 依赖于它们自身的框架也保持独立 即使字面名称一样 比如两个WebKits 两个SceneKits等等 原因有很多
主要原因是那些类不一样 比如NSView和UIView 它们还拥有自己的行为和支持结构 因此我们反过来在创建这些类时 类的声明和实施也不一样 那么例如这是MKMapView 在AppKit 和UIKit中的声明 你可以看到这些实际上是 不兼容的定义
因此我们在系统中其实是 拥有两个版本的框架 在开发者SDK中也是 然而这并不是你需要担心的东西 Static Linker和 Dynamic Loader 会替你实现 它们会查找这些框架的正确版本 无论是在创建时的链接中 或是在运行时的加载时
那么换个话题 谈谈我们为什么这么做 我们为什么要把 UIKit引入Mac?
嗯 我的意思是这只是部分原因 你知道的 我刚刚只展示了你们所创建的 许许多多iPad app中的一些 我们认为如果它们能在Mac上使用 一定会很棒 并且还有无数的Mac用户 他们中有许多人都对你们的app 很感兴趣 因此这种技术为他们提供了 获取这些app的途径 也为你们创造了新的机遇
(何时考虑向MAC 引入iPAD APP) 或你可能在想 这种技术是否适合你的app 这个问题很好
那么假如你有一个iPad app 并且你没有Mac app 并且你想把app的功能 引入到Mac上 嗯 这是个很好的例子 正好可以考虑使用这种技术 其中一种情况是 你可能有一个iPad app 但也许在台式机上是一种网页体验
现在web界面可能会非常棒 但它们不是原生的 你知道的 原生app有菜单栏、命令键、 可以使用硬件功能、 有稳健的本地存储等等 如此多的完整体验
另一种情况就是 你可能有一个老版的Mac app 但也许你的iPad app 增加了一些新功能 这两者并没有保持同步 因此这可能是让你的Mac app 面目一新的一种方式
还有一种情况也许是替换一个 使用了非原生、非最优 第三方端口框架的Mac app 如果你的iPad app是原生的 这可能是一个使你的Mac app 更新换代的好方式
然而 有一件事需要记住
如果你已经在Mac上有了一个 AppKit app 并且在Mac上维护良好 并随着iOS版本进行了升级 那么你其实就不需要考虑这个技术了 你可以继续使用AppKit AppKit是最好的框架 提供完整的API集合 用于开发Mac app 事实上它可以提供完整的API集合 比Mac上提供的这种技术完整的多
那么其中 还有一些app并不适用这种技术 其中一个例子就是 iPhone app iPhone app 针对小屏幕进行了优化 因此它们会利用小屏幕的优势 我们非常希望你们 先做一个iPad app 可以充分利用大屏幕的优势 在你把它引入Mac之前
另一种情况是 围绕移动功能创建的app
之前我告诉过你 ARKit在Mac上不可用 如果你的app是基于ARKit的 那么它在Mac上 就不会运行得那么好 但如果增强现实功能不是主要功能 那引入app仍然可能有意义 但条件是在Mac上移除那个功能
因此在这个舞台上 在我邀请Jake上台来演示之前 让我提一下高水平的目标 帮助我们设计和提交 这种技术的高水平目标
我们希望你们容易上手 我们有一个复选框 你昨天已经看到了 并且你很快会再看到它
我们希望你们能使用单一源代码库 单一源代码库可以让你在开发时 不对代码分区 并支持同时推进 app的iPad和Mac版本
我想让你们在心里把你的app 看作iPad app
就跟你把它们作为 iOS SDK开发一样 并且我们希望你们思考— 继续以iOS SDK和概念来思考 最后我们希望在外部 app可以成为一个Mac app 因此对于用户来说 这是一种一流的Mac体验
好的 我说完了 让我邀请Jake上台来 谈谈如何着手去做
大家下午好 现在你已经了解了一些关于把 iPad app引入Mac的信息 我要给大家介绍 如何使用Xcode 把app引入到Mac 一般来说 你必须要学习一个 完全不同的UI框架 并从零开始写一个全新的app 但通过Xcode 11 我们可以让你重复使用 你当前的项目和源代码 让我们来试试
(着手去做)
那么在这里我有一个 关于菜谱管理的小iPad app 是我之前准备好的 一开始 我们要在Xcode中 打开我们的项目…
并勾选部署信息 下边的Mac复选框 现在请注意只有你的app 支持iPad时这个复选框才可用
那么我要继续并点击这个复选框
我们将看到弹出一个sheet 那会告诉你Xcode 正在对你的项目进行修改 我要继续并点击启动
现在让我们看看它会做什么 那么你首先会注意到的 其中一件事就是 Scheme Selector中 运行了一个新的My Mac 这就允许你针对Mac创建、 调试和测试app
你还会看到在捆绑标识符字段下边 有一个新标签 使用这种技术引入到Mac的 所有iPad app和app扩展 都将自动默认获得一个 新的捆绑标识符 它使用了一个特殊的前缀
如果你的app中有硬编码的引用 或它的app扩展捆绑了ID 你可能需要做一些协同修改 以解决那个问题
你可以在我们的下一场演讲中 了解有关于此以及它如何影响签名、 配置和分配的更多信息 把iPad App引入Mac 提升到下一个层级 接下来让我们谈谈功能 在iOS上 app需要 在它们的Info.plist中 指定用法描述字符串 从而获取某些受保护的系统资源 比如摄像头或用户的地理位置 Xcode将使用这些信息 向你的Mac app中自动添加 同等的权利 从而使你获得与iOS上同样的功能
比如 iOS app可以默认进行 外部网络连接 而Mac app需要授权
如果我们进入签名和功能编辑器 我们可以看到Xcode 自动添加了网络客户授权 以及一些其它授权 根据我们app的 Info.plist中的 用法描述字符串
接下来是框架和app扩展 因为在macOS上还支持 大多数iOS框架 但两个SDK之间仍有差异
我主要讲Xcode项目配置 稍后Jason会讲API差异
当Xcode更新你的项目时 它会自动从Mac版中 排除所有不可用的内容 包含不可用的系统、SDK框架、 不可用的app扩展类型 以及Apple Watch内容
如果我们返回到通用标签…
你可以看到在框架库中 和嵌入内容部分… Xcode已经为某些依赖关系 完成了这个操作 ARKit和Watch app 都被标记为仅适用于iOS
让我们继续并尝试创建Mac版
让我们看看我们是否有报错
这个报错是由于 其中一个依赖型框架不兼容 因为它是针对iOS模拟器创建的
你可能在想 iOS模拟器和macOS框架 都适用于x86 你能在Mac版iPad app中 重新使用它们吗? 嗯 答案是不能
对于你可能拥有的任何 预编译二进制库来说 你都需要联系供应商 以获得一个针对Mac环境下 的iPad app 进行了特别编译的版本 从源代码构建框架是项目的一部分 另一部分是默认为Mac 进行自动配置
你可能会考虑使用平台下拉菜单 这里在框架库和潜入内容部分 排除了不兼容Mac版的库 除非你可以获取兼容版本 或者如果它提供的功能 不适合Mac app 然而如果你依赖于框架来实现 主要功能 你最好等着供应商更新库 在你报告给Mac之前
在这种情况下 我恰好有这个库的 一个更新的可用的版本 因此我要继续并把它添加到项目中
首先我要删除现有框架
现在我要继续并拖入新框架
现在你可能会注意到的第一件事 就是这不是一个常规的框架
更新的库是作为XC框架提交的 它是Xcode 11中的新功能 允许库的开发人员 从多个平台中把库打包到 你能在Xcode项目中使用的 单一分配的捆绑包中
把app引入Mac时 不需要XC框架 但它们使 跨平台管理依赖关系变得更方便
你可以在Swift中的 二进制框架中了解更多信息 请注意它们也适用于 Objective-C
接下来把你的app 引入到Mac的最重要的一个方面 当然就是你的代码 我刚讲了Xcode如何自动排除 一些不可用的框架 但你仍然需要对源代码做一些调整 以便编译出 对那些框架所提供的API的引用 那可能由于硬件不同 或用户体验不同而变得不可用
你可以有条件地在Swift中 使用目标平台环境 或Objective-C中的 目标OS宏命令编译你的代码
现在让我们来看一下 我要继续并尝试再次创建
我们可以看到ARKit不可用
很好 那么我想添加一种 在增强现实中预览菜谱的方式 如果没有那种效果 我们很可能就会离开 食物的最好体验是在AR中 非常真实 那么让我们继续并把它注掉
那么我们已经拥有一些示例代码 我们可以用于把它注掉
我要继续并 #ifdef ARKit
我还要#ifdef相应的API
好的 让我们再一次尝试创建它
另一个报错 好的 那么这一次…
看起来StoreKit框架 在Mac中不可用 但我们尝试 在这里使用的那个API却可用 现在我不确定我的app营销团队 正在尝试做什么 但很可能不那么重要 我把这个也#if掉 好的
我们可以把它留给他们来处理… TODO: 还有别的吗? 好的 很好 那么此时此刻 我可以运行app了 但在此之前 让我们思考一个可对Mac app 做的一个很关键的改善
默认情况下UIKit app将用 来自iPad app的图标 同样的圆角设计
正如你在这里所看到的 这个漂亮的小点心
但Mac app的图标 一般都有漂亮而丰富的细节 尺寸最大可以达到512点 并利用了透明度 更有设计性和灵活性
给你的app自定义一个 很棒的Mac图标 真的会帮助它脱颖而出 你可以从下面的演讲中 了解关于设计的更多信息 “关于iOS和macOS设计 的新功能”
为了添加Mac专用图标 我们想导航到Xcode中的 资产目录编辑器
那么在这里选择我的资产目录
我要选择App图标资源
进入监测器
并勾选Mac复选框 显示新插入点
然后你只需拖入新图标即可 我要继续并使用一个 我之前准备好的图标集合
我要继续并拖入
哎呦
好了
好的 你可以看到我们得到了一个 很棒的点心图标
那么让我们继续再做一次 我要继续并再创建一次 这可能要花点儿时间 因为我们已经从为iOS创建 切换成了为Mac创建 它需要重新创建所有的源代码 和所有的资源
我们给它一点儿时间
我们已经成功创建并运行了Mac版 并且你可以看到我们已经有了 —哦 谢谢大家
并且你可以看到 我们已经有了标题栏 我们有窗口信号灯 我们有菜单、可调整大小的窗口 当然了 还有漂亮的Mac点心图标
正如你所期待的那样
一旦完成 你可以在Xcode中点击 产品存档菜单项 创建一个存档并打开管理器 然后你就可以发布到 Mac App Store 或使用开发者ID独立地发布
那么这就是Xcode 11 如何帮助你把iPad app 引入到Mac
现在我要邀请Ali返回舞台 他会告诉你更多 关于改善用户体验的信息 你都可以免费使用
好的 那么现在我想谈谈 有哪些免费功能 我要讲一下… 你的免费午餐 但你在UIKit中 为Mac app得到了什么 有大量...老实说 你获得了大量免费的功能 整个框架栈的大部分 还有我刚才展示给你的数据库和服务 都会自动应用到 你的Mac app中 但在这里我想强调一些东西 它们不仅仅是免费的 还会自动映像到Mac范例 并按Mac的方式来实现 那么让我们首先看一下 Jake 所使用的那个美味的菜谱app (免费获得默认菜单栏) 那么正如你在演示中所看到的那样 你得到了默认菜单栏 app有一个默认的 漂亮的功能性菜单栏 拥有大量Mac用户所期待的菜单项
接下来得到了窗口管理 这包括比如重调窗口尺寸 全屏、分屏 以及我们亲切地称为 窗口信号灯的功能 在标题栏中有三个按钮 还要指出一点…
如果你的iPad恰好在附近 你可以在iPad上显示 Mac窗口中的iPad app
自动适用暗黑模式
如果你再进一步并采用任意新API 让你的app成为一个 更好的iOS暗黑模式app 那些也将会被自动迁移过来 滚动条和滚动在Mac上也没问题 进行了映像以覆盖滚动条功能
当窗口不活跃时也能使用滚动 当然了 那是用户对Mac的期待 通过手势滚动 如果用户让滚动条一直显示 那也会自动应用在你的app中
现在让我来谈谈设置 我们的菜谱app没有任何设置 因此我要给你演示一个 语音备忘录app
在iOS上 app指定设置捆绑包 并且这些控件—这些设置控件 出现在iOS设置app中 比如这是语音备忘录的设置 在设置app中 Mac上的设计准则是 获取app偏好 通过一个菜单项实现 在诸如这样的app中 当我们看到你的app有设置之后 我们会为你提供这个菜单项 并像这样自动把设置 映像到Mac prefpane 在app内 并且你可以看到它们并排放在一起 这是自动发生的
你的app获得了触摸条的基本支持 所有app都会使用系统触摸条 此外如果你使用API 比如AVPlayerViewController 或UITextView 它们也将自动提供 app中的文本触摸条的媒体权限 就像你在这里看到的这些一样
另一个自动映像的关键元素就是 文档选择器 这就是如何让 UIDocumentPickerViewController 看上去像NSOpenPanel 以满足用户的期待
你所创建的自定义视图按原样显示 跟预期一样 在这个语音备忘录app中 自定义波形视图 在两个平台上看起来完全一样
现在让我讲另一个话题 你可能会经常遇到 让我们看一下News中的 表格sheet 这是iPad上的News 这是用于管理通知的表格sheet
这是Mac上的News 显示的是同样的表格sheet 你可以看到表格sheet 连同内容中的UI切换项一起 都按原样显示 我把它并排显示一下 在这里你可以看到我的一个主要目标 是在可能的情况下为你的app
提供源代码的高度兼容性 尝试为app提供 完全的AppKit控制和标准 象征着太多的混乱 因此单独地 基于此的UIKit控件和布局 按原来那样为你的app 提供最大限度的兼容性
此外还有文本大小 在iOS上 控件的基础字号大小是17点 而在Mac上是13点
正如你所看到的那样 当它们并排显示时字号大小不一样 这种差异的存在有两个原因 分别是iOS设备相对显示密度较高 以及适应触摸需要 为了提供与Mac app 一致的交互性 我们把内容区缩减到了原来的77%
因此窗口中的一切看起来 都进行了统一缩放 并且你不需要针对Mac版 重新设计任何窗口
本周稍后会有一场 关于字体管理和文本缩放的演讲 会深入地谈到一些与此相关的话题
(还有更多免费功能) 现在让我快速讲讲更多免费功能 如果你实施了复制和粘贴、 拖放、打印或利用iOS 13中的 新功能多窗口、多任务API 这些将会被自动免费迁移到Mac上
在Mac上 app的生命周期 要适应Mac范例 针对管理生命周期所实施的任何回调 都将被自动迁移到Mac上 你可以在把iPad app 引入Mac 提升到下一层级的演讲中 获取与此相关的更多信息 除了这些免费功能 还有一些功能可以让你的app 成为一个更好的Mac app 就是这些 Jake已经讲过了Mac图标 本周稍后的高级演讲上 我们会讲其余的 在今天下午稍后的iOS 和macOS设计演讲上也会讲到
好的 谢谢 此时此刻 我要邀请Jason上台来 (采用MAC图标、自定义菜单、 工具条、) (触摸条、悬浮事件、 帮助和更多的功能)
好的 谢谢Ali
(API差异) 大家下午好 我要深入地讲一些API的差异 你很可能会在把iPad app 引入Mac的过程中遇到
我要讲的是三类API差异
那些API有完全相同的行为 好消息是 绝大部分API都能正常使用 (API差异概览) 那些映像到macOS的API 会自动功能化
它们利用的是iOS API 但却导致了macOS行为
最后我们还会讲到 由于各种原因而不可用的API 在第一部分中我们不能全都讲到 Ali在第二部分中讲到了许多 但我还想在我们进入第三部分之前 提到一个额外的区域
就是鼠标和触摸事件 (鼠标和触摸事件) iOS是围绕一个直接的 多点触控交互模型创建的 并且macOS是围绕非直接的 基于游标的交互模型创建的 当你尝试把多点触控app 引入Mac 并让它自由发挥作用时 你面临着巨大的挑战 虽然我们的确尝试尽可能地 自动映像更多的行为
我们引入了一个新的 UI悬浮手势识别器 当鼠标悬浮在你的视图上时会通知你 (悬浮) (单指触摸追踪) 并且鼠标左键拖动 被映像到一个单一合成的触摸序列中 并由轻触、 平移和长按手势识别器自动识别 手势识别器用于识别单一触摸
(标准手势) 在Mac上标准系统手势 在硬件或驱动程序级别被识别 它们向系统发布高等级的手势事件
当UIKit app收到高等级的 捏合旋转手势时 我们合成一对触摸行为 并把它们提交给游标下的视图 这将在你的app中自动触发 任意捏合或旋转手势识别器
如果用户执行了标准的系统滚动手势 在这种情况下我们不会合成 任何触摸行为 UIKit将自动 在游标下的UI滚动视图中进行滚动 (自定义多点触控代码) 现在我们不能 自动映像的其中一个行为 是自定义多点触控行为 无论是直接处理UI触摸 或是已经写好自定义手势识别器 没有任何自动方式 把Mac上的各种不同的输入设备 映像到自定义手势 如果你在app中依赖于此 你需要提供一种替代方式 让用户实现同样的操作 当你把app引入到Mac时
让我们继续API差异的第三类 就是不可用的API 一般分为四大类 (不可用的API 弃用的框架) 弃用的框架 (iOS特有框架) 框架不可用是因为 它们所关联的iOS功能 在macOS中不存在 (硬件特有框架) 关联到特定软件功能 或传感器的框架 在Mac上不存在 最后还有许多框架 有不同的行为或API 由于各种原因在macOS上不可用 要对这些添加注释从而澄清 并在Xcode中生成报错 那么让我们再深入地看一下 (框架差异) (弃用的框架) 弃用的框架通常是用了很久的框架 在它们被弃用过之后
然而这对于iPad app来说 是个新平台 因此你不应该假设任意弃用的框架 对你可用
现在是时候把弃用的框架迁移到 替代框架上了 这不仅允许你 把iPad app引入到Mac 还会让你的iPad app 从中获利
还有一些框架 关联了当前Mac上 不存在的iOS功能 (iOS特有的框架 CLASEKIT、 HEALTHKIT、HOMEKIT) ClassKit框架用于 允许你的app 能与Schoolwork app 一起使用 但Mac上不存在这个app 因此那毫无意义 HealthKit 和HomeKit 此时此刻不可用 因为并不是所有潜在的功能都存在 (硬件特有的框架) 有一些关联到iOS设备上的 特定传感器的框架 用于实现仅存在于iOS上的功能 这将在Mac上不可用 因此如果你的app使用了这些框架 在你把它引入到Mac之前 制约它们的使用
有些关联了iOS设备上 特定硬件的框架 在Mac上可用 但这些API的可用性和功能性 受到限制 因为Mac通常没有 可比较的传感器
在某些情况下 在非网格式iPad上也一样 因此你的app可能已经 在做对的事情了
让我给你一个你可能期待的 那种差异的例子 Core Location能用 但Mac没有GPS芯片 因此你应该期待它们在移动时 对地理位置的变更没有那么敏感
且若你使用Core Motion 在app中控制游戏 你应该意识到Mac 没有实现此功能的传感器 那样会实现非常好的用户体验 因此你应该添加一个替代机制 在Mac上进行游戏控制
有许多媒体相关的框架 你应该注意其中的差异
Media Player框架 提供的功能 与它在Mac上提供的功能基本一样 可以使用立即播放信息中心 和远程命令中心 但不能使用库或回放支持 (框架差异 MEDIA PLAYER、 AVFOUNDATION、AUDIOTOOLBOX) 并且如果你使用 AVFoundation框架 在iOS设备上捕捉静止图像或视频 你可以在UIKit中使用 UIImagePickerController 从内嵌的前置Mac摄像头进行捕捉
还有许多其它存在差异的框架 我希望你们能关注其中几个
Metal在我们的所有平台上 都大致相同 因此你们中绝大多数人会发现 当你把iPad Metal app 引入到Mac之后不经修改就能使用
如果你使用了我们最新的GPU中的 某些更高级的功能 比如Memoryless Textures
我们引入了一个新GPU家族API 帮助你制约你的代码 从而使其在GPU家族的范围内运行 UIKit中 UIWebView 将不存在于Mac上 因此如果你已有UIWebView 现在是时候迁移到 WKWebView了
(API可用性) 那么正如你所看到的 我们的API存在许多差异 我们没时间提到每一个差异 那么我想花点儿时间来谈谈如何 自己定义哪个API存在差异 以及哪个API不可用 当你把 iPad app引入到Mac时
那么Mac版的iPad app 是用macOS SDK创建的 因此对于不可用的框架来说 它们只是不存在于SDK中 但对于在iOS和macOS上 存在差异的框架来说 我们给方法添加了恰当的注释来阐明
我们给API添加注释… 在Swift中可用 及在Objective-C中可用 对于iOS app 我们显然只关心这部分
好消息是iOS上的可用性 对Mac版iPad app 进行了自动暗示
正如我之前提到过的那样 绝大部分API都可用 因此当你浏览API时 你一般会看到这些
当存在可用性差异时 你会看到我们对它做了清楚的注释 这是一个仅适用于Mac上的 iPad app中的API 现在类似的API非常罕见 你所能找到的Mac版iPad app中的绝大部分API差异 都是因为API在iOS上可用 但在Mac上不可用 在绝大多数情况下 你会看到API清晰地注明了 不适用于UIKitForMac
(制约代码) 理想情况是绝大多数代码 都保持相同 当你把它们引入到Mac时 然而如果你有一些代码 不应该出现在Mac上 你可以使用targetEnvironment 条件语句来排除它
并且如果你使用Objective-C 你可以使用Target OS UIKitForMac 目标条件语句来实现同样的操作
当然 你可以使用这个目标条件语句 来包含只与Mac相关的代码
(数据保护)
数据保护是一个iOS功能 你可以用于保护你app的文件 并防止未经授权获取文件
你可以正常读写文件 但系统会自动对它们加密和解密
当向文件系统写入文件时通过指定 以下四个写入选项中的一个来实现
目前在macOS上 这些数据保护API不起作用 如果你尝试像这个例子一样使用它们
代码会进行编译并执行 但数据不能被安全地存储到 文件系统上
如果你需要安全地存储数据 有一些可用的选项 密码和相关数据可以存在 KeyChain中 并且FileVault显然会加密 磁盘上的全部文件
但如果那不足以满足你的需要 你可以在CryptoKit中 使用AES.GCM加密API 在把内容写入到磁盘之前进行加密 正如你在示例中看到的那样 这个API让数据加密变得直截了当 然后你只需要把数据存到磁盘上 并把关键字写入 Keychain即可 请参考文档了解全部详细信息 关于如何存储并稍后解密数据
(捆绑格式) 我想提到的另一个差异 就是app的捆绑格式
iOS上的app捆绑 被认为是平面捆绑 当Xcode创建Mac版 iPad app时
它将创建一个macOS样式捆绑 比你在iOS上所使用的 平面捆绑格式更深入
如你使用NSBundle API 来查找app中的资源 那么这一切对你来说都是透明的 然而如果你有与app捆绑 相关的硬编码路径 你需要修改代码 以处理macOS捆绑格式
(扩展)
iOS支持多种多样的扩展… 但并不是所有都可用 当你把iPad app 引入Mac时 这是一些所支持的扩展集合 但你可能会发现一些API差异
这些扩展将自动 在AppKit和UIKit上生效 Mac… Mac上的app 因此比如说 你app中的一个分享扩展 将会在AppKitapplication中 出现在分享扩展旁边的分享按钮中
还有许多ACPI扩展—抱歉 许多目前不能在macOS上 使用的扩展 其中有许多目前在macOS上 毫无意义 比如 便签包、自定义键盘 或iMessage扩展 因为与之相应的功能 在macOS上不存在 并且在某些情况下 比如文件提供器 你应该直接切换到 macOS上的文件提供器扩展
那么我们了解了许多 会对Mac版iPad app 产生影响的API差异 让我们看一个关于 如何在你的app中着手处理 这些差异的演示
(演示)
那么我们的菜谱app…
有一个功能是可以把一个菜谱 标记为收藏…
并且你可以看到其中一个菜谱旁 已经有了一个心形图案 用于显示状态
现在app有个自定义多点触控手势 可以转换收藏状态 但正如我们所讨论过的 那在Mac上不起作用 因此让我们添加一个自定义菜单项 来替代它
因此我们要做的第一件事是禁用… 我们的自定义手势识别器
我们通过之前提到过的目标条件语句 把它裹起来实现
哎呦…那个 稍等一下
好的 然后
接下来我们要做的是…
用IBAction注释标记 手势识别器调用的那个方法 即toggleSelectedRecipeFavoriteState 因此IB—或… IB可以看到这个信息 然后 最后我们需要… 添加一个菜单验证方法 这将在 移除收藏和添加收藏菜单项之间转换 根据当前所选择的菜谱 是否为收藏菜谱
现在我们只需要添加 我们的自定义菜单即可
我们要进入 Storyboard编辑器 我们将拖出主菜单
哎呦 抱歉 我拖错了
主菜单 我们想向文件菜单中添加一个 新菜单项 因此我要添加一个内联的菜单分区
我只需要这些项中的其中一项 因此我要删除其它项 我们要把它修改为添加收藏
我们要实现与命令键等同的功能
然后我们所需要做的就是 把它写入到第一个响应器中
让它发送与手势识别器 所要发送的同样的方法 现在让我们创建并运行我们的app
我认为它的位置可能显示错了
现在你可以看到我们有一个 叫做添加收藏的新菜单项 当我点击它时我们会看到收藏图标
当然如果你取消—也会取消收藏 我们要测试菜单的快捷方式 当然了它的功能很棒
你刚才已经了解把iPad app 引入到Mac有多么简单 因此如果你的app 是一个很好的候选app 请勾选那个复选框 并创建和运行你的Mac版app 一定要经常查看文档和版本注释 获取最新信息 我们在本场演讲结束后 会在讨论室为你们提供一些帮助 请一定要参加我们周四下午的演讲 把iPad app引入Mac 提升到下一个层级 我们会讲如何让你的app 在Mac上更加流畅地使用 通过合并平台特有功能
请参加一会儿举办的关于iOS 和macOS设计的新功能演讲 我们将讨论设计考量 当你把iPad app 引入到Mac时 最后是周四上午的字体管理 和文本缩放演讲 我们将具体介绍如何处理新字体 或如何处理Mac版 iPad app的字体 谢谢 请享受接下来的时间
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。