#if canImport() does not find frameworks with CocoaPods
Short answer: Using #if canImport(Module)
would not allow you to achieve what you described in a closed source setup. I see some misunderstanding of how this conditional compilation works.
What I mean is that you've already built a framework. Seems that #if canImport
is resolved at a compile time, so it is not dynamic.
When you use already prebuilt mainSDK.framework
, the part #if canImport(additionalSDK)
was already evaluated. And the result depends on the availability of 'additionalSDK' in the build chain, when it was built (so on your machine when you prepare it for shipping to clients), not when it is linked.
I found someone struggling with a similar issue here: https://flint.tools/blog/finding-a-weak-linking-solution.html
The good news is, that what you want to achieve is possible using weak linking and objective-C interoperability.
I'm working on a short article about the topic, in the meantime, here is an example repository with a working setup, similar to what you described as requirements:
https://github.com/amichnia/Swift-framework-with-optional-frameworks
It supports:
- AdditionalSDK is optional
- MainSDK have classes adopting AdditionalSDK's protocols
- MainSDK knows if additional features are available
- It is all in closed source setup
Update:
I finished an article, which should describe the solution in more details. It is available at https://medium.com/@amichnia_31596/create-a-mostly-swift-framework-with-optional-features-7e8a9ac960f9
Can't import dependency installed with Cocoapods
- Select your Project Target
- Go to Build Settings.
- Search for Header Search Paths.
- Add this value $(SRCROOT)/Pods with recursive, then Xcode will resolve the path for you.
#if canImport(module) still does not solve conditional import statement in Swift 4.1?
you need to include the called functionality of your IceCream framework also with that macro like
#if canImport(IceCream)
let iceCream = IceCream()
let text = iceCream.toString()
#else
// and now?
#endif
And you should think about the else code.
Why are iOS frameworks I'm linking as Optional being treated as required when my framework is imported elsewhere?
If you create your own framework which uses third party frameworks and you want to make those third party frameworks optional (but at the same time required only for some features of your framework) then I think you need to do few things.
First make sure that those third party frameworks that should be optional use -weak_framework
option for linking. It seems that you already did that. If you are adding those third party frameworks with cocoapods then you will probably need to add at the end of your Podfile script such as the one below because cocoapods tends to override those changes and reverts -weak_framework
to -framework
if you made that change manually.
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
xcconfig_path = config.base_configuration_reference.real_path
xcconfig = File.read(xcconfig_path)
xcconfig_mod = xcconfig.gsub(/-framework "ThirdPartyFrameworkName"/, "-weak_framework \"ThirdPartyFrameworkName\"")
File.open(xcconfig_path, "w") { |file| file << xcconfig_mod }
end
end
end
Second thing is that you will need to import this third party framework in your framework as implementation only framework and you can do this like below:
@_implementationOnly import ThirdPartyFrameworkName
Last thing is that in you code you will need to check if this third party framework is actually loaded so that your code will not crash in case when someone will not add this third party framework to his application. So the optional feature in your framework that uses third party framework should first check for example if given class of this external framework exists before using it like below:
if NSClassFromString("ClassNameFromThirdPartyFramework") == nil {
return // third party framework not available
}
// do something with ClassNameFromThirdPartyFramework here
If you perform all those steps it should work.
Related Topics
Add Uitapgesturerecognizer to Uitextview Without Blocking Textview Touches
How to Hide the Home Indicator with Swiftui
How to Create a PDF File Programmatically in an iOS Application
How to Use Afnetworking or Sthttprequest to Make a Request of a Soap Web Service
Stroke Width with a Scenekit Line Primitive Type
Facebooksdk(4.1.X) Custom Login UI Button - Swift(1.2)
Nspredicate for Array of Dictionaries
Why Must a Protocol Operator Be Implemented as a Global Function
Application Identifier Entitlement Value Has Changed
Set<Nsobject>' Does Not Have a Member Named 'Anyobject." - Xcode 6.3
Uibutton with Single Press and Long Press Events Swift
Load a .Tmx (Tiled Map) in Sprite Kit
Submitting iOS App to App Store Application Identifier Invalid
Error: Uitableview Jump to Top with Uitableviewautomaticdimension