Introduction
Lerix delivers push notifications using each platform’s native service — Firebase Cloud Messaging (FCM) on Android, Apple Push Notification service (APNs) directly on iOS (no Firebase required), and standard Web Push (VAPID) on Flutter Web (no Firebase or OneSignal required there either). One package, oneLerix.notifications.* API, for all three. After you complete the Flutter installation, follow the platform steps below to enable push delivery in your app.
Make sure you have initialized the SDK with
Lerix.init() before configuring push notifications.Android configuration
No additional SDK setup is required for Android. You only need to add your Firebasegoogle-services.json file to the project.
- Create or open your app in the Firebase Console.
- Download
google-services.jsonfor your Android app. - Upload the file to the Lerix dashboard.
iOS configuration
You need an active Apple Developer account to send push notifications on iOS.Set up APNs authentication
- In the Apple Developer portal, go to Certificates, Identifiers & Profiles → Keys.
- Create a new key with Apple Push Notifications service (APNs) enabled.
- Download the
.p8authentication key and note the Key ID. You can only download the key once. - Upload the
.p8file to the Lerix dashboard.
AppDelegate configuration
Add the following overrides toios/Runner/AppDelegate.swift:
AppDelegate.swift
macOS configuration
macOS uses APNs with the same key you uploaded for iOS; no extra dashboard setup is needed. In Xcode, openmacos/Runner:
- Signing & Capabilities: sign with your Apple team and add Push Notifications. An app signed “to run locally” can’t receive pushes.
- App Sandbox: allow Outgoing Connections (Client) so the SDK can reach Lerix.
- AppDelegate: forward the APNs callbacks in
macos/Runner/AppDelegate.swift:
For Windows, see Windows push notifications (preview). Linux push isn’t supported yet.
Web configuration
Flutter Web is supported by the samelerix_flutter package — no separate JS SDK, no Firebase project. Two steps instead of Xcode’s:
- Copy the service worker. A Flutter package can’t add a file to your app’s
web/folder for you — copy thelerix_flutterpackage’sweb_sw/lerix-sw.jsinto your app’sweb/lerix-sw.js, so it’s served at your site’s root (e.g.https://yoursite.com/lerix-sw.js). - Generate a Web Push key from the dashboard: Notifications → Settings → Web Push → Generate keys. One click — Lerix generates and stores the VAPID key pair for you; there’s nothing to copy into your code.
Lerix registers its worker on its own scope (
/lerix/), so it runs alongside Flutter’s flutter_service_worker.js and a default flutter build web works as is. With lerix_flutter 0.0.1, the two workers competed for the root scope and Flutter’s replaced Lerix’s, so pushes were reported as sent but never shown. If you are still on 0.0.1, upgrade, or build with flutter build web --pwa-strategy=none.On web,
requestPermissions() does more than it does on mobile — see Platform differences below.Huawei configuration
Coming Soon Huawei push notification support is not available yet. Check back soon for setup instructions.Dashboard settings
Once you’ve uploaded yourgoogle-services.json (Android) and/or .p8 key (iOS), or generated a Web Push key pair, from the project’s Notifications → Settings tab in the dashboard, that platform card shows a Configured badge and the credentials it holds — click it again any time to review them or replace them.
Flutter code
All notification methods live onLerix.notifications, and require await Lerix.notifications.init() to have run first — registration with APNs/FCM happens automatically as part of init(), so there’s no separate “register” call for the normal flow.
main.dart
setOnNotificationTapped somewhere that has access to navigation (e.g. a global navigatorKey), since a tap almost always means routing to a specific screen based on payload.metadata rather than just logging it.
The notification payload
setOnNotificationReceived and setOnNotificationTapped both receive an LerixNotificationPayload — the same shape on iOS and Android, regardless of how differently each platform actually delivers the underlying push:
A tap is delivered reliably even when it’s what launched the app from a
fully terminated state — call
setOnNotificationTapped right after
Lerix.notifications.init() and any tap that happened before your app
finished starting up is replayed automatically once the callback is
registered.Device identifiers: getDeviceId() vs getDeviceToken()
These look similar but answer different questions — use the right one for what you’re doing:
null until registration completes, which Lerix.notifications.init() handles automatically — no separate call needed.
Sending a custom sound
Setsound when sending a notification — from the dashboard’s Send notification tab, or the REST API’s sound parameter — to play a bundled sound file instead of the device default:
- The file must already ship inside your app project — Lerix only passes the filename through, it never hosts or uploads sound files.
- iOS: pass the filename with its extension, e.g.
sound.mp3(.wav/.cafalso supported). - Android: pass the filename without an extension, matching a file under
res/raw/(e.g.soundforres/raw/sound.mp3). Supported formats:.wav,.mp3,.ogg. - Web: not supported — the Web Notifications API has no cross-browser way to set a custom sound, so this parameter is ignored for web recipients.
On Android, a sound is locked in the first time it’s used on a given
device — the OS fixes a notification channel’s sound at creation and never
lets it change afterward. Sending a different
sound value later creates a
new channel rather than updating the old one; that’s expected Android
behavior, not a bug.Sending metadata
Attach arbitrary custom data withmetadata (a JSON object) when sending — from the dashboard’s Send notification tab, or the REST API’s metadata parameter. It’s delivered back to the device inside payload.metadata:
Sending an image
SetimageUrl when sending a notification — from the dashboard’s Send notification tab, or the REST API’s imageUrl parameter — to show a rich image in the notification. Unlike sound, this is a normal https:// URL, not a bundled file — Lerix downloads it on your behalf.
- Android: works automatically, no extra setup. The image renders as a
BigPictureStylenotification. - Web: works automatically, no extra setup — the service worker renders it as the notification’s icon/image directly.
- iOS: requires your app to have a Notification Service Extension — APNs has no native “image” field, so the OS needs a small extension to download and attach the image before displaying the notification. This is a one-time setup step per app:
- In Xcode: File → New → Target… → Notification Service Extension. Name it (e.g.
NotificationServiceExtension). - Replace the generated
NotificationService.swiftwith the one from thelerix_flutterpackage atios/NotificationServiceExtension/NotificationService.swift. - Build and run — no other configuration needed. The backend automatically sets APNs’
mutable-contentflag whenever a notification carries animageUrl, which is what triggers your extension to run.
- In Xcode: File → New → Target… → Notification Service Extension. Name it (e.g.
If iOS’s extension isn’t set up, an
imageUrl is silently ignored on iOS —
the notification still shows normally with no image, it doesn’t fail to send. Android is unaffected either way.payload.imageUrl (in setOnNotificationReceived/setOnNotificationTapped) if you want to show it in a custom in-app banner, in addition to the OS rendering it natively.
Platform differences on web
Flutter Web uses the sameLerix.notifications.* calls as mobile, with a few real differences worth knowing about rather than being surprised by:
requestPermissions()does more on web. On mobile, push registration happens automatically insideinit(), andrequestPermissions()only concerns the visible-notification permission. A browser can’t subscribe to push before permission is granted, so on web,requestPermissions()also registers the service worker’s push subscription with the backend once the user allows it — the same method call, just doing double duty.getSenderId()returnsnullon web — it’s an Android/FCM-only concept (Web Push uses VAPID, not Firebase).getDeviceToken()also returnsnullon web — the browser’sPushSubscriptionisn’t a single opaque token the way APNs/FCM’s are, so there’s nothing meaningful to return. UsegetDeviceId()on every platform instead.- Custom sound isn’t supported — see Sending a custom sound above.
- Browser support: Chrome, Firefox, and Edge fully; Safari requires macOS 13+ or iOS 16.4+ — older Safari doesn’t support standard Web Push at all.
Target a user on every device
If your product also ships on other platforms (web, mobile or desktop), add them to the same project and link each install to your own user ID after login. Your backend can then send toexternalUserIds and reach that person
on every device in one request.
Topics
Instead of targeting specific device tokens, a device can subscribe to a named topic — send one notification to the topic and every subscriber receives it. A topic doesn’t need to be created ahead of time; it’s created automatically the first time any device subscribes to it. You can also view, create, and delete topics from the Notifications → Topics tab in the dashboard.sendByTopic: true.