In 2025, being an iOS developer feels like living in a golden age of convenience.
You discover a shiny new library, add a single line to your Package.swift
or Podfile
, and boom — it just works. Swift Package Manager (SPM) and CocoaPods are like magic spells: they download, compile, link, and configure everything behind the scenes.
But what happens when the magic runs out?
Imagine this: you stumble across the perfect library. It’s fast. It’s stable. It solves a problem that no Swift package comes close to. But there’s a catch — it isn’t on SPM, it isn’t a CocoaPod. It’s just a GitHub repo with a dusty folder of C/C++ source files.
Your first instinct? Panic.
Your second? Look for an alternative.
But what if there isn’t one?
This is where the “lost art” comes in. Manually integrating a native C/C++ library into your SwiftUI project isn’t just possible — it’s a superpower. By learning it, you gain access to an entire world of high-performance, battle-tested code that most Swift developers never touch.
This guide is your missing manual. Step by step, we’ll build a bridge between Swift and C, showing you every command, every file, and every setting along the way.
The Four-Phase Blueprint
Integrating a C/C++ library is not magic. It’s a methodical engineering process. Think of it like forging a weapon in a fantasy RPG — deliberate, precise, and powerful when done right.
Here’s our four-phase plan:
- Forge the Library — compile the C/C++ source into an
.xcframework
. - Organize the Project — add headers, frameworks, and bridging headers in Xcode.
- Configure Build Settings — teach Xcode how to find, link, and embed your library.
- Write Swift Code — finally call C functions from Swift and manage memory safely.
Let’s roll up our sleeves.
Phase 1: Forge the Library
Goal: Compile raw .c
/ .cpp
files into an .xcframework
that Xcode can consume.
Why an .xcframework
?
Because Xcode can’t just use random .c
files. It needs a binary package that works across all platforms — iOS, iPadOS, macOS, and even Simulator builds. An .xcframework
bundles all of this neatly.
Step 1: Clone the Source Code
# Make a workspace for open-source projects
mkdir -p ~/open-source
cd ~/open-source
# Replace with the actual repo URL
git clone https://github.com/some-author/your-library.git
cd your-library
Step 2: Run the Build Script
Most libraries that support iOS ship with a helper script. For example:
./build-ios.sh
This script does the heavy lifting: compiling for different architectures (ARM64 for iPhone, x86_64 for Simulator), packaging into an .xcframework
, and spitting out your prize:
YourLibrary.xcframework
Phase 2: Organize Your Project
A clean project is a happy project. Chaos here = hours of “file not found” errors later.
Step 1: Add the Framework
- In Xcode, create a new Frameworks group.
- Drag
YourLibrary.xcframework
into it. - Check Copy items if needed (critical!).
Now your project is self-contained — you can delete the cloned repo, and Xcode won’t break.
Step 2: Add the Header Files
Header files (.h
) are like dictionaries — they define the functions you’re allowed to use.
- Create an Include group.
- Inside, replicate the exact folder structure from the original library (important for
#include
paths). - Drag only the public
.h
files into your Include group.
If the library has your-library/include/api.h
, replicate that same folder structure.
Step 3: Create a Bridging Header
This is your translator — the single file that tells Swift which C functions it can see.
- Create a new header file in Xcode:
YourAppName-Bridging-Header.h - Add the main library header:
// YourAppName-Bridging-Header.h
#include “your-library/api.h”
Phase 3: Configure Build Settings
Now we teach Xcode how to actually use our new library.
Step 1: Embed the Framework
- Go to General > Frameworks, Libraries, and Embedded Content.
- Set
YourLibrary.xcframework
to Embed & Sign.
Without this, your app will crash at launch with library not found
.
Step 2: Link the C++ Standard Library (if needed)
If the library uses C++, link against libc++
:
- In Frameworks, Libraries, and Embedded Content, click
+
. - Search for
libc++.tbd
. - Add it.
Step 3: Set the Header Search Path
- Go to Build Settings.
- Search for
Header Search Paths
. - Add:
$(SRCROOT)/Include
(Make it recursive if needed.)
Step 4: Register the Bridging Header
- Search for
Objective-C Bridging Header
. - Set it to:
YourAppName/YourAppName-Bridging-Header.h
Phase 4: Write Swift Code
Finally — calling C functions in Swift.
Example 1: Calling a C Function
If the header has:
int calculate_sum(int a, int b);
You can just call it in Swift:
func doSomeMath() {
let result = calculate_sum(10, 20)
print("C library says: \(result)") // -> 30
}
Example 2: Managing Memory
Here’s the golden rule: Swift manages memory, C does not.
If a C function allocates memory, you must free it.
func workWithCLibrary() {
// CREATE
let obj = YourLibrary_create_object()
// USE
YourLibrary_process_data(obj)
// FREE
YourLibrary_free_object(obj)
}
Think of it as: CREATE → USE → FREE. Miss the last step, and you leak memory.
To sum it up
Congratulations — you’ve unlocked the “lost art” of integrating native libraries.
By mastering this process, you’re no longer limited to what’s on CocoaPods or SPM. You can reach into decades of high-performance, industrial-strength C/C++ code and bring it into SwiftUI.
This isn’t just a niche trick. It’s a superpower. It means you can pick the best tool for the job, regardless of language, package manager, or ecosystem.
You’ve gone beyond the magic. Welcome to the larger world of development.