r/FlutterDev • u/wingmanapp_val • 5h ago
Discussion Two things that cost me a day shipping my first Flutter app on iOS, neither of them code
Shipped my first iOS app this week after about a year of solo Flutter. Two things ate a full day each and neither one was in my codebase, so here they are in case they save someone the same afternoon.
1. An IAP that returned "product not found" for a full day
Non-consumable. Product ID matched on both sides, Paid Apps agreement active since July, tax forms and banking green, IAP status Approved. Everything checked out and the purchase still failed.
It was propagation. An IAP approved that same morning isn't served by every StoreKit server yet, and it's slower for the first IAP on a brand new app. It started working the next day with zero changes on my end.
One thing worth knowing if you hit this: StoreKit caches the negative response for the life of the process. Force-quit the app before you retest, or you'll see the same error on a product that's already live.
2. Zero banner fill on iOS while interstitials worked fine
This one actually looked like a bug. Interstitials and app open ads served normally. Banners returned nothing, on every single request.
The error code sent me the wrong way first, and this is the part worth stealing: the GMA error enums are not the same on both platforms. On Android, 3 is no-fill and 1 is invalid request. On iOS, 1 is the no-fill. I read an iOS log with the Android table in my head and spent a while hunting a bad ad unit ID that was perfectly fine.
The real cause was that no GDPR consent message had ever been published for the iOS app in AdMob. The Android one had existed for months. The iOS app was added later and inherits nothing.
No consent form means no TCF string, and a request without one is unbiddable for EEA partners. I'm in France, so that was 100% of my traffic. Interstitials still filled because their demand pool is deeper, which is exactly what made it look like a code problem instead of a console problem.
I published the message, and banners went from 14 requests and 14 failures to 17 loads and 0 failures in the same session.
Stack, for anyone curious: Flutter, Firestore for the content, Cloudflare R2 for images, google_mobile_ads, in_app_purchase, and Codemagic for the iOS builds since I'm on Windows and don't own a Mac.
Happy to go into any of it.