We are developing 8 SDKs, which are to be shared as XCFrameworks. The SDKs are interdependent on each other and also we have dependency on third party XCFrameworks which they have shared as Cocoapods.
Below is a simple demo of how the dependency graph looks, (@Apple - image attachment will be very helpful here)
A -> B, C
B -> D, E, F
C -> G, H
D, E, F -> H
H -> I, J
I -> K
here G and J are third party XCFrameworks. K is a third party FAT framework, written completely in Objective C. other letters denote the SDKs we are writing fully in Swift with Objective-C compatibility.
You can read the first line as A is dependent on B and C.
We started developing the SDKs by adding all these as Development Pods to a sample iOS Client. The only issue we faced was that even a small change in any of the pods required to clean build the entire project. We got around this setting "Legacy Build System" in Workspace settings.
When we approached release, we generated XCFrameworks and tried adding them to the Client.
We faced the following issue in almost all our frameworks. Because we had class names matching the SDK names, just like the old FAT framework.
‘FrameworkName’ is not a member type of ‘FrameworkName’ errors inside swiftinterface - https://forums.swift.org/t/frameworkname-is-not-a-member-type-of-frameworkname-errors-inside-swiftinterface/28962
Then we renamed all the frameworks and got struck with the following issue.
XCFramework requires to target iOS 13 for inter-framework dependencies with Objective-C compatibility - https://forums.swift.org/t/xcframework-requires-to-target-ios-13-for-inter-framework-dependencies-with-objective-c-compatibility-tested-with-xcode-11-beta-7/28539
We are supporting from iOS 9. So moving to iOS 13 is not even an option. We were not able to find the exact cause of this issue for so long even after exploring the generated .swiftinterface file which was throwing these issues. We found that issue could be because of using inheritance in the following way.
X is a Swift class, made Objective C compatible by inheriting NSObject. When we have another class Y from any of the other SDKs, inheriting X like below, this issue will be thrown.
For example, we have in Framework H.
@objc class X: NSObject { }
and then in framework D, which depends on H, we have
class Y: X { }
We removed it in one place and the issue resolved. We had this pattern all over the eight SDKs and we removed all those.
Then when we tried to build, we ran into the following issue.
'@objc' instance method in extension of subclass requires iOS 13.0.0.
We moved all @objc extension methods to the class. Those were mostly delegates and data source methods from common UIKit classes.
After facing these issues with XCFrameworks in the Client app, we decided to remove the development pod setup and manually drag and drop the xcodeproj files of all the SDKs into the Client app. Also we had to manually add the third party frameworks.
This way, some of the above issues can be identified during development instead of release time.
Now, the situation is that, when we make changes to any of the SDKs, it will be not be reflected unless we do a clean build, which takes a lot of time and is not desirable.
Even then, in some cases, the client app just throws Unable to import D or any other framework, in which we have made some changes. Then we to select that framework in the scheme, build it once and then select on to the Client App and build it again to see the change in our app.
This workflow is cumbersome and painful in the long run. Kindly suggest better alternative setups for developing multiple XCFrameworks.
Our next problem is when generating XCFrameworks, we need each SDK to use the XCFramework of the other dependent SDKs. For this, we have to work our way from the bottom most framework. Generate it, add to the one above it and then move on to the next.
This also feels like a burden in the long run. We seriously hope there are better ways to do it. Kindly suggest those.
We have not used Swift Package Manager (SPM) because most of our customers use Cocoapods for dependency management and the remaing few just drag the frameworks manually into their projects.
If SPM can act as a magic pill and solve all these issues at once, then we can consider using it.