-
-
App icon - three interlocking circles on warm paper.
-
iOS - Communities - private circles for family and friends.
-
Android - Support the developer paywall on Android (RevenueCat, same tiers).
-
iOS - A prayer up close, with the people praying for it.
-
iOS - Share a new prayer with tags and who can see it.
-
Android - Settings on Android - same theme selector, communities, reminders.
-
Android - Shared feed, dark theme.
-
iOS - Support the developer - a RevenueCat tip jar; nothing is locked behind it.
-
Android - Shared feed, light theme.
-
iOS - Sign in with email, Google, or Apple.
-
iOS - Shared feed in dark mode with the iOS 26 liquid-glass tab bar; answered prayers get an "Answered" note.
-
iOS - Settings with the Device / Light / Dark theme selector.
-
iOS - Praying - the prayers you're holding for others.
-
iOS - My Prayers - your own requests in one place.
Share Pray
A quiet place for families and small churches to carry each other's prayers.
What inspired it
Distance is the ordinary condition now. Family in one country, friends in another, a church you visit twice a year. Staying in each other's lives takes more deliberate effort than it used to, and the thing that goes first is the small stuff — not the news you announce, but the things you are quietly carrying. Those get lost in a group chat, scrolled away under photos and links by the evening.
I wanted somewhere those could sit still. You write what you would like prayer for; the people who care about you see it and can say they are praying. That is the whole app.
I first tried to build it in 2017 — Kotlin app, Kotlin backend — and never had the evenings for it. It sat unfinished for years. What changed was not the idea. It was that I finally had the time.
How I built it
Kotlin Multiplatform, with Compose Multiplatform for the interface and my own Ktor backend. SQLDelight for storage on both ends, Koin for wiring.
The split is the point:
| files | |
|---|---|
| shared, platform-agnostic | 109 |
| Android-specific | 18 |
| iOS-specific | 15 Kotlin + 3 Swift |
Nearly everything — the feed rules, the session handling, the offline cache, the validation — is written once. What stays platform-specific is what genuinely differs: how a text field looks, how a link arrives from the system, how the database driver opens, and how a native SDK like Google Sign-In is reached.
The backend is mine too, not a BaaS: accounts and email confirmation, prayers and their visibility, communities with invite codes, a moderation panel with an audit trail. Around 390 unit and integration tests, plus 81 instrumented tests that drive the real app against a real server.
Paying for it without charging for it
Charging someone to ask for prayer was never going to happen. Nothing in the app is behind a paywall and nothing ever will be.
So RevenueCat runs a tip jar instead of a gate. The Settings screen offers a coffee, a coffee and a snack, lunch, dinner, or a standing subscription for anyone who wants to keep it running. Everything about the offer — how many tiers, what they cost, what the paywall says — comes from the offering RevenueCat serves, not from constants in my source, because prices differ by country and change without an app release.
Purchases are tied to the account rather than the device, so someone who supports on their phone is still a supporter on their tablet. Restore is there for the people who reinstall. And when no API key is built in — the ordinary state of the test flavour — the app says support is unavailable and everything else carries on. That had to be a state the app could be in, not a crash.
It is an unusual use of a purchases SDK: no entitlement gates anything. The customer info exists only so the app can say thank you.
What I learned
The bugs that matter are the ones that fail silently. Not crashes — those announce themselves. The ones that cost weeks are the ones where everything looks fine.
A test asserted the very typo it existed to catch. The Digital Asset Links file
named kg.nongrate.share_pray where the app is kg.nongrate.sharepray, and
Android's response to a mismatch is not an error — it simply never offers to
open the app. The test had encoded the wrong spelling, so it went green every
time.
Google Sign-In failed for a week because I had registered the upload key's
fingerprint rather than the one Play re-signs with. The device log said
NoCredentialException, and my own error handler translated that to "no Google
account available" on a phone with two.
Ktor 3.2.0 compiled, passed all 390 tests, and then failed to build a release:
Space characters in SimpleName 'use streaming syntax' are not allowed prior to
DEX version 040. It needs minSdk 30; mine is 24. Only the release build
caught it.
And a feature can fail without anything being broken. I curated 98 prayer
tags and put a search box over them. Production ran for weeks with nine tags
ever used. Someone typed trevoga — Russian, transliterated — rather than
find anxiety, which was right there. You cannot search a set you have never
seen. A tag nobody can find is a tag that does not exist.
Cutting the list would have decided that most of what people pray about does not deserve a word. Grouping was the third answer: six groups, ten tags in each, and the picker shows six things at a time.
Challenges
The one I spent longest on was a faint ring around the launcher icon. Eight diagnoses, each plausible, each wrong. It turned out to be an emulator rendering artefact — invisible on a physical Pixel. I had been correcting artwork that was already correct. Since then I check on real hardware before I believe anything.
Then there is measurement instead of taste. When a card needed lifting off dead centre, the honest version is not a number I liked the look of but a bias over the space actually left over, so a short prayer rises and a full one does not move. Same for placing the logo: its weight sits above its bounding-box centre, so the mark is positioned by a measured centroid,
$$\bar{y} = \frac{\sum_{y} y \cdot w_y}{\sum_{y} w_y}$$
where each row's weight $w_y$ is how far its pixels depart from the paper, in the proportions the eye uses — a broad pale wash counting for less than a thin dark stroke of the same area. That number is measured at build time, so it stays true if the artwork is ever redrawn.
Where it is
Live on Google Play and Apple Store in English and Russian — the Russian reviewed by a native speaker, because a devotional word and an everyday word are not the same word.
Log in or sign up for Devpost to join the conversation.