7

Hello here is our Podspec which has a default_subspec and an optional subspec (which won't be taken since the default is already set). That subspec has more features, but takes an additional 8MB of size...

`s.default_subspec = 'mainSDK'

s.subspec 'mainSDK' do |mainSDK|
mainSDK.vendored_frameworks = 'mainSDK.framework'
mainSDK.source_files = "mainSDK.framework/Headers/*.h"
end

s.subspec 'additionalSDK' do |additionalSDK|
additionalSDK.source_files = "additionalSDK.framework/Headers/*.h"
additionalSDK.vendored_frameworks =['additionalSDK.framework', 'mainSDK.framework']
end

Now, in our mainSDK we include additionalSDK with #if canImport(additionalSDK) We then provide code related to additionalSDK in between those compiler flags, like this:

#if canImport(additionalSDK)
    //adding optional delegate
    class ViewController: UIViewController, OptionalDelagate
#else
    //no need for delagete
    class ViewController: UIViewController
#endif

However, after client integrates our mainSDK he sees that this framework is missing module: additionalSDK.framework

How is this possible? We have marked additionalSDK as optional in our workspace. We have tried to set additionalSDK as a -weak_framework in other linker flags(Build settings) , but this did not helped.

If client integrates additionalSDK everything works well, because all frameworks are linked..

Optional dependencies, without CocoaPods work well, it is just problem of CocoaPods or I don't know how to configure it

s.platform = :ios
s.ios.deployment_target = '9.0'
s.name = "mainSDK"
s.summary = "mainSDK IOS SDK"
s.requires_arc = true

# 2
s.version = "1.0.8.6.5"

s.source = { :http => "https://s3-eu-west-1.amazonaws.com/zipOfSDK.zip"}
s.framework = "UIKit"

s.source_files = "mainSDK.framework/Headers/*.h"

s.default_subspec = 'mainSDK'

s.subspec 'mainSDK' do |mainSDK|
mainSDK.vendored_frameworks = 'mainSDK.framework'
mainSDK.source_files = "mainSDK.framework/Headers/*.h"
end

s.subspec 'additionalSDK' do |additionalSDK|
additionalSDK.source_files = "additionalSDK.framework/Headers/*.h"
additionalSDK.vendored_frameworks =['additionalSDK.framework', 'mainSDK.framework']
end

s.swift_version = "4.2"

end
denis_lor
  • 6,212
  • 4
  • 31
  • 55
Viktor Vostrikov
  • 1,322
  • 3
  • 19
  • 36
  • Is the additionalSDK.framework your framework (so do you have control over it?). Or is it a 3rd party dependency? – Andrzej Michnia Mar 28 '19 at 09:53
  • And one more question, is the additionalSDK.framewrk a standalone sdk? So, do you ever use it without mainSDK.framework? – Andrzej Michnia Mar 28 '19 at 10:13
  • @AndrzejMichnia I have answered in the email! I could update this post with your information or you can .do it too yourself :) I am sure you will get many upvotes :) I could start a bounty too – Viktor Vostrikov Mar 28 '19 at 14:54

2 Answers2

7

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

Andrzej Michnia
  • 538
  • 3
  • 9
  • Wow, sorry for not responding to you, was still double checking all your answers :D Will reply soon – Viktor Vostrikov Apr 07 '19 at 15:46
  • Has someone managed to get this working with Bitcode (https://stackoverflow.com/questions/58740662)? Edit: I think I figured it out in Objective-C after reading https://flint.tools/blog/finding-a-weak-linking-solution.html. In my case I had to use NSClassFromString instead of directly calling e.g. [AdditonalSDK class] or e.g. [PrimeNumberChecker alloc]. – Sebastian Kirsche Apr 06 '22 at 19:22
1

Can't achieve that by saying that mainSDK is MainTarget and additionalSDK is your AdditionalTarget? What I see is that whatever version you want differently it will be just another target. You can right-click on the original target, select duplicate from the current target and after it you can make the changes you wish to linking frameworks within the Build Phases section.

#check1: check you have use_frameworks! uncommented like this:

# Uncomment this line if you're using Swift
use_frameworks!

#check2: try to delete the ModuleCache if you really think the Framework is there and in the right path. To delete ModuleCache just delete ~/Library/Developer/Xcode/DerivedData/ModuleCache directory, clean the project and delete project-specific derived data just to be sure. When you do the normal cleanup, the ModuleCache directory usually doesn't get rebuilt.

#check3: inspect your framework to see if it contains a Modules folder with a module.modulemap file inside it (right click on your framework > Show In Finder > make sure your modulemap is there)

denis_lor
  • 6,212
  • 4
  • 31
  • 55
  • Yes, I have two targets(both are frameworks in workscpace). If I try to link additionalSDK to the mainSDK as an optional framework, and declare it as a weak_framework in other linker flags. Cocoapods still say that additionalSDK is required module and must be implemented... I could share you our pod in private. Can you create a chat for us? – Viktor Vostrikov Mar 19 '19 at 05:47
  • The room as far as I know can be private but means that anyone can enter only approved user can talk. So I guess won't be helpful if you want to share something publicly. Let me know. In any case would be helpful to see the error you are seeing as to be more aware on how the error is appearing. And also can you post the pod file without the real pods, just put there 2-3 fake pods in case you don't want to share that info. – denis_lor Mar 19 '19 at 07:40
  • 1
    We could chat privately, and then you could post response here, I will comment and it will be useful for others :) I am adding full podspec. I have seen you suggestions, but here is my answers: 1. Did already 2. cleared cache 3. yes it contains, with all supported architectures What I did found is that, then you import our SDK and double click on it, Xcode will show all dependencies and somehow optional dependencies **are provided in the top** – Viktor Vostrikov Mar 19 '19 at 10:38
  • Have you tried to remove `s.source_files` or comment it out? – denis_lor Mar 19 '19 at 15:09
  • yes, I have.. no results. may I send you our pod name, you could check it. Create a private chat :) – Viktor Vostrikov Mar 19 '19 at 19:09