#If Canimport() Does Not Find Frameworks with Cocoapods

#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

  1. Select your Project Target
  2. Go to Build Settings.
  3. Search for Header Search Paths.
  4. Add this value $(SRCROOT)/Pods with recursive, then Xcode will resolve the path for you.

Sample Image

#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



Leave a reply



Submit