[Pre-pitch] targetEnvironment(appExtension)

I was not sure whether this should go here or in Feedback Assistant, so I did both: FB9759824

Most apps on Apple's platforms today need to include some kind of extension. For example, a widget extension, share extension, Siri intent handler, etc. Some APIs are excluded from use in extensions and you need to conditionalize the code. The current way to do this is to add a build flag. However, there are a lot of downsides to this. You have to remember to manually add it to every extension target in every app. And it makes code less portable as different apps may use different build flag name for app extensions. And if you share your code, you have to document the build flag.

targetEnvironment(simulator) solved a similar problem for simulator-specific code. I suggest expanding targetEnvironment to cover app extensions too.

Example use-case:

#if targetEnvironment(appExtension)
showErrorMessage("You need to open Settings to grant access.")
#else
UIApplication.shared.open(settingsURL, options: [:], completionHandler: nil)
#endif

Note: I'm aware of @available(macOSApplicationExtension, unavailable), but it works at runtime, and does not cover all the use-cases.

Resources:

3 Likes

The problem here is that the same compiled code can run both in application and extension, for example some utility code extracted into dynamic lib. There is no compiler option to mark specific code for application or extension, only to mark code that can be run in application extension.

And what are cases that runtime doesn’t cover? Your specific example is easily solved with runtime check:

if #available(macOSApplicationExtension, *) {
  showErrorMessage("You need to open Settings to grant access.")
} else {
  UIApplication.shared.open(settingsURL, options: [:], completionHandler: nil)
}

Your provided example does not work (running in an extension):

if #available(macOSApplicationExtension 11, *) {

} else {
	UIApplication.shared.open(URL(string: "-")!, options: [:], completionHandler: nil)
	//=> Compiler error: 'open(_:options:completionHandler:)' is unavailable in application extensions for iOS
	//=> Compiler error: 'shared' is unavailable in application extensions for iOS: Use view controller based solutions where appropriate instead.
}
1 Like

My bad, you are right. Actually, what you want is to check availability of platform regardless of its version, that you can't do now. Something like:

if #available(iOSApplicationExtension, *) { ... }

This is useful only for application extension, because in other cases you need to recompile the code to run it under different environments. But still, conditional compilation flag is not suitable here.