18

This question is based purely on publicly released documents regarding the introduction of application extensions in iOS.

With the introduction of app extensions in iOS 8, it is now possible to "extend custom functionality and content beyond your app and make it available to users while they’re using other apps".

In my implementation of my extension, I am including some classes from my actual app in my extension (models, etc). The problem is that these classes make calls to UIApplication, which is not available in an app extension, and the compiler tells me so.

I thought an easy solution to this would to be enclose any calls to UIApplication in an #if directive.

For example, if I wanted to only include code if I was running on a simulator, I would use:

#if TARGET_IPHONE_SIMULATOR
    // Code Here
#endif

Is there a similar defined macro when the target is an application extension?

Andrew
  • 15,357
  • 6
  • 66
  • 101

3 Answers3

21

You can define your own 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
    // Do your calls to UIApplication
#endif
Andrew
  • 15,357
  • 6
  • 66
  • 101
  • it works :) , but I think I don't understand , isn't the condition means if the your building a target for extension should "Don't call UIApplications" or I missed something? – Mohamed Saleh Dec 25 '15 at 17:27
  • I believe you are correct @MohamedSaleh, my mistake. – Andrew Dec 25 '15 at 19:35
  • no problem , the point here that it actually worked as you advised , not the other way :D , I really don't know why?! – Mohamed Saleh Dec 26 '15 at 11:26
  • because #ifndef means 'If not defined'. So you are only running // Do your calls to UIApplication code if TARGET_IS_EXTENSION is NOT defined, which would be on the primary app, not the extension – vtcajones Jan 03 '19 at 02:06
0

Update: Unfortunately, it doesn't actually work because it is working in __has_feature(attribute_availability_app_extension)-feature manner. Sad.

It is not actually that was asked but it is should be noted:

If you are using Swift, you have @available(iOSApplicationExtension) attribute! It is not actually preprocessor's feature but it is kind of compile time feature.

Example:

@available(iOSApplicationExtension, message="It is meaningless outside keyboard extension")
public var rootInputViewController: UIInputViewController {
    return storedInputViewController
}

Or with #-notation (but probably not):

public static var rootInputViewController: UIInputViewController! {
    guard #available(iOSApplicationExtension 8, *) else {
        return nil
    }

    return storedInputViewController!
}
Valentin Shergin
  • 7,166
  • 2
  • 50
  • 53
  • 1
    This is not correct. `#available(iOSApplicationExtension 8, *)` will be true for for code running in extensions on iOS8+ and _all others_, including iOS apps themselves for all versions. In other words, it would be false only for extensions with iOS versions older than 8. Unfortunately, #available can be used only to strip off old versions of a platform due to this * in the lats parameter. – abjurato Jun 29 '18 at 07:20
-1

You can use the same technique than Apple uses for raising the compilation error.

#if !(defined(__has_feature) && __has_feature(attribute_availability_app_extension))
  //Not in the extension
#else
  //In extension
#end
Angel G. Olloqui
  • 8,045
  • 3
  • 33
  • 31
  • 17
    You must define your own macro as described in the accepted answer. You can define it either in the project settings as described above, or add it to your prefix header file for your extension. You CANNOT use `__has_feature(attribute_availability_app_extension)`. That macro just checks whether the compiler you are using supports building app extensions, and not whether you are currently building one. It will always be true on newer Xcodes (6.2+) even if you are building your main app. I wanted to make sure this is clear, so no one else finding this question uses the macro incorrectly. – bdorfman Apr 08 '15 at 18:25