Skip to content
Development

Building a rating prompt I was sure wouldn't render in the simulator

By Victor Da Luz
iosswiftapp-storedev-logdeep-cut-atlas

Deep Cut Atlas needed an App Store rating prompt somewhere, and the obvious rule is: ask after someone’s had a genuine win, not on launch. I picked “three successful album adds” as the signal - enough to mean the app actually did its job at least once, not so many that the ask feels like nagging.

The gating logic itself is unremarkable: a counter in SettingsStore, incremented on every successful add across all three tabs that can trigger one (Discover, History, and Playlist’s “More from artist” suggestions), a threshold check, and a per-app-version flag so it only fires once until the next version bump. SwiftUI’s native @Environment(\.requestReview) handles the actual system sheet - you don’t build any UI for this, you just call it at the right moment.

Going in, I assumed I’d have to fake the whole verification: SKStoreReviewController and its SwiftUI wrapper are well known for being unreliable to trigger even on a real device, gated by Apple’s own yearly-per-app throttling, and I’d read more than once that it silently no-ops in the simulator entirely. I expected to verify the gating logic with unit tests and just trust the one line that calls requestReview().

It rendered anyway. Three real adds through the simulator UI, and the actual system rating sheet came up, on the first try, no special entitlement or debug flag needed. That’s not what I expected walking in, and it changed how I verified the rest of the feature - instead of trusting the call blind, I could screenshot the real sheet, confirm no re-prompt on a relaunch or a fourth add, and treat the whole flow as actually proven rather than “probably fine.”

The device pass afterward was mostly a formality at that point - tap responsiveness on the adds, no hangs, same behavior as the simulator. The interesting finding here wasn’t the feature, it was that a piece of received wisdom about how this API behaves in dev tooling turned out to be wrong, and I’d have shipped with weaker verification if I hadn’t just tried it.

Related reading