PocketBill Blog
One optional button, one week of setup, and a limit I should have known about: the native Google account picker is a custom native module, and Expo Go's shell simply does not contain it. What the forced move to a development build changed, and how I kept login from leaking into every screen.
PocketBill is deliberately account-free: subscriptions, bills and spending, all kept on the phone, no signup, happy on a plane. For two months I treated that as a feature rather than a limitation. Then a beta tester asked what happens when he changes phones, and the honest answer was that his ledger lived on exactly one device.
So the plan became one button, entirely optional. I wrote it in an evening, then spent a week learning that the button cannot exist on the device where I was testing.
Most of that week was not configuration, it was a limit I should have known. The native Google account picker — the real system sheet, the one that recognises your face — ships as a custom native module. Expo Go is Expo's universal shell: it carries only the libraries Expo itself bundles. That module will never be inside it, which means the picker can never open there. Not misconfigured, not broken. Absent.
That leaves exactly one road: a development build, an APK I sign myself, carrying the native code my app actually needs. You cannot negotiate with a missing system dialog, and for once that was clarifying.
What I did not want was auth leaking into the whole app. The layer sits behind three files split by platform: one calling the system sign-in on the device and trading the returned identity token for a session, one used only when debugging in a browser, and a shared file for the parts that are identical everywhere. The public surface stayed at three calls, so the login screen and the state store never had to notice anything changed.
One decision paid for itself straight away. Because the app talks to Firebase through its JavaScript SDK rather than a native one, there is no downloaded config file anywhere — the project details are plain strings in an env file, including one client ID that gets handed to the sign-in library as the web client. The Android side identifies itself differently: package name plus signing fingerprint. Remember that sentence, because it cost me three days.
The part I keep returning to is that none of this was strictly necessary. PocketBill still opens, records and closes with no account at all, and that order matters. Sign-in is something you reach for when you are changing phones, not a door you walk through on the way in.
The button shipped. The first thing it did was fail without saying so, which is where the next part starts.