Fg FileGrab
Back to Blog

Push notifications on FileGrab, now including UnifiedPush

Push notifications shipped on the FileGrab mobile apps. When a new file lands on one of your links, when a long-running transcription finishes, or when you are running low on storage, the app tells you. The interesting bit is what is under the hood on Android.

Three push transports, one app

FileGrab sends every notification the same way from the server. The mobile apps pick the transport based on what the device actually supports:

  • iOS: Apple Push Notification service (APNs). Rich thumbnails via a Notification Service Extension.
  • Android with Google Play services: Firebase Cloud Messaging (FCM). Rich thumbnails via BigPictureStyle.
  • Android without Google services: UnifiedPush. One APK, no Firebase dependency at runtime, no Google Play services required.

The server writes one push_events row per dispatch with the outcome classifier, so we can watch delivery rates across all three transports in one dashboard.

Why UnifiedPush

Push on Android has been Google’s walled garden for years. Firebase Cloud Messaging is the default, it’s the simplest integration, and it’s what every tutorial assumes. But it has two costs:

  1. The binary needs Google Play services to deliver messages. That breaks the app on GrapheneOS, CalyxOS, LineageOS without gApps, Fairphone without Google, and every other degoogled setup.
  2. Your push traffic flows through Google’s servers. That matters to some users; it matters to regulators in some jurisdictions.

UnifiedPush solves both. It’s an open protocol where the user picks a push “distributor” (the most popular is ntfy, but there are others). The distributor handles the long-lived connection to the server. The app talks to the distributor through a standard intent-based API. From the server side, UnifiedPush uses plain HTTP with RFC 8291 Web Push encryption, the same encryption the browser Push API uses.

No tracking. No Google services. No proprietary SDK to pull in. The messages stay end-to-end encrypted from our backend to your device.

How we built it

A single APK on both Play Store and F-Droid. At runtime, the app detects whether Google Play services are available:

  • If yes, FCM handles push. The user never sees UnifiedPush unless they go looking.
  • If no (or if the user explicitly picks a UnifiedPush distributor in settings), the app registers with UnifiedPush instead.

The backend doesn’t care which path the app took. Every push subscription in the database carries a transport column (apns, fcm, or unifiedpush) and, for UnifiedPush, the RFC 8291 encryption keys. When the dispatch worker picks up a notification job, it routes to the right code path and encrypts the payload for UnifiedPush subscribers.

The payload format is identical across transports. The Android client constructs the system notification locally from a JSON blob, so push messages are tiny and we don’t rely on FCM’s notification block (which doesn’t exist in UnifiedPush anyway).

If you’re on a degoogled phone

Open Settings → Notifications in the FileGrab Android app. You’ll see:

  1. A toggle for Android’s system notification permission (Android 13+).
  2. A UnifiedPush section that lists every installed distributor.

Install ntfy or any other UnifiedPush distributor, come back to this screen, pick it, and you’re registered. No Google anywhere in the loop.

What you’ll see

  • Upload digests. When people upload files to your link, FileGrab batches notifications based on your per-link frequency (5 min, 15 min, hourly, or daily) and sends one push per window rather than one per file.
  • Processing complete. When a long transcription or a large document conversion finishes, you get a tap-through to the result.
  • Storage warnings. When you’re about to hit your quota.

Tap a notification to jump straight into the relevant link. On iOS, notifications with an image get a rich thumbnail courtesy of the Notification Service Extension. On Android, the same thumbnail shows through BigPictureStyle.

Want the details

The full implementation spec, including the backend architecture, the Cloudflare Queue consumer, and the per-transport error classifier, lives in docs/specs/push-notifications-implementation.md in the FileGrab repo. If you’re building push into your own app and curious about the UnifiedPush integration specifically, the connector code at apps/fg-android/app/src/main/java/link/filegrab/core/push/UnifiedPushReceiver.kt is the minimal example.

Try it out. If you run into anything weird, the Notifications screen in settings will tell you where delivery is coming from.

#push-notifications#android#ios#unifiedpush#privacy

Ready to try FileGrab?

Share files instantly. Recipients download with no signup and no ads.

Start Sharing Files