0

I'm developing a framework which will be distributed via CocoaPods as .xcframework. The framework is depending on some third party libraries and using CocoaPods to resolve that dependencies. To support the module stability feature in my framework I set BUILD_LIBRARY_FOR_DISTRUBUTION option to YES in build settings of the framework project.

I know that if my module-stable framework using some dependencies I should set BUILD_LIBRARY_FOR_DISTRUBUTION=YES setting for each dependency used by the framework. I achieving this by adding post install script to Podfile in app where the framework is integrated. This script looks like this:

post_install do |installer|
  installer.pods_project.build_configurations.each do |config|
    config.build_settings["BUILD_LIBRARY_FOR_DISTRIBUTION"] = "YES"
  end
end

If I open some project that integrates my .xcframework via CocoaPods in Xcode with the same version that was used for the framework building (Xcode 12.5 in my case), everything will be fine on build and run. But if I try to build and run this project in Xcode with some other version (I tested it with Xcode 12.4), launched app will crash on startup with "dyld: Symbol not found..." error.

How to achieve true module stability for my framework even if it has some dependencies? And, if it possible, how to avoid forcing our clients to add post install script to their podfiles?

1 Answers1

2

I ended up using static linking for the third party libraries. If you use CocoaPods, just write:

use_frameworks! :linkage => :static

Then, in the swift files you'll need to avoid exporting the third party symbols by:

@_implementationOnly import Alamofire
Yonat
  • 4,382
  • 2
  • 28
  • 37
  • Thank you for your answer! I will try this today. – Антон Голополосов May 24 '21 at 09:26
  • It's a quite good workaround but the problem is integrator of my library may has the same dependency linked to his app as my framework uses (Realm for example). This will lead to runtime conflicts between different implementations of one class and will cause unpredictable behavior of an integrating app. – Антон Голополосов May 25 '21 at 08:44
  • 1
    With static linking each function call is resolved during build time and not at runtime. So you can have a version of Realm than the integrator, and your code will call your version while the integrator code will call his version. – Yonat May 25 '21 at 11:15
  • But if I install my .xcframework with statically linked dependencies to some test app project I will have warnings in my debug console for all intersecting dependencies like below: – Антон Голополосов May 26 '21 at 08:59
  • objc[52595]: Class RLMArray is implemented in both /Users/macbook/Library/Developer/CoreSimulator/Devices/9B109861-975D-4A11-BDF7-37AC6A910345/data/Containers/Bundle/Application/6F3687B2-79D0-1CCC-BBCE-6C02D753C032/SomeTestApp.app/Frameworks/Realm.framework/Realm (0x104896280) and /Users/macbook/Library/Developer/CoreSimulator/Devices/9B109861-975D-4A11-BDF7-37AC6A910345/data/Containers/Bundle/Application/6F3687B2-79D0-1CCC-BBCE-6C02D753C032/SomeTestApp.app/Frameworks/MyFramework.framework/MyFramework (0x1035fd1e8). One of the two will be used. Which one is undefined. – Антон Голополосов May 26 '21 at 08:59
  • 1
    Yes, I wasn't able to solve that, and it seems others have the same problem: see for example https://stackoverflow.com/questions/46932341/class-is-implemented-in-both-one-of-the-two-will-be-used-which-one-is-undefine and https://stackoverflow.com/questions/30581884/class-is-implemented-in-both-one-of-the-two-will-be-used – Yonat May 26 '21 at 11:13