Why this happens
When developing for iOS, iPadOS, or macOS, your code frequently relies on APIs provided outside your target’s compiled source files. While modern Swift often automatically resolves system frameworks through module imports (import StoreKit, import CoreLocation), older codebases, Objective-C targets, C/C++ libraries, and third-party .xcframework distributions require explicit linking.
Historically, Xcode allowed developers to right-click a project group and choose “Add Existing Frameworks.” Modern versions of Xcode migrated framework management into target configuration settings, dividing responsibilities between compile-time linking (pointing the Mach-O linker to the symbol tables) and runtime embedding (copying dynamic libraries into the application bundle’s Frameworks directory).
Failing to link a framework leads to compile-time linker errors such as Undefined symbols for architecture arm64. Conversely, misconfiguring the embedding options can trigger App Store upload rejections or dyld crash loops like Library not loaded ... Reason: image not found at launch.
How to fix it
1. Add via the Target General Tab
The General tab provides the primary interface for managing dependencies, handling both linking and embedding settings simultaneously.
- Open your project in Xcode.
- In the Project Navigator (
Cmd + 1), click the top-level project file. - Under the Targets list in the main editor area, select your app or extension target.
- Stay on the General tab and scroll down to the Frameworks, Libraries, and Embedded Content section.
- Click the + (plus) button at the bottom of the list.
- Search for your framework (for example,
AudioToolbox.frameworkorStoreKit.framework), select it, and click Add. - Adjust the Embed column:
– Set to Do Not Embed for all Apple system frameworks.
– Set to Embed & Sign for dynamic third-party.xcframeworkor.frameworkpackages.
– Set to Do Not Embed for static libraries (.a) or static XCFrameworks.
2. Link Directly in Build Phases
If you only need to link symbols at build time without altering package bundle embedding, manage the binary directly in the build pipeline:
- Select your target in the project editor.
- Click the Build Phases tab.
- Expand the Link Binary With Libraries section.
- Click the + button.
- Choose an Apple SDK framework, or click Add Other… at the bottom of the sheet to select a custom framework file from your disk via Add Files….
- In the Status column, leave the value as Required unless your app must run on older OS versions that lack this framework, in which case change it to Optional (weak linking).
3. Drag and Drop Custom XCFrameworks into the Project Navigator
For third-party SDKs distributed as .xcframework bundles:
- Drag the
.xcframeworkfolder from Finder directly into the Project Navigator pane under your project files. - In the dialog that appears, check Copy items if needed.
- Under Add to targets, ensure your target is checked, then click Finish.
- Return to the target’s General tab under Frameworks, Libraries, and Embedded Content.
- Confirm that Xcode added the framework and correctly set its embed status.
// Verify the framework links cleanly by importing and calling an API
import StoreKit
func checkStoreAvailability() async {
let canMakePayments = AppStore.canMakePayments
print("Payments enabled: \(canMakePayments)")
}
How to prevent it
- Prefer Swift Package Manager (SPM) over manual framework linking whenever dependencies support it.
- Never choose Embed & Sign for standard Apple system frameworks, as system libraries reside in the OS shared cache and will cause App Store validation errors if embedded.
- Set weak linking to Optional in Link Binary With Libraries whenever you reference symbols that are only available on newer OS deployment targets.
- If using custom binary frameworks, always distribute them as
.xcframeworkrather than legacy.frameworkbundles to avoid arm64 simulator architecture collisions.
FAQ
Why do I get a dyld crash at launch after adding my framework?
This happens when a third-party dynamic framework is linked under Build Phases but not embedded. Go to your target’s General tab and change the framework’s embed setting to Embed & Sign so the binary is copied into the application bundle.
What is the difference between Required and Optional linking?
Required linking causes the app to terminate on launch if the dynamic framework cannot be found by dyld. Optional (weak) linking allows the app to launch even if the library is missing on older operating systems, allowing you to check API availability at runtime.
Why does App Store Connect reject my binary with an embedded system framework error?
Apple system frameworks are part of iOS and macOS and must never be packaged inside your app bundle. In your target’s Frameworks, Libraries, and Embedded Content section, change the embed dropdown next to any system framework to Do Not Embed.
Parts of this guide are adapted from content licensed under CC BY-SA 4.0; this article is shared under the same license.
