API to detect apps installed by default on macOS

I have an app on the Mac App Store that does uninstallation of Mac applications. Recently the app got rejected saying that it should not uninstall apps which ship with the OS. How can I programmatically retrieve the list of system apps or find out if a given app is a system app? Our technical support query to Apple met with a response that a workaround should be available in the developer forums. Thanks in advance!

Answered by DTS Engineer in 366729022

Hmmm, that seems strange.

I had a chat with SolShare about how they managed to end up here. I’m not going to go into the details but suffice to say that there are two parts to this question, and one of them falls into DTS’s purview.

The two parts are:

  • How do you reliably identify built-in apps?

  • Will an app that removes other apps be allowed on the store?

The first part is a purely technical question, and thus is something that I can address here. The part is about App Review policy, and I can’t comment on that.

With regards the first part, I can’t think of any supported way to answer that question exactly. There is, however, a way to answer a slightly different question, that is, “Is this Apple code?” You can do that by evaluating the

anchor apple
code signing requirement. Pasted in at the end of this email is a tiny test project that does just that.

I must stress that this can produce false positives. For example, Xcode is not a built-in app but is reported as Apple code. However, there are no false negatives, that is, every built-in app will be reported as Apple code. I’ll leave it up to you to decide whether this is sufficient for your needs.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
let appleCodeSignedByApple: SecRequirement = {
    var reqQ: SecRequirement? = nil
    let err = SecRequirementCreateWithString("anchor apple" as NSString, [], &reqQ)
    assert(err == err)
    return reqQ!
}()

func isAppleCodeSignedByApple(_ url: URL) throws -> Bool {
    var codeQ: SecStaticCode? = nil
    let err = SecStaticCodeCreateWithPath(url as NSURL, [], &codeQ)
    guard err == errSecSuccess else {
        throw NSError(domain: NSOSStatusErrorDomain, code: Int(err), userInfo: nil)
    }
    let code = codeQ!

    return SecStaticCodeCheckValidityWithErrors(
        code,
        SecCSFlags(rawValue: kSecCSBasicValidateOnly),
        appleCodeSignedByApple,
        nil
    ) == errSecSuccess
}

let appDir = try! FileManager.default.url(for: .applicationDirectory, in: .localDomainMask, appropriateFor: nil, create: false)
let appDirContents = try! FileManager.default.contentsOfDirectory(at: appDir, includingPropertiesForKeys: nil, options: [])
let appDirApps = appDirContents.filter { $0.pathExtension == "app" }
let sortedAppDirApps = appDirApps.sorted { $0.lastPathComponent < $1.lastPathComponent }
for app in sortedAppDirApps {
    let isApple = try! isAppleCodeSignedByApple(app)
    print("\(isApple ? "+" : " ") \(app.lastPathComponent)")
}

Our technical support query to Apple met with a response that a workaround should be available in the developer forums.

Hmmm, that seems strange. Please drop me a line via email (my address is in my signature), making sure to reference this DevForums thread.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

How is that even possible? Wouldn't your app need root access to uninstall 3rd party software?


You can always run a script on a freshly installed system and use the results. You can also check the signature and developer of apps. Almost all Apple apps and tools are signed. I think there might be some variation in the developer name, but they are all some form of "Apple".

Accepted Answer

Hmmm, that seems strange.

I had a chat with SolShare about how they managed to end up here. I’m not going to go into the details but suffice to say that there are two parts to this question, and one of them falls into DTS’s purview.

The two parts are:

  • How do you reliably identify built-in apps?

  • Will an app that removes other apps be allowed on the store?

The first part is a purely technical question, and thus is something that I can address here. The part is about App Review policy, and I can’t comment on that.

With regards the first part, I can’t think of any supported way to answer that question exactly. There is, however, a way to answer a slightly different question, that is, “Is this Apple code?” You can do that by evaluating the

anchor apple
code signing requirement. Pasted in at the end of this email is a tiny test project that does just that.

I must stress that this can produce false positives. For example, Xcode is not a built-in app but is reported as Apple code. However, there are no false negatives, that is, every built-in app will be reported as Apple code. I’ll leave it up to you to decide whether this is sufficient for your needs.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
let appleCodeSignedByApple: SecRequirement = {
    var reqQ: SecRequirement? = nil
    let err = SecRequirementCreateWithString("anchor apple" as NSString, [], &reqQ)
    assert(err == err)
    return reqQ!
}()

func isAppleCodeSignedByApple(_ url: URL) throws -> Bool {
    var codeQ: SecStaticCode? = nil
    let err = SecStaticCodeCreateWithPath(url as NSURL, [], &codeQ)
    guard err == errSecSuccess else {
        throw NSError(domain: NSOSStatusErrorDomain, code: Int(err), userInfo: nil)
    }
    let code = codeQ!

    return SecStaticCodeCheckValidityWithErrors(
        code,
        SecCSFlags(rawValue: kSecCSBasicValidateOnly),
        appleCodeSignedByApple,
        nil
    ) == errSecSuccess
}

let appDir = try! FileManager.default.url(for: .applicationDirectory, in: .localDomainMask, appropriateFor: nil, create: false)
let appDirContents = try! FileManager.default.contentsOfDirectory(at: appDir, includingPropertiesForKeys: nil, options: [])
let appDirApps = appDirContents.filter { $0.pathExtension == "app" }
let sortedAppDirApps = appDirApps.sorted { $0.lastPathComponent < $1.lastPathComponent }
for app in sortedAppDirApps {
    let isApple = try! isAppleCodeSignedByApple(app)
    print("\(isApple ? "+" : " ") \(app.lastPathComponent)")
}

I don't know what the OP's goals are for detecting Apple apps. But this can be tricky. Here is an example.


I modified the above code slightly to run against the path "/tmp/apps". Then, I copied in a "bash" executable into "/tmp/apps" and slightly modified it. 😉


Here is my output:


+ bash


But...


/tmp/apps $ ./bash

No Apple here!


To avoid this problem, the "kSecCSBasicValidateOnly" should be changed to "kSecCSCheckAllArchitectures".


I assume this will be overcome by events in Catalina

I don't know what the OP's goals are for detecting Apple apps.

SolShare was pretty clear about this in their first post:

I have an app on the Mac App Store that does uninstallation of Mac applications. Recently the app got rejected saying that it should not uninstall apps which ship with the OS.

Thus, false positives are much less of a problem than false negatives.

To avoid this problem, the

kSecCSBasicValidateOnly
should be changed to
kSecCSCheckAllArchitectures
.

The downside to this is that it’s really slow when dealing with large apps (like Xcode).

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
API to detect apps installed by default on macOS
 
 
Q