DEV Community

Weavri
Weavri

Posted on

Shipping a signed Android APK as a solo dev (and the WiFi app it was for)

I shipped a small Android app this week and I want to talk about the other half of building it: making the release artifact something a stranger can actually trust.

WiFi Beacon (WiFi 哨兵) is a tiny utility: you pick a Wi-Fi network, and every time you open an app you've flagged as distracting while connected to that network, it throws a full-screen wall in front of it. It's the digital equivalent of putting the snacks on a shelf you can't reach.

It's not exciting. That's the point — it's the kind of app that either works quietly or doesn't get used at all.

What it actually does

  • Pick a Wi-Fi SSID (the one you work on)
  • Pick the apps you don't want to open there
  • A foreground-service detector (AccessibilityService) notices the app coming to the foreground
  • A full-screen warning covers it: "You're on . You opened . Go back?"

The logic is small. Most of the value is in getting the details right:

Getting the current foreground app without root. ActivityManager.getRunningAppProcesses() is basically useless post-Android 5. The reliable route is an AccessibilityService watching TYPE_WINDOW_STATE_CHANGED. It costs you a scary permission dialog, so the app has to justify it clearly in one sentence.

Android 12 broke SSID reads. WifiManager.getConnectionInfo() no longer hands you the SSID the way it used to — you now need ACCESS_FINE_LOCATION (and on 13+, NEARBY_WIFI_DEVICES) or the SSID comes back as <unknown ssid>. That's the single most common bug in this category of app.

I wrote both of those up in detail before building this:

The part I'd been skipping for years: shipping a signed, verifiable release

I've shipped debug APKs by hand for years. This time I did it properly, and the friction was all in places I didn't expect (no Android Studio involved — just JDK 17, the Android SDK, and Gradle on a headless Linux box):

  1. assembleRelease with no signing config produces an unsigned APK, and Gradle will happily give you a success message for it. The signing config has to be conditioned on a properties file that exists outside version control.
  2. services.gradle.org being unreachable doesn't fail loudly — the wrapper just sits there. The fix is getting the distribution into the wrapper cache under the right hash, or pointing at a mirror.
  3. Verify what you shipped, not what you think you shipped:
apksigner verify --print-certs app/build/outputs/apk/release/app-release.apk
shasum -a 256 app-release.apk
Enter fullscreen mode Exit fullscreen mode

I wrote that flow up too: No Android Studio? Build APKs in GitHub Actions and verify them on real hardware

The result

Same app, four ways in — no paywall in front of the code:

  • Source: github.com/weavrikx/wifiwarn — MIT, build it yourself, do whatever you want with it
  • Signed APK (4.5 MB): releases/latest — built and verified, SHA-256 published alongside it
  • Landing page: weavrikx.github.io
  • The paid version, if you just don't want to compile: ¥9.9 (about $1.40) for the ready APK + a setup guide, or a ¥99+ white-label build (your app name, icon, warning copy, preset rules)

Why "open source + a $1.40 paid build" instead of one or the other

I went back and forth on this and landed here: the code being MIT isn't a loss leader, it's the honest position — I'd rather someone fork it than bounce off a paywall. The paid tier sells not having to build it, which is a real thing people pay for. Nobody who wants to git clone was ever going to be a customer, and pretending otherwise mostly just annoys developers.

If you've fought the Android 12 SSID permission mess, or you've ever shipped an unsigned APK and only found out later, I'd like to hear how you handled it.

Top comments (0)