RECEIPT · 2026-09-06 · the FrankenKeys log

A one-time unlock with no account and no server

How the FrankenKeys Pro unlock is bought once, restored on a new phone, and refunded, when the app has no account, no server and no network permission.

2026-09-06 · by Corey Redwine · one time purchase android keyboard

FrankenKeys is free. There is one in-app purchase, a single one-time unlock called Pro, and no subscription. A reasonable person asks how that works when the app cannot reach the network: how is a purchase verified, how does it come back on a new phone, and what stops a backup file from being a free licence. Here are the mechanics.

The purchase goes through the Play Store app, not through mine

Google Play Billing is a library inside the app that talks, over inter-process communication, to the Play Store app already on the phone. The Play Store app does the networking, on its own permission, with your Google account. FrankenKeys never opens a socket; it asks the Play Store app "does this account own forgeboard_pro" and gets an answer.

This was tested rather than assumed. An earlier plan was to ship Pro as a separate paid app, on the belief that adding Play Billing would drag the INTERNET permission into the manifest. It does not. The billing library adds com.android.vending.BILLING and nothing else, and the air-gap assertion in the build would have failed if it had.

What Pro unlocks, and what it does not

Nothing that affects how well the keyboard types is ever gated. Typing, prediction, autocorrect, swipe, dictation, AI rewrites, emoji, clipboard, all thirty-one preset themes, twenty haptics, fifty sounds, thirty press effects, and Theme Studio's colour tools are free. Nobody pays to find out whether building a look feels good.

Pro unlocks the creation tools: background photos, imported fonts, imported key sounds, per-app profiles, theme scheduling, the Effect Forge, the Shader Forge, unlimited saved scenes (free keeps two), the Key Editor and the macro row.

The price is set in Play Console and shown by Play in your currency; the app never hard-codes a number, which is why the button reads "Unlock Pro" with whatever Play reports beside it. In the US store it is $6.99 at the time of writing.

Restoring on a new phone

There is no account to sign into because there is no server holding one. Restore is Play's job: when the billing library connects, it queries the purchases the signed-in Google account owns, and if forgeboard_pro is among them the unlock is set. Install the app on a new phone with the same Google account and Pro comes back on first launch of settings. No code, no email, no "restore purchases" button to find, although the connection happens every time settings opens so a missed one catches up.

Refunds revoke it

The same query handles the other direction. If Play reports the purchase refunded or revoked, the flag is cleared. This is Google's standard model and I am not going to pretend to be more generous than it; a refund is a refund.

One detail here was a real bug. The developer's own test unlock and the purchase flag used to share a key, so the sequence was: test unlock set, billing connects, Play says "no purchase", the refund path clears it. Pro evaporated every time billing connected, which is every launch, and read as "it forgets after each update". They are separate keys now, and the owner unlock is not something a user can set.

N/I

The Pro flag never leaves in a backup. Export a backup from Settings, open the JSON inside the zip, and search for pro. The entitlement keys are stripped on export and ignored on import, so a backup file cannot be passed around as a licence. Class: studio.forgedev.forgeboard.core.Backup, in the shipped build.

Why a backup cannot be a licence

The backup file is readable JSON by design, because you own what the keyboard learned. That created an obvious hole: if the Pro flag were in it, anyone could share the file and unlock Pro on any phone. So the exporter strips the entitlement keys, and the importer ignores them if a hand-edited file carries them. Pro on a restored phone comes from Play, as above, never from the file.

The same file, wrapped with a passphrase, is encrypted with AES-256-GCM. That protects your dictionary, not the unlock; the unlock was never in there.

What I cannot do because of this design

I cannot give you a discount code of my own; that needs a server to check it against. I cannot see how many people have bought Pro except through Play Console's own reporting, which is Google's data about Google's transactions. I cannot offer a "buy once on Android, use on another platform" arrangement, because there is no other platform and no account to tie it to. And I cannot sell Pro anywhere but Play, because the entitlement check is a question to the Play Store app.

Those are real limits. They are also the reason the answer to "what does the app send when I buy" is: nothing, because it cannot.

Where each mechanism lives

  • studio.forgedev.forgeboard.billing.Pro: the only class allowed to ask about payment; the two separate keys.
  • studio.forgedev.forgeboard.billing.BillingManager: connect, query purchases, query the localised price, handle refunds.
  • studio.forgedev.forgeboard.core.Backup: the keys that must never travel.
  • The merged manifest: com.android.vending.BILLING, and no network permission. Verify it.

One payment, once. The SKU is still called forgeboard_pro because renaming a Play product voids every purchase made under the old name, and the name of a database key is not worth your money.