如何检测 iOS 应用程序是否在 M1 mac 上 运行?

How to detect if an iOS app is running on an M1 mac?

我在 App Store 上提供了一个 iOS 应用程序。随着 Apple 的 M1 Macs 的推出,运行 iOS 应用程序可以在 macOS 上运行。我想防止我的应用程序在 macOS 上使用,例如在启动后抛出异常或稍后调用 exit(0)

我如何检测到该应用程序 运行正在 M1 Mac 上运行?

在某种程度上,iOS 应用 运行ning 在 Mac 上似乎将自己报告为 iPad1,因此此规则找出一些识别设备的常用方法。

提供上下文的一些细节:

  1. 我已经从 App Store Connect 上的 Mac App Store 中删除了该应用程序。

  2. 该应用程序针对触摸屏进行了制作和优化。当前版本在 macOS 上 运行 时会提供非常糟糕的用户体验。要使它成为一个好的 Mac 应用程序,需要进行许多更改和大量的努力。我没有任何计划,更不用说执行此操作的资源了。

  3. 从表面上看,这似乎类似于“如何检测我的应用 运行 是否在越狱设备上?”这个问题。从技术上讲,这可能是正确的,而且我知道通常不建议实施越狱检测以防止 IAP 黑客攻击等。一个重要的区别是 Apple 正在积极尝试防止越狱并强烈劝阻用户这样做,这似乎保留了越狱社区规模较小且不合主流,但另一方面,Apple 显然希望在 Mac 上拥有尽可能多的 iOS 应用程序。目前在 Mac 上 运行 iOS 应用程序非常容易,即使 Mac App Store 中不提供这些应用程序。 MacRumors and 9to5mac 等热门科技博客上有说明。我想确保至少阻止 运行 mac 上的应用程序的这种简单方法。

  4. 此应用中的许多实施细节都是在假设该应用只会 运行 用户无法轻松访问的 iOS 沙箱中开发的.现在,用户可能更容易 运行 具有修改后的资源、用户默认值或 Application Support 等目录内容的应用程序,包括我认为始终不可变的文件。如果用户找到一种访问应用程序中通常需要应用内购买或订阅的内容的方法,例如通过捏造 .plist 或以意想不到的方式重命名资源文件,这就是真正的商业风险。


1 在最初 post 的时候,M1 Macs 似乎通过 hw.machine 报告了自己作为模型标识符 iPad8,6。一条提供了更多细节的推文已被删除。

您的问题包含以下子问题。

  1. 如何不允许我的 iOS 应用在 Mac 上可用?

如果您想将您的应用程序限制为只能在 iOS 设备上下载,而不能在 macOS 设备上下载,那么您可以在 App Store Connect 中禁用您的应用程序的 Mac 可用性。学习 more

  1. 如何知道我的应用 iOS 在由 M1 驱动的 macOS 下是否 运行?

您必须获取有关 CPU 的信息,这个问题已经有人提出并且有一个很好的答案

Apple 的框架允许您使用进程信息标志 isiOSAppOnMac.[=14 来检测该应用程序是否在 Mac 上 运行 宁作为 iOS 应用程序=]

此标志可从 iOS 14.0 开始使用,因此需要在这些版本上仅封装到 运行。请注意,由于版本 14.0 也是 Mac 上 iOS 的 first 版本,您可以放心地假设它不能在 Mac 上,如果版本是 14.0 之前的版本。

// Swift
var isiOSAppOnMac = false
if #available(iOS 14.0, *) {
    isiOSAppOnMac = ProcessInfo.processInfo.isiOSAppOnMac
}
print("\(isiOSAppOnMac ? "iOS app on Mac" : "not iOS on Mac")!")

或者如果你更喜欢Objective-C:

// Objective-C
BOOL isiOSAppOnMac = false;
if (@available(iOS 14.0, *)) {
    isiOSAppOnMac = [NSProcessInfo processInfo].isiOSAppOnMac;
}
NSLog(@"%@", isiOSAppOnMac ? @"iOS app on Mac" : @"not iOS app on Mac");

参考: Apple: Running Your iOS Apps on macOS

要检查应用程序是否在 Mac Apple Silicon(如 M1)上处于 iOS 模式,您必须检查仅适用于 [=19= 的新变量] 14+ :

Objective-c :

if (@available(iOS 14.0, *) && [NSProcessInfo processInfo].isiOSAppOnMac) {
    // on Mac
}

Swift :

if #available(iOS 14.0, *), ProcessInfo.processInfo.isiOSAppOnMac {
    // on Mac
}

最简单的方法:

struct Environment {
  static let isSimulator: Bool = {
    #if arch(i386) || arch(x86_64)
    return true
    #else
    return ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"] != nil
    #endif
  }()
}

用法:

Environment.isSimulator

此代码还会检查该应用是否 运行 作为 Mac Catalyst 应用。

var isiOSAppOnMac: Bool = {
#if targetEnvironment(macCatalyst)
    return true
#else
    if #available(iOS 14.0, *) {
        return ProcessInfo.processInfo.isiOSAppOnMac
    } else {
        return false
    }
#endif
}()