How to create XCFramework for closed source CocoaPod when it has dependencies on other pods
Asked Answered
T

2

5

I am looking to create a closed source CocoaPod. From my research the recommendation seems to be to distribute it as an XCFramework. (source) It seems it should also be possible to make your framework dependent upon other CocoaPods by specifying them in your Podspec file. (source) (source) That will ensure when someone adds this pod to their Podfile and runs pod install, it will install this framework and its dependencies.

I have created a framework Xcode project and have been developing it inside our app's workspace as a subproject. So at this time, the app has all of the dependencies installed via CocoaPods, which allows the framework in it to utilize them. Now I am ready to prepare the framework for distribution so it can be used in other apps.

From what I understand, I need to create an XCFramework first and then can create a CocoaPod for it. When I go to archive the framework project, I get an error because it cannot find the dependencies, which makes sense. At this point I don't understand how this is supposed to work, because it seems the framework needs the dependencies included in itself in order to successfully create the XCFramework, but I anticipated from my research this would be handled by CocoaPods and not included in the framework itself.

xcodebuild archive \
-scheme MyFramework \
-configuration Release \
-destination 'generic/platform=iOS' \
-archivePath './build/MyFramework.framework-iphoneos.xcarchive' \
SKIP_INSTALL=NO \
BUILD_LIBRARIES_FOR_DISTRIBUTION=YES
/Users/.../AppName/MyFramework/Helpers/Extensions.swift:10:8: error: no such module 'Kingfisher'
import Kingfisher
       ^

** ARCHIVE FAILED **
Throwaway answered 11/10, 2021 at 17:38 Comment(0)
T
7

To resolve this, what I did is create a Podfile for the framework project and run pod install so it has its own workspace. I verified I was able to successfully build the framework in Xcode when opening that workspace. Then to create the archive, specify it should build the workspace rather than the project like so:

xcodebuild archive \
-workspace MyFramework.xcworkspace \
-scheme MyFramework \
-configuration Release \
-destination 'generic/platform=iOS' \
-archivePath './build/MyFramework.framework-iphoneos.xcarchive' \
SKIP_INSTALL=NO \
BUILD_LIBRARIES_FOR_DISTRIBUTION=YES

From what I understand, when you create the XCFramework, the dependencies won't be included it will only be your own framework. However the dependencies have to be accessible in order to successfully build the archive.

This understanding resolves the confusion I had when asking this question. Now I can proceed to create a CocoaPod for my XCFramework and specify its dependencies in the Podspec file.

Throwaway answered 12/10, 2021 at 19:41 Comment(1)
Correct. Suppose Foo depends on Bar and Baz frameworks. Before you archive, you have to build a target. And because Foo depends on Bar and Baz Frameworks, then the compiler needs to makes sure that you can actually fulfill that promise. The only way to validate is if you install the dependencies using a project with a Podfile. Also correct that, while Foo has lines that call functions from Bar, Baz, your Foo.framework is a just a binary of Foo, it won't include Bar,Baz frameworks. The final app that installs Foo, will then link (the pulled and installed) Bar, Baz frameworks...Taub
T
0

Jordan's answer is correct.

Suppose Foo depends on Bar and Baz frameworks. Before you archive, you have to build a target. And because Foo depends on Bar and Baz Frameworks, then the compiler needs to makes sure that you can actually fulfill that promise.

There are two ways to build your pod alongs it dependencies

Build and Archive it using a Example app that uses a Podfile

Set your scheme to the Example app and perform archive

You install the dependencies using a project with a Podfile. Jordan is also correct that, while Foo has lines that call functions from Bar, Baz, the Foo framework is a just a binary of Foo, it won't include Bar, Baz frameworks. The final app that installs Foo, will then link (pull and install) Bar, Baz frameworks...

Beware: If you're using the Podfile and the Podfile has included some post install hook to change build settings, then obviously your build will be impacted by them.

Build the framework directly without a Podfile

Set your scheme to the pod's scheme, not the example app and archive that.

The archive is just a compressed form of the build. The build will include all dependencies.

FWIW you can invoke/create archives either from command line tool or from Xcode, however it's better to do it from command line tool, so you have a more explicit control over the flags passed to xcodebuild.

To create a framework, you only use your desired framework within the archives.

When you do:

xcodebuild -create-xcframework \
    -framework "archives/StarWarsKit-iOS.xcarchive/Products/Library/Frameworks/StarWarsKit.framework" \
    -framework "archives/StarWarsKit-iOS-simulator.xcarchive/Products/Library/Frameworks/StarWarsKit.framework" \
    -output "StarWarsKit.xcframework"

You're doing two important things:

  • passing archives from both (iOS & iOS-simulator) platforms
  • From all frameworks within the archive's /Products/Library/Frameworks you're only attempting to create an xcframework for StarWarsKit. You're not creating an xcframework for other frameworks in the workspace. All others are libraries get excluded — if the dependencies of StarWarsKit are dynamically linked. However the dependencies may become part of the binary if they're linked statically, i.e. they get absorbed and linked into the final product/binary of StarWarsKit.

With some oversimplification, Xcode's build process works a bit like this:

  • build whatever it is along with all its dependencies. (If you don't build the dependencies then I can't know if it can actually compile)
  • Archive all the build with all other dependencies
  • Extract only the product you need. Don't include any other external depdency.
Taub answered 28/2, 2023 at 7:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.