Repository navigation
feat(android): foreground service and versioned push messages for ongoing notifications - #359
Open
hristototov wants to merge 1 commit into
Conversation
…oing notifications
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What is this?
Android ongoing notifications stop at
NotificationManager.notify(). Nothing keeps the app process alive, so a workout or delivery notification freezes at its last value once Android kills the app in the background. On Android 14 and later the user can swipe any ongoing notification away, and neither the capabilities API nor the docs said so. Every app also had to hand-write the same push task body, and two pushes delivered out of order left the older content on screen.This adds an opt-in foreground service for one ongoing notification at a time, reports dismissibility in the capabilities API, and adds a versioned push message with a ready-made handler. The handler drops updates that arrive out of order. The decisions are recorded in ADR 0013. Closes #323.
How does it work?
ongoingNotificationForegroundService: { types }, declaresvoltra.ongoingnotification.VoltraOngoingNotificationServicewith the chosen types, plusFOREGROUND_SERVICEand oneFOREGROUND_SERVICE_<TYPE>permission per type. It works in the Expo plugin and involtra apply, which share one module.specialUsewithout a subtype.startAndroidOngoingNotification()andupsertAndroidOngoingNotification()acceptforegroundService: { type, onDismiss?, fallbackBehavior? }.foregroundService: { attached: true, type }, or{ attached: false, reason }with one of eight reasons, such asnot_declared,missing_permission,background_start_not_allowedorbusy.location,healthandconnectedDevice. A service that stops without going foreground would crash the app.fallbackBehavior: 'error', such a problem rejects withVOLTRA_FOREGROUND_SERVICE_UNAVAILABLEbefore anything is posted.stopandendAllrelease the service before cancelling, because Android ignorescancel()for a foreground service notification.onDismiss: 'stop') and never reposts.dataSyncandshortServicetimeouts detach the service and leave the notification visible.START_NOT_STICKY, and any record still markedattachedafter process death is corrected todetached.getAndroidOngoingNotificationCapabilities()addsisUserDismissible,supportsForegroundServiceandforegroundServiceTypes.getAndroidOngoingNotificationStatus()addsforegroundService: { type, state }.getAndroidOngoingNotificationHandle()and the KotlinVoltraOngoingNotifications.buildNotification()let an app's own foreground service carry Voltra's notification instead of posting a second one.createAndroidOngoingNotificationPushEnvelope()in@use-voltra/android-serverbuilds a version 1 message (v,notificationId,operation,revision,options,payload).handleAndroidOngoingNotificationPush()is the whole background task body. It accepts the message in every shape push providers deliver it, creates the channel through a callback, applies the upsert or stop, and never throws.parseAndroidOngoingNotificationPush()exposes the parsing step on its own.vare read as version 1, so existing pushes keep working.revisionapplied, natively, so the check survives process restarts.reason: 'stale_revision'.stopAndroidOngoingNotification()takes an optional{ revision }.revision, because they are replayed on every update.The docs cover the service, the reason table, dismissibility by Android version, the push message and the new task body. The example app's background task now uses the handler, and its Ongoing Notifications screen has a foreground service toggle.
Why is this useful?