'How to detect if code is running in Main App or App Extension Target?

Does anyone know how you detect from within your code if you're running inside an App Extension?

I have an app which shares classes between an app and an extension. The app code uses [UIApplication sharedApplication] but this isn't available from within an extension, so it won't compile saying:

'sharedApplication' is unavailable: not available iOS (App Extension)

So I need a way to detect that I'm in the extension and use an alternative to sharedApplication if that's the case.



Solution 1:[1]

You can use a preprocessor macro:

In the project settings use the dropdown in the topbar to select your extension target: enter image description here

Then:

  1. Click Build Settings
  2. Find (or search) Preprocessor Macros under Apple LLVM 6.0 - Preprocessing
  3. Add TARGET_IS_EXTENSION or any other name of your choice in both the debug and release sections.

Then in your code:

#ifndef TARGET_IS_EXTENSION // if it's not defined
    // Do your calls to UIApplication
#endif

Solution 2:[2]

As Apple's documentation says:

When you build an extension based on an Xcode template, you get an extension bundle that ends in .appex.

So, we can use the following code:

if ([[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]) {
    // this is an app extension
}

// Swift version
if Bundle.main.bundlePath.hasSuffix(".appex") {
    // this is an app extension
}

Solution 3:[3]

The preprocessor macro will work mostly, but will not work in shared library (e.g. cocoapods or shared frameworks).

Alternatively you can use following code.

@implementation ExtensionHelpers

+(BOOL) isAppExtension
{
    return [[[NSBundle mainBundle] executablePath] containsString:@".appex/"];
}

@end

This work by checking the bundle executablePath, as only App Extension has extension ".appex".

Solution 4:[4]

Swift 5

let bundleUrl: URL = Bundle.main.bundleURL
let bundlePathExtension: String = bundleUrl.pathExtension
let isAppex: Bool = bundlePathExtension == "appex"

// `true` when invoked inside the `Extension process`
// `false` when invoked inside the `Main process`

Solution 5:[5]

The solution proposed by @Andrew did not work for me.

What worked was:

  1. Select extension target
  2. Build Settings
  3. Search "Custom Flags"
  4. Add a new Flag (example: "EXTENSION") to Debug and Release

enter image description here

Now the code:

#if EXTENSION
// IF is extension (SIRI) we do stuff
#else
// ELSE is main app do more stuff
#endif

Solution 6:[6]

You can add a preprocessor macro on the extension target and then check with a #ifdef inside of your class.

Solution 7:[7]

For my shared library I created a separate target who's app extensions flag is set to yes, and used preprocessor macro's within the build settings for that specific target.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 some_id
Solution 3 siuying
Solution 4 neoneye
Solution 5
Solution 6 Marcelo Fabri
Solution 7 cohen72