I had just finished moving one of my wallpaper apps from CocoaPods to Swift Package Manager. The build was green, and the warnings were what I expected. I pressed Run on the simulator, the launch screen flashed for a moment, and I was dropped back on the home screen.
No crash dialog. No red line. Only when I opened the Xcode console did I find a single unfamiliar line:
dyld[1234]: Library not loaded: @rpath/AppLovinSDK.framework/AppLovinSDK
Referenced from: <...> /MyApp.app/MyApp
Reason: tried: '/usr/lib/system/introspection/AppLovinSDK.framework/AppLovinSDK' (no such file), ...
It compiled, yet something stopped it before it could even start. I want to write down how I read that line and what I changed, in case it saves someone else half a day.
How to recognize this failure
First, this is not a bug in your code. If all three of these are true, suspect this one:
- Build and link succeed
- The app dies at launch, before the first line of
AppDelegateruns - The only trace is a
dyldline in the console
In my setup, Crashlytics received nothing. That makes sense, since the process stops before any SDK is initialized. The quiet dashboard nearly convinced me nothing was wrong.
What was actually happening
Under CocoaPods, the Podfile decided how each SDK was brought in. With SPM, that decision splits into how the package is delivered and how the target is configured. This SDK ships as a dynamic framework, and a dynamic framework is found at launch only when two things hold:
- Its binary is embedded in the app's
Frameworksfolder - The runtime search path includes that folder
My project referenced the SDK only through an ad adapter package and never linked it directly from the app target. That indirect reference is the trap: the build passes, but the framework is left out of what gets embedded.
What I handed to Claude Code, and what I didn't
project.pbxproj runs to thousands of lines, and pasting all of it would waste context. I gave Claude Code just two things:
# Resolved dependencies (which packages, which products)
grep -n "productName" MyApp.xcodeproj/project.pbxproj
# The runtime search path setting
grep -n "LD_RUNPATH_SEARCH_PATHS" -A3 MyApp.xcodeproj/project.pbxprojAlong with the dyld line, I added: "Build succeeds, dies right before launch. I suspect dynamic framework embedding or the runpath." The answer pointed at two things: the SDK wasn't linked directly from the app target, and LD_RUNPATH_SEARCH_PATHS lacked @executable_path/Frameworks.
That matched my hunch, but having the order of checks laid out kept me moving. Claude Code only helped me decide where to look. The builds and the on-device checks stayed with me in Xcode.
The fix (Before / After)
Three places needed attention.
# 1. Link the SDK directly from the app target
- (referenced only indirectly, through the adapter)
+ Add AppLovin-MAX-Swift-Package under Package Dependencies, then add
+ AppLovinSDK to the target's Frameworks, Libraries (Embed & Sign)
# 2. Runpath Search Paths in Build Settings
- LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks" <- was missing
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );I added the direct dependency first and checked the search path second. Fixing the path alone does nothing if the framework was never embedded.
Verify it with your own eyes
"It launched, so it's fixed" isn't enough. Look inside the build product. Two lines are all it takes:
APP="$HOME/Library/Developer/Xcode/DerivedData/<project-hash>/Build/Products/Debug-iphonesimulator/MyApp.app"
ls "$APP/Frameworks" # is AppLovinSDK.framework listed?
otool -l "$APP/MyApp" | grep -A2 LC_RPATH # does @executable_path/Frameworks appear?If the binary is in Frameworks and LC_RPATH shows the path, the app can find it at launch. Only after seeing both did I relax.
If it still fails
| What you see | Where to look first |
|---|---|
Library not loaded now names a different framework | Is that framework also only referenced indirectly? |
The binary is in Frameworks but it still dies | Is LC_RPATH empty, or overridden by another value? |
| Works on the simulator, dies on a device | Signing and embed mode (Embed & Sign vs. Do Not Embed) |
| Stuck at dependency resolution | Run xcodebuild -resolvePackageDependencies first |
For me, this migration did not finish in one pass. I went around the build-and-fix loop about seven times. It helps to assume a single clean pass is unlikely.
The line I drew
My mistake was treating "the build passes" and "the app launches" as the same thing.
A green build is the doorway; launching is what finishes the job.
For this migration, I now call it done only after checking Frameworks and LC_RPATH in the built product, not when the build succeeds.
If you're about to do the same migration, try those two commands before your first run. If you can see the binary and the search path there, most of that lost half day should disappear.