Deendar — prayer times, Quran and hadith for daily practice
Selected screens

A tour of the build.

Swipe or click through the screens.

6,236
Quran verses, all 114 surahs
16,453
hadiths across 29 collections
23
prayer time calculation methods
2
languages, switchable anywhere

One codebase has to ship as two different products, and only one of them may go near Google Play.

One codebase has to ship as two different products, and only one of them may go near Google Play. The Bangladesh build sells bundles through carrier billing, which violates Play's Payments policy outright — an enforcement action against it would take the global listing down with it — so the two flavors have to diverge in distribution, sign-in, paywall and Android permissions while staying a single repo. Underneath that sat a build system that could not be trusted: flutter clean silently failed to delete the build directory on this checkout, so Gradle considered its outputs current and repackaged the previous Dart snapshot while reporting success. A release was signed and uploaded carrying code that did not match the commit it claimed to be, and the two differing snapshots were byte-for-byte the same size. And a Play submission is more than a binary — it needs a Data Safety declaration that matches the privacy policy exactly, a deletion route a user can complete on the web without installing the app, and honest content counts, because a discrepancy between any two of them is itself a rejection reason.

What we did

The flavor is selected twice, once by Gradle and once by a dart-define, and the app throws on startup when the define is missing, so a mismatched build fails immediately instead of shipping a Play-signed bundle that behaves like the Bangladesh one. The global manifest is the Play-safe baseline, and a verification script parses the merged manifest rather than grepping it — grep matches the explanatory comments inside those files and reports permissions as present when they are only being discussed — to assert that no Play-restricted permission survives into the global build while Bangladesh keeps everything it shipped with. Release builds are now verified by extracting the compiled snapshot from the bundle and searching it for a string added just before the build, with the trap written into the runbook that a single non-ASCII character turns the whole literal UTF-16 and makes a plain search report a fresh build as stale. Sign-in moved to Texion Auth through the system browser, which removed the SHA-1 fingerprint registration and with it the classic trap where Google sign-in works under a debug run and fails for every real user once Play re-signs the app; the backend checks that a token's audience equals its own client id, because Texion Auth is multi-tenant and without that check a token issued for any other application would be accepted.

What changed after

Live at deendar.texion.tech, carrying the marketing page, the privacy policy and the account deletion flow, with the global build in internal testing on Play ahead of the public release. The app is free with no ads and no paywall, everything is readable without an account, and sign-in exists only so favourites and the deeds tracker follow a user between devices. The Data Safety answers were derived from what the code actually does rather than from a template — including declaring precise location, because the app asks for roughly 100-metre accuracy and holds the fine-location permission, and answering "approximate only" while holding it is a mismatch Play checks for. The store copy was written against verified row counts for the same reason: the dua collection is deliberately mentioned without a number, because claiming more than ships is both dishonest and a support-ticket generator.

Ready when you are.

One business day to first reply. Always.