Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are iOS frameworks I'm linking as Optional being treated as required when my framework is imported elsewhere?

I'm trying to add a feature to an existing iOS framework published by my company. The new feature requires that we make use of a number of other, third party-supplied frameworks. We want to ensure that our customers are not required to deploy those frameworks if they do not want to activate the new feature.

I've configured each of these frameworks as Optional when I reference them in the Target / General / Linked Frameworks and Libraries section of my own framework. I also mark them as Optional in the Target / Build Phases / Link Binary With Libraries section of my framework. I'm expecting that this will mean my framework can be imported in an xcodebuild when those frameworks are not present.

This works on the machine where I build my framework, but as soon as anyone else tries to import my new framework their Xcode objects to the import statement with a message "Missing required module 'x'" (where x is the top level third party framework that my framework imports).

I tried removing them and adding linker directives of the form "-weak_framework {name}" to the build, but I can see from the xcodebuild log that the Optional settings simply generate these anyway, and more conveniently.

My framework uses Swift 5, in case it's relevant.

What am I missing?

Many thanks for any clues.

like image 398
xinxilanren Avatar asked Nov 06 '22 18:11

xinxilanren


1 Answers

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.

like image 87
Leszek Szary Avatar answered Dec 28 '22 16:12

Leszek Szary