#ios #swift #frameworks
#iOS #swift #фреймворки
Вопрос:
Я создал библиотеку для своего приложения iOS, но получаю предупреждение linking against a dylib which is not safe for use in application extensions
.
Я знаю, что это потому, что я не включил Allow app extension API only
свою библиотеку. Поэтому, когда я включаю этот параметр, моя библиотека выдает ошибки там, где я использовал UIApplication.shared
.
Я знаю, что не могу использовать shared
в своем расширении, и на самом деле в этом нет необходимости, но эта библиотека используется как моим приложением, так и моим расширением.
Итак, вопрос в том, как я могу скомпилировать библиотеку с защитой UIApplication.shared
?
Я уже использую это:
#if !IS_EXTENSION
// Cancel the background task
UIApplication.shared.endBackgroundTask(bgTask)
#endif
и установите IS_EXTENSION
для Active Compilation Conditions
в моей цели расширения, а также IS_EXTENSION=1
для Preprocessor Macros
в моем расширении приложения, однако библиотека по-прежнему выдает мне предупреждения в этих строках.
Ответ №1:
1-е решение
Я рекомендую вам использовать внедрение UIApplication в вашу библиотеку. Это может быть достигнуто следующим образом.
Ваш экземпляр библиотеки может выглядеть примерно так:
class DarrenLib {
static var shared = DarrenLib()
// User application instance everywhere where needed in your lib.
private var application: UIApplication?
func setup(_ app: UIApplication) {
self.application = app
}
}
В качестве примера инъекцию можно выполнить в функции запуска did finish:
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
DarrenLib.shared.setup(application)
return true
}
Я бы не рекомендовал использовать макросы препроцессора, потому что это зависит от дополнительных требований к настройке, которые невозможно выполнить с помощью исходного кода.
2-е решение
Также, поскольку вы в настоящее время используете целевые приложения и расширения. Вы могли бы создать эти фреймворки:
- Djswiftcommon Helpers. В этой структуре будет содержаться исходный код, который будет работать с приложением и целевым расширением.
- DJSwiftAppHelpers. Этот фреймворк будет содержать исходный код, который будет содержать конкретные случаи UIKit, такие как общий экземпляр UIApplication.
- DJSwiftExtensionHelpers. В этой структуре будет содержаться исходный код, специфичный только для расширений, если таковые имеются.
DJApp будет встраивать фреймворки djswiftcommon Helpers и DJSwiftAppHelpers.
DJNotificationExtension будет встраивать фреймворки djswiftcommon Helpers и DJSwiftExtensionHelpers.
Комментарии:
1. Также мне интересно увидеть разные решения.
2. Спасибо за предложение. Мне не нравится идея подготовки библиотеки. На самом деле библиотека — это набор помощников, которые я использовал на протяжении многих лет и, как правило, импортирую во все свои проекты. Есть странный вариант, который не подходит для расширения.
3. Есть ли у вас аналогичный проект, размещенный на GitHub, с которым я мог бы поэкспериментировать?
4. @Darren добавил 2-е решение, но я не смог достичь одного рамочного решения.
5. Знаете ли вы стороннюю библиотеку на GitHub, которая работает с целевыми приложениями и расширениями и использует общий экземпляр UIApplication. Если да. Вы могли бы посмотреть, как они работают.
Ответ №2:
На ваши вопросы есть несколько ответов. В общем, ответ — и ДА, и НЕТ.
Прежде всего:
#if !IS_EXTENSION
// Cancel the background task
UIApplication.shared.endBackgroundTask(bgTask)
#endif
Этот подход более или менее в порядке и, вероятно, будет работать, но точно не с Carthage (это то, что я вижу, вы используете в https://github.com/ddaddy/DJSwiftHelpers ), возможно, с помощью Pods или SwiftPM, если вы можете быть уверены, что флаг правильно установлен во время компиляции.
Причина проста, и вы сами на нее ответили — это флаг времени компиляции.
Carthage компилирует фреймворк и создает двоичный файл как часть carthage build/update
процесса, так что в итоге вы получаете уже существующий двоичный файл. Этот флаг уже был разрешен и, вероятно, был false, поскольку не установлен. Таким образом, никакие флаги времени сборки в приложении или цели расширения не будут «работать» для библиотек carthage.
Что касается карфагена — я могу предложить добавить дополнительные цели / схемы DJSwiftHelpers.xcodeproj
. Аналогично поддержке мультиплатформенности обрабатывается для библиотек carthage с поддержкой нескольких платформ, таких как iOS, tvOS и macOS. Добавьте схему DJSwiftHelpers-extensions
, убедитесь, что она создает двоичный файл с использованием правильных флагов сборки, и carthage создаст два отличительных двоичных файла. Свяжите одно с расширениями, а второе с приложениями, и это может сработать.
Другие возможности:
-
Используйте внедрение UIApplication, как предложено в ответе Ramis
-
Используйте инъекцию, но на самом деле вы можете определить вторую библиотеку, которая будет использоваться только для целей applicatyion, содержащую один класс ObjC с переопределенным методом ‘ load’, например:
#import 'yours helpers library'
@implementation SomeClass
(void)load {
// This is called once, when module is being loaded,
// "Invoked whenever a class or category is added to the Objective-C
// runtime; implement this method to perform class-specific behavior
// upon loading."
[YourHelperLibraryClass setupWithApplication:[UIApplication shared]];
}
@end
Это немного запутанно, но позволит не подключаться к делегату приложения. Я бы лично не использовал ее для этого.
- Используйте cocoapods или SwiftPM — если я правильно помню, код библиотеки будет скомпилирован вместе с приложением, поэтому возможно, что он «увидит» установленные там флаги времени компиляции.