Late last year I needed in-app purchases in a Godot 4 project and found nothing that covered both stores: an old Play Billing version on Android, unmaintained iOS plugins, and the “Frustrating state of Godot mobile IAPs” thread here still unresolved a year after it was posted.
I already maintain IAP libraries for React Native, Flutter and KMP, all built on a spec called OpenIAP — one schema, generated bindings, shared StoreKit 2 / Play Billing layer. So adding Godot was mostly generated GDScript types plus a Swift GDExtension. godot-iap shipped January 1st, MIT — Asset Library.
Eight months on there have been issues and discussions from people using it, which I’m grateful for. But the Asset Library doesn’t publish download counts the way npm or pub.dev do, so I have no real sense of how many of you there are or how it’s holding up in actual projects — hence the question. If you’ve tried it, I’d love to hear how it went: what worked, where it fought you, anything you ended up working around. Even a one-liner would help.
And if you shipped a game with it, the OpenIAP showcase has no Godot entry yet — I’d be happy to add yours.
Hey @hyochan. I am working on my first Godot game and I am trying to use godot-iap for cross-platform IAP. I have it working for Android, but for iOS I believe the SwiftGodotRuntime.framework is in conflict with another native iOS plugin I am using for GameCenter achievements, GodotApplePlugins. I have tried removing their SwiftGodotRuntime.framework and using just the one with godot-iap, but that causes the app to crash on device (I followed all other install steps like running the fix_ios_embed.sh script). I have tried other things as well, but I cannot seem to get godot-iap to work on iOS. Any ideas?
Thanks for the report, and sorry it bit you on device.
I haven’t reproduced it yet, so I won’t guess at the cause. What I can narrow by measurement: our shipped iOS SwiftGodotRuntime carries the same install name as the one GodotApplePlugins depends on, @rpath/SwiftGodotRuntime.framework/SwiftGodotRuntime, and its exported symbols are identical to upstream SwiftGodot v0.79.0’s XCFramework — same 43,641 symbols, only the build UUID differs. GodotApplePlugins pins SwiftGodotBinary at v0.79.0 as well, though I haven’t measured their binary directly. So an ABI mismatch between the two runtimes looks unlikely.
Removing one copy didn’t isolate the crash, so unfortunately that attempt doesn’t tell us much either way.
What would settle it: the crash report from Xcode’s Organizer — the exception type, and the Binary Images lines mentioning SwiftGodotRuntime, with UUIDs. And one thing that may matter more than the crash log: after running fix_ios_embed.sh, does the target’s Embed Frameworks phase list SwiftGodotRuntime.framework once or twice, and does the built .app end up with one copy or two? I’m looking hard at that script — it locates the framework reference by name alone, so in a project containing two references with that name it takes whichever appears first, which is not something I want it doing.
If a crash log or screenshots are easier to attach on GitHub, godot-iap Discussions is fine for setup questions and Issues if it turns out to be our bug. Answering here is just as good though, and I’ll follow up in this thread either way. I’m setting up a project with both plugins on my side now.
The crash’s “Expected in” UUID matches godot-iap’s copy, so that’s the one being used, and GodotApplePluginsGameCenter (built against GodotApplePlugins’s copy) is missing RefCounted.godotClassName. Given that this is absent from one binary and present in the other, it seems like more than a build-UUID difference. Hopefully this helps. Let me know if you need any more info.
That log was exactly what was needed — thank you. It settles it, and it turns out there are two separate problems.
The first is ours and is now fixed. Both plugins ask Godot to embed a runtime that installs as Frameworks/SwiftGodotRuntime.framework: ours as a .framework, GodotApplePlugins as an .xcframework whose iOS slice carries that same name. Godot embeds each GDExtension dependency independently with no dedup, so one copy phase gets two sources for one destination and Xcode refuses with Multiple commands produce '.../Frameworks/SwiftGodotRuntime.framework'. I reproduced that on a project of ours that ships today: with godot-iap alone it exports and builds, and adding the GameCenter plugin breaks it. fix_ios_embed.sh now drops our entry when another addon already embeds the same bundle, never theirs, and leaves a solo install untouched. Patched project builds clean with one runtime in the bundle. It’s on main.
The second is why deleting one copy crashed you instead of fixing it, and this one is not solved by the above. Expected in: <E472F3D2-E013-3613-9B3E-96FE7E0E9DE2> is our shipped binary — I checked the UUID against the file in our repo. So your build kept our copy, and your GameCenter then wanted SwiftGodotRuntime.RefCounted.godotClassName, which our copy does not export. Neither does upstream SwiftGodot v0.79.0, which is the newest release and what godot-iap pins. In v0.79.0 godotClassName is declared on Wrapped, not on RefCounted. Your GodotApplePlugins is built against a SwiftGodot newer than any release — your 90C915DC… runtime is not the one in their latest published addons build either, which is 21E7242A….
So the two plugins are compiled against different SwiftGodot versions, and since both runtimes share the install name @rpath/SwiftGodotRuntime.framework/SwiftGodotRuntime, dyld loads exactly one and the other plugin is stranded. The good news for you is the asymmetry: our plugin never references godotClassName, so keeping their runtime feeds both, which is the direction the fix takes. If their newer runtime dropped or renamed anything we rely on, that would surface as the mirror-image error, and I’d want to know.
Could you pull the updated fix_ios_embed.sh from main, re-export, and run it? Keep both addons installed this time, no manual deleting. If it still crashes, the next thing I need is which GodotApplePlugins build you have — a commit or download date — so I can match SwiftGodot versions rather than guess.
The fix is released, so you don’t need to pull from main — godot-iap 3.5.1 has it. Replace addons/godot-iap with the zip from that release, keep both addons installed, re-export and run fix_ios_embed.sh as usual. It will now print a line saying it is using GodotApplePlugins’ runtime instead of ours; that line means it worked.
Asset Library still points at 3.5.0 for the moment, so take the zip from the GitHub release rather than the in-editor installer.
That gets the duplicate out of the way. The version skew I described is still there and is the one I can’t fix from my side, so if it still crashes, the build info for your GodotApplePlugins copy is what I need next.
I am using godot-iap 3.5.1 and I ran the fix_ios_embed.sh script but I didn’t see anything in the output about using GodotApplePluginsRuntime. My iOS export directory is outside of the directory of my Godot project if that means anything. The Godot project is at /dev/games/Star\ Bandit/star-bandit
You’re right, that’s not the line I said to expect.
3.5.2 is out and the script now prints what it inspected, so we don’t have to guess. Replace addons/godot-iap with the zip from that release — or update from the Asset Library, which now serves 3.5.2 — then re-export, run the script, and paste the full output.
If you get:
Runtime embed check: no conflict among the embeds we could read: GodotIap.framework, SwiftGodotRuntime.framework
then GameCenter’s runtime never reached the Embed Frameworks phase, so the duplicate fix has nothing to act on — worth checking the plugins are enabled and ticked in the iOS export preset.
If it names GodotApplePlugins’ xcframework instead, the fix engaged and their runtime is the one being kept.
Are you seeing a crash, or just the missing line?
For anyone looking for a complete example: I maintain godot-iap, and my game Moonlit Beacon, live on the App Store and Google Play, is open source at GitHub - hyodotdev/MoonlitBeacon: Moonlit Beacon — Godot 4.7 game and godot-iap example · GitHub. It runs godot-iap 3.6.1 and covers one-time purchases end to end on both stores (fetch, purchase, verify with IAPKit, finish or consume, restore, re-sync on resume). It has no subscriptions and no GodotApplePlugins, so it won’t show the two-runtime case. To run purchases from it you still need your own bundle ID and signing, your own products in App Store Connect and Play Console, and an IAPKit key; setup steps are at Godot Setup | OpenIAP.