iPad 和 iPhone App 在 Apple Silicon Mac 上的运行
iPad and iPhone apps on Apple silicon Macs
2020年6月23日
一句话判断
当 Mac 转向 Apple Silicon 后,几乎所有的 iOS/iPadOS App 都能直接在 Mac 上运行——你的 App 会自动出现在 Mac App Store 中,除非你明确选择退出。
这场 Session 讲了什么
Apple 宣布 Mac 将从 Intel 转向自研的 Apple Silicon(ARM 架构)。由于 iPhone、iPad 和 Mac 将共享同一套芯片架构,iOS 和 iPadOS App 可以在 Apple Silicon Mac 上原生运行——不需要重新编译或修改代码。
Session 详细解释了这个机制的工作原理。当你上传 iOS App 到 App Store Connect 时,Apple 会自动将你的 App 发布到 Mac App Store(适用于 Apple Silicon Mac)。用户可以在 Mac 上直接下载和安装,运行在一个安全的沙盒环境中。你可以选择不让你的 App 出现在 Mac App Store 中(通过 App Store Connect 设置),也可以选择为 Mac 提供优化版本。Session 还讨论了哪些类型的 App 不适合在 Mac 上运行(比如依赖特定硬件传感器的 App)。
值得深挖的点
自动发布与选择退出
默认情况下,所有 iOS App 都会自动出现在 Mac App Store 中。如果你不想让你的 App 在 Mac 上运行(比如你的 App 依赖陀螺仪或 GPS 等 Mac 没有的硬件),可以在 App Store Connect 中选择退出。选择退出后,用户无法在 Mac 上安装你的 App。你也可以选择只在特定版本的 macOS 上提供。
输入映射与窗口行为
iOS App 在 Mac 上运行时,触摸事件会自动映射为鼠标事件。点击等于触摸,右键等于长按,滚轮滑动等于捏合缩放。窗口大小可以在一定范围内调整,但不会进入全屏模式。状态栏、导航栏等 iOS 特有的 UI 元素在 Mac 上会自动适配。大部分 UIKit 控件在 Mac 上都能正确渲染。
代码片段
检测是否运行在 Mac 上
场景:根据平台调整 App 行为。
import UIKit
func isRunningOnMac() -> Bool {
// iOS 14 新增:检测是否运行在 Mac 上
if #available(iOS 14.0, *) {
return ProcessInfo.processInfo.isiOSAppOnMac
}
return false
}
// 根据平台调整功能
func configureForPlatform() {
if isRunningOnMac() {
// Mac 环境:隐藏依赖硬件的功能
disableMotionFeatures()
disableCameraFeatures()
// 调整布局(Mac 屏幕比例不同)
adjustLayoutForMac()
}
}
private func disableMotionFeatures() {
// Mac 没有陀螺仪和加速计
// 隐藏或禁用相关功能
motionManager.stopDeviceMotionUpdates()
}
private func adjustLayoutForMac() {
// Mac 屏幕比例通常为 16:10 或 16:9
// iPhone 屏幕比例更窄长
// 调整 CollectionView 的列数等
}
处理平台特定的 API 不可用
场景:优雅地处理 Mac 上不可用的 API。
import CoreMotion
import AVFoundation
class FeatureManager {
// 检查特定功能是否可用
func isMotionAvailable() -> Bool {
if ProcessInfo.processInfo.isiOSAppOnMac {
return false // Mac 没有运动传感器
}
return CMMotionManager().isDeviceMotionAvailable
}
func isTelephonyAvailable() -> Bool {
if ProcessInfo.processInfo.isiOSAppOnMac {
return false // Mac 没有电话功能
}
// 检查是否有电话能力
guard let url = URL(string: "tel://") else { return false }
return UIApplication.shared.canOpenURL(url)
}
func isCameraAvailable() -> Bool {
if ProcessInfo.processInfo.isiOSAppOnMac {
// Mac 可能有 FaceTime 摄像头,但行为不同
// 建议检测设备类型
}
return UIImagePickerController.isSourceTypeAvailable(.camera)
}
// 根据可用性显示/隐藏功能
func configureFeatures() {
if !isMotionAvailable() {
hideFitnessTrackingSection()
}
if !isTelephonyAvailable() {
hideCallButton()
}
}
}
在 App Store Connect 中管理 Mac 可用性
场景:配置你的 App 是否在 Mac App Store 中可见。
// 不需要代码修改,在 App Store Connect 中操作:
// 1. 登录 App Store Connect
// 2. 进入 App 的 "Pricing and Availability"
// 3. 在 "Mac" 部分选择:
// - "Make available"(默认:允许在 Mac 上运行)
// - "Don't make available"(不允许在 Mac 上运行)
// 如果你选择允许运行但想提供 Mac 优化版本:
// 创建一个 Mac Catalyst target 或 Universal App
优化触摸/鼠标交互适配
场景:确保交互在 Mac 的鼠标环境下也能正常工作。
class InteractiveViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupInteractions()
}
private func setupInteractions() {
// UILongPressGestureRecognizer 在 Mac 上会映射为右键
let longPress = UILongPressGestureRecognizer(
target: self,
action: #selector(handleContextMenu(_:))
)
longPress.minimumPressDuration = 0.5
view.addGestureRecognizer(longPress)
// UIPanGestureRecognizer 在 Mac 上映射为拖拽
let pan = UIPanGestureRecognizer(
target: self,
action: #selector(handleDrag(_:))
)
view.addGestureRecognizer(pan)
// 如果在 Mac 上运行,禁用依赖 3D Touch 的功能
if ProcessInfo.processInfo.isiOSAppOnMac {
// Mac 触控板不支持 3D Touch
disableForceTouchFeatures()
}
}
@objc func handleContextMenu(_ gesture: UILongPressGestureRecognizer) {
if gesture.state == .began {
// 在 Mac 上这会由右键触发
showContextMenu(at: gesture.location(in: view))
}
}
@objc func handleDrag(_ gesture: UIPanGestureRecognizer) {
let translation = gesture.translation(in: view)
// 处理拖拽逻辑
gesture.setTranslation(.zero, in: view)
}
}
最佳实践
已有项目:在 Mac(Apple Silicon)上测试你的 App,看看有哪些功能不正常。常见问题包括:依赖陀螺仪/加速计的功能失效、自定义触摸手势在鼠标操作下体验不佳、布局在 Mac 窗口尺寸下不协调。对于不适合 Mac 的 App,在 App Store Connect 中选择退出。
新项目:从架构上就考虑跨平台运行。使用 ProcessInfo.processInfo.isiOSAppOnMac 来检测运行环境,动态启用或禁用功能。使用 Auto Layout 来适配不同的窗口尺寸。避免依赖特定硬件传感器。
还有什么值得关注
- iOS App 在 Mac 上运行时,文件系统访问受到沙盒限制,不能随意访问 Mac 的文件系统。
- 你的 App 在 Mac 上运行时使用的是 iOS 的 UIKit 渲染,不是 AppKit——外观上会有细微差异。
- 如果你想要更好的 Mac 体验,考虑使用 Mac Catalyst 而不是直接运行 iOS App。