Can an iOS app programmatically detect if it's built for release or debug?

Is it possible for an iOS app to programmatically detect if its built for TestFlight/App Store distribution versus built for development?

The motivation for doing this is so that the app can detect if a push server should send pushes using the Apple production server or the sandbox server - when the app sends the push token to the server, I'd like it to additionally send an indicator to the server so the server knows which of the Apple servers to use.

Is there a way to achieve this?

TIA

Answered by DTS Engineer in 829521022

Argun and I have been chatting about this behind the scenes.

Written by mungbeans in 829311022
Its actually not the build … its the distribution signing that is.

Right.

The answer here varies by platform:

  • On macOS you can do this using the code signing API.

  • That API is not available on iOS, or any of its child platforms, so there isn’t a good way to achieve this goal there.

IMPORTANT I’ve seen folks use a variety of unsupported techniques for this on iOS. The reason why I’ve seen this is that those techniques tend to be brittle, and they ask for help when their code breaks )-: I recommend that you not go down that path.

With the advent of the LightweightCodeRequirements framework we are very close to being able to support this sort of thing on iOS. You can build a requirement without any problems, you just can’t check it (because routines like SecTaskValidateForRequirement are macOS only). I think it’s well worth you filing an enhancement request for an iOS API that let’s a process check a requirement against itself.

Please post your bug number, just for the record.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

This is actually quite easy.

#if DEBUG
let pushEnvironment = "development"
#else
let pushEnvironment = "production"
#endif

This would work in most circumstances and with common Xcode project setups, as by default Xcode sets the aps-environment entitlement to development or production based on whether it is built for debugging or release.

Unfortunately this is not foolproof, as there could be scripts that change the entitlement with a build script, and so on. If you know your builds are simple, then this would work. But it is definitely not a foolproof approach.

The entitlements are built into your signed app and don't exist in a recognizable form, so it is not possible to read them while running. You could possibly use some creative build script engineering to read the aps-environment entry from the file, but with so many variables that goes into anything but the simplest build configurations, this would also be fragile.

So, if this is for your own project (as in, you're not building a library for general use that will answer this question), and you know no build shenanigans are going on the #if DEBUG construct might be the easiest solution.

@Engineer

The problem with this approach is that it assumes a debug build of code equates to the development push server and a release build equates to the production server, which is not the case.

Its actually not the build, as I said in my question that is important and dictates the push server, its the distribution signing that is.

You might have a debug build of code that you want to publish to TestFlight; or you might have a body of code that you first test running with Xcode,then without modifying it you want to build and publish to testflight/App Store; or you might want to create an archive, and then distribute that same archive to TestFlight or as a developer distribution .ipa, and so on.

Maybe I could look through the Firebase Crashlytics code, they detect when code is debuggable i.e. when the get-task-allow entitlement is set, I expect that would be useful and relevant to obtain in this case as that will vary with the distribution signing.

Argun and I have been chatting about this behind the scenes.

Written by mungbeans in 829311022
Its actually not the build … its the distribution signing that is.

Right.

The answer here varies by platform:

  • On macOS you can do this using the code signing API.

  • That API is not available on iOS, or any of its child platforms, so there isn’t a good way to achieve this goal there.

IMPORTANT I’ve seen folks use a variety of unsupported techniques for this on iOS. The reason why I’ve seen this is that those techniques tend to be brittle, and they ask for help when their code breaks )-: I recommend that you not go down that path.

With the advent of the LightweightCodeRequirements framework we are very close to being able to support this sort of thing on iOS. You can build a requirement without any problems, you just can’t check it (because routines like SecTaskValidateForRequirement are macOS only). I think it’s well worth you filing an enhancement request for an iOS API that let’s a process check a requirement against itself.

Please post your bug number, just for the record.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

@eskimo

Is looking for the presence of Bundle.main.appStoreReceiptURL usable in this context? If present it would mean the app requires the Apple push production server

My experience is that inferring X from Y, where X and Y are very different things, is rarely a good idea. In this case X being “which push server to use” and Y being “whether you have an App Store receipt”.

That’s because folks at Apple might change Y without considering it’s impact on your inference, because X doesn’t even enter onto their radar.

Written by mungbeans in 844712022
If present it would mean the app requires the Apple push production server

My understanding is that you can run into all sorts of weird edge cases here. The two that immediately spring to mind are:

  • App Review — I’m hardly an expert on this, but my understanding is that the App Review execution context is an odd hybrid of production and release.

  • Non-App Store distribution — If you test your app using Ad Hoc distribution, it will be distribution signed but not have an App Store receipt


Did you end up filing that ER per the suggestion in my previous post?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Can an iOS app programmatically detect if it's built for release or debug?
 
 
Q