Notifications: restore the sound on the extension's fallback notifications - #785
Open
mpretty-cyro wants to merge 1 commit into
Open
mpretty-cyro wants to merge 1 commit into
mpretty-cyro wants to merge 1 commit into
Conversation
…tions The notification service extension never set a sound on either of the paths that build their own content, so every notification they produce is silent - the generic "You've got a new message" shown whenever processing fails, and the incoming call notification from handleFailureForVoIP. handleFailure already had the settings in hand for previewType and simply never read sound. The success path is unaffected; it builds content through NotificationContent.toMutableContent(shouldPlaySound:), which does attach one. handleFailure is the default: arm of handleError, so anything unrecognised lands there. A user whose messages consistently fail to process in the extension gets a banner with no sound for every message, with nothing in the app's settings to explain it. This was fixed once before, in ecf92ce ("fix PN sound settings not applying to remote PNs"), and dropped while resolving the merge in a68ed28 where the other branch had rewritten the same block. That is why it is a named function rather than an assignment repeated at each call site - a bare `content.sound = ...` in the middle of a rewritten block is exactly what went missing last time. Also fixes Sound.default resolving to UNNotificationSound(named: ""), which plays nothing: filename() returns an empty string rather than nil for that case, so the existing nil guard never caught it and the UNNotificationSound.default fallback was unreachable. Not currently reachable through the UI - default isn't offered in the sound picker and libSession decodes a stored 0 to note - but the fallback paths now depend on this function resolving correctly. The extension has no test target, so the regression tests cover the sound resolution and NotificationContent instead.
mpretty-cyro
force-pushed
the
fix/notification-extension-fallback-sound
branch
from
September 8, 2026 01:44
a10289a to
96bbc27
Compare
mpretty-cyro
marked this pull request as ready for review
September 8, 2026 01:45
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.
Reported twice this week (#28249, #28223): no sound on incoming message notifications, on iOS, with everything configured correctly — system notifications on with sounds enabled, Fast Mode on, a sound selected, "Sound when App is open" on.
The bug
NotificationServiceExtension.swiftnever sets a notification sound. The stringsounddoes not appear in the file at all.The extension has one path that builds content through the shared
NotificationContent.toMutableContent(shouldPlaySound:)— that one attaches a sound correctly and is unaffected. It also has two paths that hand-roll aUNMutableNotificationContent, settingtitle,body,userInfoandbadgebut neversound:handleFailurehandleFailureForVoIPThere is nothing to inherit from the payload either: it carries only
spnsandenc_payload(PushNotificationAPI.swift:146,150), and the sound preference lives in libSession locally and is never transmitted, so the server could not set the right one even in principle.handleFailureis thedefault:arm ofhandleError, so any unrecognised error lands there. A user whose messages consistently fail to process in the extension gets a visible but silent notification for every single message, with nothing in the app's settings to explain it. The incoming call case is the worse of the two.handleFailurealready fetchednotificationSettingsforpreviewTypeand simply never read.sound.This was fixed once already
ecf92ceeea(2021-10-19) — "fix PN sound settings not applying to remote PNs" — addednotificationContent.sound = OWSSounds.notificationSound(for: thread).notificationSound(isQuiet: false).a68ed28a7a(2022-03-09) — "Merge branch 'dev' into voice-calls-2" — dropped it. Not a decision: the other branch had rewritten the same delivery block and resolving in its favour removed the one line it had never had.Gone ever since — zero occurrences in 2.0.0 through 2.15.4. The 2025 refactor restored a different mechanism (the shared presenter) covering the success path, and rebuilt the fallback paths from the post-merge shape.
That history is also why this is a named
applyNotificationSound(to:notificationSettings:)rather than an assignment repeated at each call site. A barecontent.sound = ...in the middle of a block someone else is rewriting is precisely what went missing last time; a missing call to a named function is conspicuous in a way a missing assignment is not.Second, smaller fix
Preferences.Sound.notificationSound(isQuiet:)guards onfilename()beingnilto fall back toUNNotificationSound.default— but.defaultreturns"", notnil. The guard never fired, the fallback was unreachable, and it builtUNNotificationSound(named: ""), which resolves to no file and plays nothing.Not reachable through the UI today (
.defaultisn't offered in the sound picker, and libSession decodes a stored0to.note), so it's a latent trap rather than a live bug — but the fallback paths now depend on this function resolving correctly, so it's fixed here. Happy to split it out if you'd rather.Testing
The extension has no test target, so the regression tests cover the sound resolution and
NotificationContentinSessionMessagingKitTestsinstead. Added toNotificationsManagerSpecrather than a new file to avoid touching the project file..defaulttest fails against the unfixed code and passes with it.SessionMessagingKitTestspasses in full.** BUILD SUCCEEDED **for theSessionscheme.The
handleFailure/handleFailureForVoIPchanges themselves are not covered by an automated test — worth saying plainly. Manual verification needs a device on a production signing cert (third-party contributors can't exercise push at all, per BUILDING.md).Still open on the tickets
This is a confirmed defect and worth fixing regardless, but it is not yet confirmed to be what the two reporters are hitting. The question that settles it is whether their notifications read "You've got a new message" or show the sender's name and message text — if the latter, the success path ran, a sound was attached, and something else is going on. I'll update once they reply.
Draft until then.