Swift 同时支持应用程序和扩展程序的库
Swift library that supports both app and extension
我已经为我的 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
并在我的扩展目标中为 Active Compilation Conditions
设置 IS_EXTENSION
,并在我的应用程序扩展中为 Preprocessor Macros
设置 IS_EXTENSION=1
,但是库仍然给我警告这些行。
第一个解决方案
我建议您使用 UIApplication 注入到您的库中。可以这样实现。
您的 lib 实例可能与此类似:
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 launching 函数中完成:
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
DarrenLib.shared.setup(application)
return true
}
我不建议使用预处理器宏,因为它取决于额外的设置要求,而这些要求无法通过抛出源代码来完成。
第二种解决方案
此外,您目前正在使用应用程序和扩展程序目标。您可以创建这些框架:
- DJSwiftCommonHelpers。在此框架中将包含可在应用程序和扩展目标上运行的源代码。
- DJSwiftAppHelpers。该框架将包含源代码,其中将包含 UIKit 特定案例,例如 UIApplication shared instance.
- DJSwiftExtensionHelpers。在此框架中将包含仅特定于扩展的源代码(如果有的话)。
DJApp 将嵌入 DJSwiftCommonHelpers 和 DJSwiftAppHelpers 框架。
DJNotificationExtension 将嵌入 DJSwiftCommonHelpers 和 DJSwiftExtensionHelpers 框架。
您的问题有几个答案。一般来说,答案是肯定的和否定的。
首先:
#if !IS_EXTENSION
// Cancel the background task
UIApplication.shared.endBackgroundTask(bgTask)
#endif
这种方法或多或少是可行的,可能会奏效,但肯定不适用于 Carthage(我看到你在 https://github.com/ddaddy/DJSwiftHelpers 中使用的是这种方法),如果可以的话,可能会使用 Pods 或 SwiftPM确保标志在编译时正确设置。
原因很简单,你居然自己回答了——是编译时标志。
Carthage 编译框架并构建二进制文件作为 carthage build/update
过程的一部分,因此您最终得到的是已经存在的二进制文件。这个标志已经被解决,并且可能是错误的,因为没有设置。 因此,对于迦太基库,应用程序或扩展目标中没有构建时间标志 'work'。
至于迦太基 - 我可以建议在 DJSwiftHelpers.xcodeproj
中增加 targets/schemes。对于具有多平台支持的迦太基库,如 iOS、tvOS 和 macOS,处理多平台支持的方式相同。添加一个方案 DJSwiftHelpers-extensions
,确保它使用正确的构建标志构建二进制文件,carthage 将生成两个不同的二进制文件。 Link 一个是扩展,其次是应用程序,它可能会起作用。
其他可能性:
按照 Ramis 回答中的建议使用 UIApplication 注入
使用注入,但实际上您可以定义第二个库仅用于应用程序目标,包含一个 ObjC class 和重写的“+加载”方法,例如:
#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 - 如果我没记错的话,库代码将与应用程序一起编译,因此它可能会“看到”那里设置的编译时标志。
我已经为我的 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
并在我的扩展目标中为 Active Compilation Conditions
设置 IS_EXTENSION
,并在我的应用程序扩展中为 Preprocessor Macros
设置 IS_EXTENSION=1
,但是库仍然给我警告这些行。
第一个解决方案
我建议您使用 UIApplication 注入到您的库中。可以这样实现。
您的 lib 实例可能与此类似:
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 launching 函数中完成:
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
DarrenLib.shared.setup(application)
return true
}
我不建议使用预处理器宏,因为它取决于额外的设置要求,而这些要求无法通过抛出源代码来完成。
第二种解决方案
此外,您目前正在使用应用程序和扩展程序目标。您可以创建这些框架:
- DJSwiftCommonHelpers。在此框架中将包含可在应用程序和扩展目标上运行的源代码。
- DJSwiftAppHelpers。该框架将包含源代码,其中将包含 UIKit 特定案例,例如 UIApplication shared instance.
- DJSwiftExtensionHelpers。在此框架中将包含仅特定于扩展的源代码(如果有的话)。
DJApp 将嵌入 DJSwiftCommonHelpers 和 DJSwiftAppHelpers 框架。
DJNotificationExtension 将嵌入 DJSwiftCommonHelpers 和 DJSwiftExtensionHelpers 框架。
您的问题有几个答案。一般来说,答案是肯定的和否定的。
首先:
#if !IS_EXTENSION
// Cancel the background task
UIApplication.shared.endBackgroundTask(bgTask)
#endif
这种方法或多或少是可行的,可能会奏效,但肯定不适用于 Carthage(我看到你在 https://github.com/ddaddy/DJSwiftHelpers 中使用的是这种方法),如果可以的话,可能会使用 Pods 或 SwiftPM确保标志在编译时正确设置。
原因很简单,你居然自己回答了——是编译时标志。
Carthage 编译框架并构建二进制文件作为 carthage build/update
过程的一部分,因此您最终得到的是已经存在的二进制文件。这个标志已经被解决,并且可能是错误的,因为没有设置。 因此,对于迦太基库,应用程序或扩展目标中没有构建时间标志 'work'。
至于迦太基 - 我可以建议在 DJSwiftHelpers.xcodeproj
中增加 targets/schemes。对于具有多平台支持的迦太基库,如 iOS、tvOS 和 macOS,处理多平台支持的方式相同。添加一个方案 DJSwiftHelpers-extensions
,确保它使用正确的构建标志构建二进制文件,carthage 将生成两个不同的二进制文件。 Link 一个是扩展,其次是应用程序,它可能会起作用。
其他可能性:
按照 Ramis 回答中的建议使用 UIApplication 注入
使用注入,但实际上您可以定义第二个库仅用于应用程序目标,包含一个 ObjC class 和重写的“+加载”方法,例如:
#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 - 如果我没记错的话,库代码将与应用程序一起编译,因此它可能会“看到”那里设置的编译时标志。