【问题标题】:Swift library that supports both app and extension支持应用程序和扩展程序的 Swift 库
【发布时间】:2020-11-05 14:16:49
【问题描述】:

我为我的 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,但是库仍然在这些行上给我警告。

【问题讨论】:

    标签: ios swift frameworks


    【解决方案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
        }
    }
    

    作为示例注入可以在完成启动功能中完成:

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        
        DarrenLib.shared.setup(application)
        
        return true
    }
    

    我不建议使用预处理器宏,因为它依赖于无法完成的附加设置要求抛出源代码。

    第二个解决方案

    同样,您目前正在使用应用程序和扩展程序目标。您可以创建这些框架:

    1. DJSwiftCommonHelpers。在这个框架中将包含适用于应用和扩展目标的源代码。
    2. DJSwiftAppHelpers。该框架将包含源代码,其中将包含 UIKit 特定案例,例如 UIApplication shared 实例。
    3. DJSwiftExtensionHelpers。在此框架中,将包含仅适用于扩展的源代码(如果有)。

    DJApp 将嵌入 DJSwiftCommonHelpersDJSwiftAppHelpers 框架。

    DJNotificationExtension 将嵌入 DJSwiftCommonHelpersDJSwiftExtensionHelpers 框架。

    【讨论】:

    • 我也有兴趣看到不同的解决方案。
    • 感谢您的建议。我不喜欢必须准备库的想法。该库实际上是我多年来使用的一堆助手,并且倾向于在我的所有项目中导入。奇怪的是,它对扩展不友好。
    • 您是否在 GitHub 上托管了类似的项目,我可以进行试验?
    • @Darren 添加了第二个解决方案,但我无法实现一个框架解决方案。
    • 你知道 GitHub 上的第 3 方库,它正在处理应用程序和扩展目标并使用 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 进程的一部分,因此您最终会得到已经存在的二进制文件。这个标志已经被解析了,并且可能是假的,因为没有设置。 因此,应用或扩展目标中的任何构建时间标志都不会对 carthage 库“起作用”。

    至于迦太基——我可以建议在DJSwiftHelpers.xcodeproj 中制定额外的目标/计划。对于具有多平台支持的 carthage 库(如 iOS、tvOS 和 macOS),处理多平台支持的方式相同。添加一个方案DJSwiftHelpers-extensions,确保它使用正确的构建标志构建二进制文件,carthage 将生成两个不同的二进制文件。将一个链接到扩展,第二个链接到应用程序,它可能会起作用。

    其他可能性:

    1. 使用 Ramis 答案中建议的 UIApplication 注入

    2. 使用注入,但实际上您可以定义第二个库仅用于应用程序目标,其中包含一个带有覆盖“+ load”方法的 ObjC 类,例如:

    #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
    

    它有点乱,但不允许在应用程序委托中插入。不过,我个人不会使用它。

    1. 使用 cocoapods 或 SwiftPM - 如果我没记错的话,库代码将与应用程序一起编译,因此它可能会“看到”那里设置的编译时间标志。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-01
      • 2020-03-05
      • 1970-01-01
      • 1970-01-01
      • 2017-06-20
      相关资源
      最近更新 更多