I've created a library for my iOS app but I get the warning linking against a dylib which is not safe for use in application extensions
.
I know this is because I haven't enabled Allow app extension API only
for my library. So when I enable that setting my library gives errors where I have used UIApplication.shared
.
I know I cannot use shared
in my extension, and don't actually need to, but this library is used by both my app and my extension.
So the question is, how can I compile the library with a guard around UIApplication.shared
?
I already use this:
#if !IS_EXTENSION
// Cancel the background task
UIApplication.shared.endBackgroundTask(bgTask)
#endif
and set IS_EXTENSION
for Active Compilation Conditions
in my extension target, and also IS_EXTENSION=1
for Preprocessor Macros
in my app extension, however the library still gives me warnings on these lines.
I recommend you to use UIApplication injection into your lib. It can be achieved like this.
Your lib instance can look similar to this:
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
}
}
As example injection can be done in the did finish launching function:
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
DarrenLib.shared.setup(application)
return true
}
I would not recommend use preprocessor macros, because it becomes depending on additional setup requirements which can not be done throw source code.
Also as you are currently using app and extension targets. You could create these frameworks:
DJApp will be embedding DJSwiftCommonHelpers and DJSwiftAppHelpers frameworks.
DJNotificationExtension will be embedding DJSwiftCommonHelpers and DJSwiftExtensionHelpers frameworks.
There are several answers to your questions. In general, answer is both YES and NO.
First of all:
#if !IS_EXTENSION
// Cancel the background task
UIApplication.shared.endBackgroundTask(bgTask)
#endif
This approach is more or less ok and would probably work, but for sure not with Carthage (that's what I see you use in https://github.com/ddaddy/DJSwiftHelpers), maybe with Pods or SwiftPM if you can assure flag is properly set on compile time.
The reason is simple and you actually answered it yourself - it is a compilation time flag.
Carthage compiles framework and builds the binary as a part of carthage build/update
process, so you end up with already existing binary. This flag was already resolved, and was probably false, since not set. So no build time flags in app or extension target would 'work' for carthage libraries.
As for the carthage - what I can suggest is making additional targets/schemes in DJSwiftHelpers.xcodeproj
. The same way as multiplatform support is handled for carthage libraries that have multi platform support, like both iOS, tvOS and macOS. Add a scheme DJSwiftHelpers-extensions
, make sure it builds binary using proper build flags, and carthage will produce two distinctive binaries. Link one to extensions and second to applications, and it might work.
Other possibilities:
Use UIApplication injection as proposed in Ramis answer
Use the injection, but actually you can define second library to be only used for applicatyion targets, containing one ObjC class with overriden '+ load' method, like:
#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
It is a bit messy, but will allow not to inect in app delegate. I would personally not use it for that though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With