Как определить, выполняется ли код в основном приложении или цели расширения приложения?

Кто-нибудь знает, как вы определяете изнутри своего кода, работаете ли вы внутри расширения приложения?

У меня есть приложение, которое разделяет классы между приложением и расширением. Код приложения использует [UIApplication sharedApplication], но он недоступен из расширения, поэтому он не будет компилироваться, говоря:

'sharedApplication' недоступен: недоступен iOS (расширение приложения)

Поэтому мне нужен способ определить, что я нахожусь в расширении, и использовать альтернативу sharedApplication, если это так.


person Mark Bridges    schedule 30.07.2014    source источник
comment
проверьте эту тему ‹stackoverflow.com/a/29076070/366025›. есть другое решение MACRO без Preprocessor Macros   -  person TopChul    schedule 17.03.2015


Ответы (7)


Вы можете использовать макрос препроцессора:

В настройках проекта используйте раскрывающийся список на верхней панели, чтобы выбрать цель расширения: введите здесь описание изображения

Затем:

  1. Нажмите Build Settings
  2. Найдите (или найдите) Preprocessor Macros под Apple LLVM 6.0 - Preprocessing
  3. Добавьте TARGET_IS_EXTENSION или любое другое имя по вашему выбору в разделы отладки и выпуска.

Затем в вашем коде:

#ifndef TARGET_IS_EXTENSION // if it's not defined
    // Do your calls to UIApplication
#endif
person Andrew    schedule 30.07.2014
comment
Спасибо, этот подход работает, но на самом деле все наоборот, мне нужно обнаружить, если подумать. Если это не расширение, используйте UIApplication. В любом случае, я решил это с помощью флага в настройках сборки приложения, определяющего его как приложение, а не как расширение. - person Mark Bridges; 02.08.2014
comment
@MarkBridges Извините за это. Я исправил это в своем ответе для будущих читателей. - person Andrew; 02.08.2014
comment
Это решение не будет работать для кода в фреймворке. В настоящее время мы проверяем имя пакета приложения, чтобы увидеть, работает ли код в расширении, но я хотел бы найти лучший способ. - person roustem; 19.09.2014
comment
не могли бы вы описать свой код, я также столкнулся с той же проблемой, какой флаг или код мне нужно добавить, тогда приложение выберет на основе приложения или расширения. Помните, что я создал общую структуру, этот код должен выполняться на основе идентификатора пакета. - person loganathan; 08.10.2014
comment
@loganathan ответ @siuying на это. - person Andrew; 08.10.2014
comment
но если вы собираетесь использовать программный подход, он будет работать, но это приведет к ошибке компиляции, верно? Например: как вы будете писать код для выбора класса uiapplication в собственном приложении, а не в приложении расширения. Потому что для меня это показывает ошибку компиляции, когда я сопоставляю идентификатор пакета - person loganathan; 08.10.2014
comment
Мой поток кода, похоже, вообще не попадает в ifdef. Есть идеи, почему? - person Shwethascar; 07.04.2016

Как сказано в документации Apple:

Когда вы создаете расширение на основе шаблона Xcode, вы получаете пакет расширений, оканчивающийся на .appex.

Итак, мы можем использовать следующий код:

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

// Swift version
if Bundle.main.bundlePath.hasSuffix(".appex") {
    // this is an app extension
}
person Ruslan Skorb    schedule 28.03.2015
comment
Это должен быть выбранный ответ, это гораздо предпочтительнее, чем зависимость от макроса препроцессора. - person MobileVet; 03.12.2017
comment
Согласитесь, это чище. - person some_id; 07.08.2020
comment
Не совсем чище, это косвенно и может измениться в будущем, если это расширение изменится, плюс условная компиляция позволит вам исключить ресурсы или методы, которые не могут скомпилироваться в вашем расширении. - person Wil Gieseler; 31.08.2020

Макрос препроцессора будет работать в основном, но не будет работать в общей библиотеке (например, в Cocoapods или общих фреймворках).

В качестве альтернативы вы можете использовать следующий код.

@implementation ExtensionHelpers

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

@end

Это работает путем проверки исполняемого пути пакета, поскольку только расширение приложения имеет расширение «.appex».

person siuying    schedule 24.09.2014
comment
Я по-прежнему получаю ошибку компиляции при компиляции общей библиотеки, так как для нее установлен флаг Require Only App-Extension-Safe API, установленный в YES. Как избежать ошибки компиляции, используя этот код, который вы написали выше? - person cohen72; 23.02.2015
comment
Я не рекомендую использовать -[NSString containsString:] в продакшене по двум причинам: 1. Это не опубликованный API, т.е. официальная страница помощи не упоминает об этом (что, скорее всего, является ошибкой, но в любом случае); 2. Вылетит на iOS7. Вместо этого используйте -[NSString rangeOfString:]. - person Alexander Vasenin; 09.06.2015
comment
@AlexanderVasenin 2: это задокументировано в NSString.h и четко помечено как доступное для iOS 8+. - person Maciej Swic; 31.08.2015

Свифт 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`
person neoneye    schedule 03.07.2019
comment
Это потрясающе! Спасибо :) - person Baran Emre; 22.10.2019

Вы можете добавить макрос препроцессора в цель расширения, а затем проверить с помощью #ifdef внутри вашего класса.

person Marcelo Fabri    schedule 30.07.2014

Решение, предложенное Дедом Морозом, у меня не сработало.

Что сработало:

  1. Выберите цель расширения
  2. Настройки сборки
  3. Поиск пользовательских флагов
  4. Добавьте новый флаг (пример: EXTENSION) для отладки и выпуска

введите здесь описание изображения

Теперь код:

#if EXTENSION
// IF is extension (SIRI) we do stuff
#else
// ELSE is main app do more stuff
#endif
person Tiago Mendes    schedule 11.02.2021

Для моей общей библиотеки я создал отдельную цель, для которой флаг расширений приложения установлен на «да», и использовал макрос препроцессора в настройках сборки для этой конкретной цели.

person cohen72    schedule 23.02.2015