26

I offer an iOS app on the App Store. With the launch of Apple's M1 Macs it's possible to run iOS apps on macOS. I want to prevent that my app is used on macOS, for example by throwing an exception after launch or calling exit(0) at a later time.

How can I detect that the app is running on an M1 Mac?

To a certain extent, iOS apps running on Macs seem to report themselves as iPads1, so this rules out some common ways to identify the device.

Some details to provide context:

  1. I already removed the app from the Mac App Store on App Store Connect.

  2. The app is made and optimized for touch screens. The current version would offer a very bad user experience when run on macOS. It would require many changes and a lot of effort to make it a good Mac app. I don't have any plans, let alone the resources to do that.

  3. On the surface this might seem similar to the question "How can I detect if my app runs on a jailbroken device?". Technically, this might be correct, and I understand that it's generally not advisable to implement jailbreak detection to prevent IAP hacks etc. An important difference is that Apple is actively trying to prevent jailbreaks and strongly discourages users from doing so, which seems to keeps the jailbreak community rather small and off mainstream, but on the other hand, Apple obviously wants to have as many iOS apps as possible available on Macs. It's currently very easy to run iOS apps on Macs, even if they are not offered in the Mac App Store. There are instructions on popular tech blogs like MacRumors and 9to5mac. I want to make sure that at least this easy way to run the app on a mac is prevented.

  4. Many implementation details in this app have been developed under the assumption that the app will only ever run in an iOS sandbox that users don't have easy access to. Now, it's probably much easier for users to run the app with modified resources, user defaults or contents of directories like Application Support, including files that I assumed to be always immutable. If users find a way to access content in the app that usually requires in-app purchases or subscriptions, for example by fudging .plists or renaming resource files in an unexpected way, it's a real business risk.


1 At the time of the original post, M1 Macs appeared to report themselves via hw.machine as model identifier iPad8,6. A tweet that provided a few more details has since been removed.

Theo
  • 3,826
  • 30
  • 59
  • 1
    I'm not as concerned as you are. The two links you provided - one is a 5 step process and one is a 6 step (and involves using the IAP file and that's just to start. For me? The bottom line is to (a) first make your app work on iOS devices as best as possible, like using auto layout or SwiftUI, then (b) let the "buyer" beware. Yes, this **is** a hole on Apple's end and maybe they'll take care of it - but seriously, if you must? Add something to your iOS App store page (which I believe will also appear on the MAS) that states you make no promises when using your app on a Mac. –  Nov 27 '20 at 20:00
  • It's not just a user experience issue. I added (4.) to the question for clarification. – Theo Nov 29 '20 at 09:05
  • I have found that some apps tie themselves to the device using a unique identifier (for example some two factor authenticators) and do not function even if sideloaded to an M1 mac. This same process could be used to prevent your app from being ported to an M1 mac. – aquagremlin May 03 '21 at 02:29

5 Answers5

53

Apple's framework allows you to detect if the app is running as an iOS app on Mac by using the process info flag isiOSAppOnMac.

This flag is available from iOS 14.0 and therefore needs to be encapsulated to only run on those versions. Note that since version 14.0 is also the first version for iOS on Mac, you can safely assume that it cannot be on a Mac if the version is prior 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")!")

Or if you prefer 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");

Reference: Apple: Running Your iOS Apps on macOS

LGP
  • 4,135
  • 1
  • 22
  • 34
  • 2
    Oh, nice. A straightforward, native API. I have no idea why I didn't find that when I googled for a solution. – Theo Nov 30 '20 at 14:16
  • `#import + (void)deviceModel { struct utsname systemInfo; uname(&systemInfo); NSString *deviceModel = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; NSLog(@"%@", deviceModel); } ` we can only detect if an iOS app is running on mac, but we can't know the real device info by the code above, right? it prints iPad – Grey Feb 02 '23 at 06:38
4

This code also checks if the app is running as a Mac Catalyst app.

var isiOSAppOnMac: Bool = {
#if targetEnvironment(macCatalyst)
    return true
#else
    if #available(iOS 14.0, *) {
        return ProcessInfo.processInfo.isiOSAppOnMac
    } else {
        return false
    }
#endif
}()
rockdaswift
  • 9,613
  • 5
  • 40
  • 46
0

The simplest way:

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

usage:

Environment.isSimulator
Rok Gregorič
  • 2,377
  • 1
  • 13
  • 11
-2

Your question has following subquestions.

  1. How to not allow my iOS app to be available on Mac when?

If you would like to limit your app to be only downloadable on iOS devices and not macOS devices then in the App Store Connect you can disable the Mac availability for your app. Learn more

  1. How to know if my app iOS is running under macOS powered by M1?

You have to get information about CPU and this question was already asked and has a good answer here

Blazej SLEBODA
  • 8,936
  • 7
  • 53
  • 93
  • Re 1: I already stated in my question that I disabled Mac availability. Re 2: What do these functions actually return in this situation? What identifiers should I test for? – Theo Nov 27 '20 at 20:50
  • It would be great to have a Mac with M1 to test exact cpu name – Blazej SLEBODA Nov 27 '20 at 21:20
-6

For checking if app is running in iOS mode on a Mac Apple Silicon (like M1), you have to check the new var available ONLY for iOS 14+ :

Objective-c :

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

Swift :

if #available(iOS 14.0, *), ProcessInfo.processInfo.isiOSAppOnMac {
    // on Mac
}
Medhi
  • 2,656
  • 23
  • 16