Skip to content
useffect.sh
Book 30 min with a senior
Native

XCFramework

Apple’s format for shipping a multi-platform binary framework (device, simulator, macOS) in one bundle; React Native ships its precompiled core in it.

Definition

An XCFramework is Apple’s bundle format for distributing an already-compiled framework or library for several platforms and architectures at once: iOS on device (arm64), iOS simulator (arm64 and x86_64), macOS, tvOS, visionOS. Each combination gets its own slice in the bundle, and Xcode picks the right one at build time. It replaces the “fat frameworks” assembled with lipo, which cannot hold a device slice and a simulator slice when both are arm64, which has been the case since Apple Silicon Macs. You create one with xcodebuild -create-xcframework from the frameworks or static libraries of each platform. For React Native, it is the format of the precompiled binaries: since 0.84, the core (ReactNativeCore) and its dependencies are downloaded as .xcframework during pod install instead of being compiled from source. You meet it in a third-party SDK shipped as a binary, in the Pods folder of a recent project, or while reading a linker error.

In a real app

In an up-to-date React Native project, ls ios/Pods shows .xcframework bundles for React Native, its third-party dependencies (boost, folly, glog, fmt), and Hermes; RCT_USE_PREBUILT_RNCORE=0 bundle exec pod install forces a return to source, useful for debugging inside core or applying a patch. With SwiftPM, the same XCFrameworks are consumed, plus two header-only bundles (ReactNativeHeaders, ReactNativeDependenciesHeaders) introduced in 0.87.

Typical errors show up at link time: “building for iOS Simulator, but linking in object file built for iOS” means a binary without an arm64 simulator slice, common with an old third-party SDK; the fix is an updated SDK, not the EXCLUDED_ARCHS=arm64 workaround that condemns you to a Rosetta simulator. A publisher-signed XCFramework can also fail signature verification if Xcode is configured to require it.

For an in-house library shipped as a binary, the question to ask is version compatibility: a Swift XCFramework built without library evolution (BUILD_LIBRARY_FOR_DISTRIBUTION) only works with the exact compiler version that produced it, and an XCFramework compiled against one React Native version does not necessarily link with the next. That is why core binaries are published per exact version and downloaded from the React Native Maven mirror, with Maven Central as fallback.

Sources

All 35 glossary terms

One of these is blocking your app?

30 minutes with a senior to look at the problem in your code. Free.