Swift package with dynamic libraries leads to app store validation error

Hello all,

I have a confounding problem. I have built a swift package from an C++ library that uses a mix of static and dynamic libraries. The binaries have been wrapped in in individual xcframework frameworsk using xcodebuild -create-xcframework -library <....>.

Seemingly everything was working fine, no errors reported in XCode, the app builds to the device, and can be deployed through our CI with ad-hoc distribution. Building an archive works, and the local validation passes.

But when we came to submitting our app to the app store, appstoreconnect refuses the binary with the message ITMS-90426: Invalid Swift Support - The SwiftSupport folder is missing. Rebuild your app using the current public (GM) version of Xcode and resubmit it.

No matter what tricks I do, I can not get this missing folder to generate.

That package consists of 2 static libraries, which in turn, depend on 3 dynamic libraries, there's an additional target for obj-c bridging code, one for some swift helpers on top, and a resources package.

The issues seems to be that the dylibs are not properly embedding. I've separated out the dylibs into a separate sub library product, and I'm trying to set the type of the product to .dynamic.
Issue 1 is that it will not let me specify the type if the targets are only binaries, xcode seem to think it will properly detect the type of the library and act accordingly, apparently it does not and just treats them as static libraries.

I can add a dummy target with just 1 source file to the library product, and then I can specify the type as .dynamic, then in my xcode project for the app, I am given the option to embed the library. That doesn't seem to be any use though, as despite an additional .framework folder for the library in the Frameworks folder of the archive, there is no SwiftSupport folder, and the dylibs are still placed in the root of Frameworks (Not in the created .framework folder)

I'm a bit confused as to the requirement of the SwiftSupport library, if it is required, how come our app has been building successfully already, and it is only app store connect rejecting it?

Why does XCode treat a package containing only dylibs as a static package (no option to embedd)?

If I trick it into actually treating it as a dynamic library, why aren't the dylibs in the created .framework folder?

This library is actually pretty important to us, it's a core tool we use across the business and it took quite some work to just get it built for ios, and it's frustrating to find, even though we thought we had the problems solved, it gets rejected at the last hurdle.

Any hints on what to do? I'm starting to guess I need to add an additional build phase to do something.

I followed the instructions here and created a project for an xcframework for each dynamic library (some of the instructions were just ever so slightly wrong) Creating a multiplatform binary framework bundle | Apple Developer Documentation
Now it looks like the dylibs are being placed in separate Framework folders for each target in the build directory, but now my obj-c bridging target can not find the symbols in it's dylib dependencies

Not entirely sure if that's the only issue you're facing here, but the App Store does not support dylibs, only frameworks.

Does that mean that dylibs must be packaged in xcframeworks in a specific way? Or that frameworks must not contain dylibs? The documentations seems unclear to me, the docs for creating the framework clearly reference dynamic and static libraries, and is built for iOS, but OTH, the commands were ever so slightly wrong.

I could get 1 of the dylibs packaged and the app was still working, and in the archive of the app, the dylib had moved from the root of Frameworks to Frameworks/myLib.framework/Frameworks

From the doc : Avoid using dynamic library files (.dylib files) for dynamic linking. An XCFramework can include dynamic library files, but only macOS supports these libraries for dynamic linking. Dynamic linking on iOS, watchOS, and tvOS requires the XCFramework to contain .framework bundles.

Perhaps I'm not understanding this. The generated xcframeworks do contain the .framework bundle,
eg:

jpeg.xcframework
β”œβ”€β”€ Info.plist
β”œβ”€β”€ ios-arm64
β”‚   └── jpeg.framework
β”‚       β”œβ”€β”€ Frameworks
β”‚       β”‚   └── libjpeg.8.dylib
β”‚       β”œβ”€β”€ Info.plist
β”‚       β”œβ”€β”€ _CodeSignature
β”‚       β”‚   └── CodeResources
β”‚       └── jpeg
└── ios-arm64-simulator
    └── jpeg.framework
        β”œβ”€β”€ Frameworks
        β”‚   └── libjpeg.8.dylib
        β”œβ”€β”€ Info.plist
        β”œβ”€β”€ _CodeSignature
        β”‚   └── CodeResources
        └── jpeg

Ah I see, that wasn't clear to me from your earlier posts, I thought you were saying you had packaged loose dylibs in your XCFramework. The way you have organized it looks like it should work from that perspective. Sorry for the confusion.

1 Like

To be fair, that is what I had done originally. It was only on very close reading of the docs I realised my mistake.

However the docs seem to have some omissions or are out of date, with some tinkering of build settings of my xcframework I've got a step closer to my goal, I think.

Particularly, the Runpath Search Paths seemed to assume the dylibs are in the root of the Frameworks folder, adding an extra search path to the Frameworks folder of the .framework bundle has fixed the missing symbols in the package itself. But I'm still getting missing symbols when the package is included in an app and run on a device (but on simulator works, it works).

Now on submission to the app store I get
Invalid Bundle. The bundle at '<REDACTED>.app/Frameworks/<REDACTED>.framework' contains disallowed file 'Frameworks'. (ID: a0ba908a-4adb-4a33-96a4-65551db7b5e4)

I guess I have to place the dylibs at the root of the .framework, I'll try it tomorrow

Yah, I believe nested frameworks are also not supported by the App Store.

I trying to put the dylib in the root of the .framework but nothing seems to work.

If I embed them, it puts them to the Frameworks folder in the .framework, so I tried adding .. as the subpath, this places the dylibs in the root of the .framework.

But then when I build the package, the linking fails as it cannot find @rpath/libexample.dylib from the library it creates for the xcframework
I add all sorts of paths to the Runpath Search Paths settings, but no combination works
eg
@executable_path/libexample.framework
@executable_path/Frameworks/libexample.framework
@executable_path
And the same with @loader_path nothing works.

Instead of embedding, I also tried importing them in the copy bundle resources phase, same result.
It's very frustrating.

Weirdly, in the log for the linker error, the only thing I can see for -rpath is @loader_path/Frameworks and @loader_path/../Frameworks. I tried removing all the @loader_path to see if it picked up another but it's always reporting that, so I think this is being set somewhere else.

It just doesn't seem possible with dylibs. Someone managed to get the build system to spit out a framework.

1 Like

Just FYI, we have pretty decent documentation about which platforms support what when it comes to nested code. See Placing Content in a Bundle.

Now, how you get Swift PM to build code that follows those rules, that’s outside of my area of expertise )-:

Share and Enjoy

Quinn β€œThe Eskimo!” @ DTS @ Apple

@valentary Hello! We're facing a similar challenge with the "Invalid Swift Support" error while uploading our embedded C++ library. We're considering converting it into a Framework rather than a library. Could you share your experience and solutions for resolving this issue? Thank you very much!

We use Conan internally, and I had some trouble with dependencies of dependencies not receiving the config to build frameworks from higher up, but we got it to work eventually. I'm not sure what you use but Conan does have support for it
I'm really not sure what the functional difference is between a dylib and a framework other than the extension