This might be an Xcode issue (I have reported feedback) but just want to make sure I am not doing something obviously wrong in my Package.swift file. I have a project with a local package that depends on a binary target (OpenCV).
A stripped down repro looks like this:
// swift-tools-version: 5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Experiment",
platforms: [.iOS(.v17)],
products: [
// Products define the executables and libraries a package produces, making them visible to other packages.
.library(
name: "Experiment",
targets: ["Experiment"]),
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.target(
name: "Experiment",
dependencies: ["opencv2"]),
.binaryTarget(name: "opencv2",
url: "<some-server>/opencv2.xcframework.zip?raw=1",
checksum: "<checksum>"),
.testTarget(
name: "ExperimentTests",
dependencies: ["Experiment"]),
]
)
The app builds and runs fine with Xcode 15.2 and earlier. In Xcode 15.3, I get an error when it tries to install the app (simulator or device) relating to the OpenCV.xcframework's Info.plist.
Failed to load Info.plist from bundle at path /Users/rayfix/Library/Developer/CoreSimulator/Devices/2F5E4E52-C9F2-47AD-973F-37653A8173FD/data/Library/Caches/com.apple.mobile.installd.staging/temp.fQ0GZz/extracted/ReproProblem.app/Frameworks/opencv2.framework;
There is, of course, an Info.plist in the binary target's xcframework but it is not getting copied to this extraction directory apparently.
Any ideas of things I might try to get things building, installing and running again. Could there be an error in the Info.plist itself that is causing it?
Sure. It would be great if you could give it a quick look. (Just so you know, I also posted a TSI about it, but I will also post the results here if I am able to solve it.)
I cobbled this xcframework build together last year (after you and others helped me out). It was working great until Xcode 15.3
Hi Ray, I had a binary framework that was working with Xcode 15.2 but not Xcode 15.3. In the end it was because as of 15.3 you need to code sign your .xcframework at the top level now as outlined in this article: Embedding a privacy manifest into an XCFramework – Rhonabwy. Privacy manifests are not required as yet but I imagine they will be before too long. For me for Xcode 15.3 the main thing was to sign the .xcframework itself, not just its contents.
The thing that immediately jumps out is that your XCFramework has component frameworks that target iOS but which use the macOS-style ‘deep’ framework format. Consider this:
In an iOS-style framework, there is no Versions directory and all those top-level symlinks are replaced by the real items. Placing Content in a Bundle explains that structure in more detail.
I recommend that you fix this and retest.
Honestly, I’m surprised this ever worked (-:
ps If you’re building an XCFramework that supports macOS and other platforms, you’ll end up with different structures in the component frameworks. Use the macOS structure in your macOS framework and the iOS structure in all the others.
We had the opposite problem. We had been using the simpler iOS style framework structure for macOS and Catalyst. It worked fine until Xcode 15.3 which forced us to switch to the 'deep' framework format (and address several knock-on issues for internal and external tooling that did not properly support symlinks).
If you put content in the wrong location, you may encounter hard-to-debug code signing and distribution problems. These problems aren’t always immediately obvious.
It would be nice if Apple’s tooling has a single coherent way to check whether a bundle structure is valid. Sadly, that’s not the case )-:
Thanks for the great information. I learned a lot about bundles and frameworks. Turns out OpenCV recently added --dynamic flag when you build that appears to produce the correct bundle structure required by iOS. For anyone struggling with this you can see this thread here: