Detect if app is running on a macOS beta version

Viewed 543

I would like to be able to somehow detect if my app is running on a beta version of macOS 11, as there are some known bugs I want to inform users about. I only want to show such an alert to macOS 11 beta users, meaning not macOS 10.15 users nor users on the final version of macOS 11. I could of course just submit an app update to remove the alert when macOS 11 is close to being done, but it would be nice to have something reusable I could use in multiple apps and for future macOS beta versions.

Constraints:

  • The app is sandboxed.
  • The app is in the App Store, so no private APIs.
  • The app doesn't have a network entitlement, so the detection needs to be offline.
  • I don't want to bundle a list of known macOS build numbers and compare that.

My thinking is that maybe it's possible to use some kind of sniffing. Maybe there are some APIs that return different results when the macOS version is a beta version.

2 Answers

I believe you're out of luck. About This Mac uses PrivateFrameworks/Seeding.framework, here the important disassembly:

/* @class SDBuildInfo */
+(char)currentBuildIsSeed {
    return 0x0;
}

So it seems this is a build time compiler flag. The plists in the framework don't contain this flag unfortunately.

Sample private API usage: kaloprominat/currentBuildIsSeed.py

For the crazy ones: It would be possible to read the binary and compare the assembly for the function. I'd start with the class-dump code, which gets you different fat binaries and the function offset.

This is far from perfect but macOS BigSur release notes mention:

Known Issues
In Swift, the authorizationStatus() property of CLLocationManager is incorrectly exposed as a method instead of a property. (62853845)

This^ is new API introduced in MacOS11 / iOS14

So one could detect this for this particular beta.

import CoreLocation
func isMacOS11Beta() -> Bool {
    var propertiesCount = UInt32()
    let classToInspect = CLLocationManager.self
    var isMacOS11OrHigher = false
    var isMacOS11Beta = false
    let propertiesInAClass = class_copyPropertyList(CLLocationManager.self, &propertiesCount)
    if classToInspect.responds(to: NSSelectorFromString("authorizationStatus")) {
        isMacOS11OrHigher = true
        isMacOS11Beta = true
        for i in 0 ..< Int(propertiesCount) {
            if let property = propertiesInAClass?[i], let propertyName = NSString(utf8String: property_getName(property)) as String? {
                if propertyName == "authorizationStatus" {
                    isMacOS11Beta = false
                }
            }
        }
        free(propertiesInAClass)
    }
    return isMacOS11OrHigher && isMacOS11Beta
}
Related