How to detect if code is running in Main App or App Extension Target?
You can use a preprocessor macro:
In the project settings use the dropdown in the topbar to select your extension target:
Then:
- Click
Build Settings
- Find (or search)
Preprocessor Macros
underApple LLVM 6.0 - Preprocessing
- 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
Detect whether run target is App Extension or iOS App
Run time checks are out, because Xcode won't let you compile extension code that uses sharedApplication
. It has to be a compile-time check.
Unfortunately this check isn't built in, you have to add it. You need to do something like:
- In the project settings for the today extension, under "Other C Flags", add your own custom compiler macro. For a macro named
TODAY_EXTENSION
, add-DTODAY_EXTENSION
:
In your code, check this macro using something like
#ifndef TODAY_EXTENSION
... app-only code here ...
#endifConversely, code that should only exist in the extension would look like
#ifdef TODAY_EXTENSION
... extension-only code here ...
#endif
It is possible to detect if my framework is running as part of the main app or an extension?
One option is to check the file extension of the current target. This has the advantage that it works in shared libraries and frameworks, whereas other options often only work within a target itself:
+ (BOOL) isAppExtension
{
return [[[NSBundle mainBundle] executablePath] containsString:@".appex/"];
}
This answer was informed by this question and answer. Those answers also outline how to set a preprocessor macro, which would be another good option in some cases, though that wouldn't be accessible from your framework.
I've not marked this question as a duplicate of that one, however, as these options are generic to all App extensions, neither is particularly elegant, and there may be WatchKit-specific options for what you're trying to achieve.
ios: how do I check for app vs extension context
Since your extension target's bundleIdentifier
will be different than your main app you can check bundleIdentifier
value. Which can be accessed by:
Bundle.main.bundleIdentifier
I've tested this on a Today Extension only and not sure if it'd work for other extensions. For me the output was like this:
Main App: com.example.app
Extension: com.example.app.today
Finally this method would allow you to differentiate the extensions in which the code is running.
static var isInExtension: Bool
{
// print ("main bundleIdentifier \(Bundle.main.bundleIdentifier)")
if Bundle.main.bundleIdentifier?.hasSuffix("Extention") ?? false {
return true
}
return false
}
iOS WatchKit - how to determine if your code is running in watch extension or the app
I've accomplished this by checking the bundle identifier:
if ([[[NSBundle mainBundle] bundleIdentifier] isEqualToString:kAppBundleIdentifier]) {
// Running in main app
}
else if ([[[NSBundle mainBundle] bundleIdentifier] isEqualToString:kWatchBundleIdentifier]) {
// Running in extension
}
How can I check whether my shared code is running in a WidgetKit widget or full app?
Here is possible helper function to detect if you run in widget. Tested with Xcode 12 / iOS 14.
func isInWidget() -> Bool {
guard let extesion = Bundle.main.infoDictionary?["NSExtension"] as? [String: String] else { return false }
guard let widget = extesion["NSExtensionPointIdentifier"] else { return false }
return widget == "com.apple.widgetkit-extension"
}
In Swift, how to ignore a part of the code when running from an App Extension target?
You could introduce a new Custom Flag (similar to the DEBUG flag) for the extension target. In your Build Settings look for the Custom Flags and add a new one (e.g. "EXTENSION"). Like here in the screenshot, but also do it for release.
In your Code you could then do something like
#if EXTENSION
// here goes code that is only compiled in the extension
#else
// here goes code that is only compiled outside the extension
#endif
How to detect if app is being built for device or simulator in Swift
Update 30/01/19
While this answer may work, the recommended solution for a static check (as clarified by several Apple engineers) is to define a custom compiler flag targeting iOS Simulators. For detailed instructions on how to do to it, see @mbelsky's answer.
Original answer
If you need a static check (e.g. not a runtime if/else) you can't detect the simulator directly, but you can detect iOS on a desktop architecture like follows
#if (arch(i386) || arch(x86_64)) && os(iOS)
...
#endif
After Swift 4.1 version
Latest use, now directly for all in one condition for all types of simulators need to apply only one condition -
#if targetEnvironment(simulator)
// your simulator code
#else
// your real device code
#endif
For more clarification, you can check Swift proposal SE-0190
For older version -
Clearly, this is false on a device, but it returns true for the iOS Simulator, as specified in the documentation:
The arch(i386) build configuration returns true when the code is compiled for the 32–bit iOS simulator.
If you are developing for a simulator other than iOS, you can simply vary the os
parameter: e.g.
Detect the watchOS simulator
#if (arch(i386) || arch(x86_64)) && os(watchOS)
...
#endif
Detect the tvOS simulator
#if (arch(i386) || arch(x86_64)) && os(tvOS)
...
#endif
Or, even, detect any simulator
#if (arch(i386) || arch(x86_64)) && (os(iOS) || os(watchOS) || os(tvOS))
...
#endif
If you instead are ok with a runtime check, you can inspect the TARGET_OS_SIMULATOR
variable (or TARGET_IPHONE_SIMULATOR
in iOS 8 and below), which is truthy on a simulator.
Please notice that this is different and slightly more limited than using a preprocessor flag. For instance you won't be able to use it in place where a if/else
is syntactically invalid (e.g. outside of functions scopes).
Say, for example, that you want to have different imports on the device and on the simulator. This is impossible with a dynamic check, whereas it's trivial with a static check.
#if (arch(i386) || arch(x86_64)) && os(iOS)
import Foo
#else
import Bar
#endif
Also, since the flag is replaced with a 0
or a 1
by the swift preprocessor, if you directly use it in a if/else
expression the compiler will raise a warning about unreachable code.
In order to work around this warning, see one of the other answers.
Related Topics
Using Tesseract to Recognize License Plates
Uiwebview VS Wkwebview to Load Local HTML
Please Clear Some Confusions Regarding Uiviewcontroller
Firebase Database Transaction When App Is in Background iOS
Calculate Uitableviewcell Height to Fit String
I Want to Create Aes 128 Using Cfb Encryption with No Padding in Objective C
How to Run Timer Though the App Entered Background or Is Terminated
Nsstring Encoding Returns Nil on Url Content
How to Parse This JSON in Swift
Sprite Kit Create an Iadbanner
How to Use Git Properly with Xcode
Adding Multiple Arrays to Form One Final Array. Debug Swift Xcode
Differences Between Websockets and Long Polling for Turn Based Game Server
Update a Label Through Button from Different View
Swift Access Control with Target Selectors
"The Data Couldn't Be Read Because It Is Missing" Error When Decoding JSON in Swift