Summary
When wavesync_nse_handle_push produces no notification content (sync timeout, cold
group-key cache, no matching SyncNotify policy), WaveSyncNotificationService
delivers the operator's APNs placeholder text untouched. Apps can already write a
localized fallback file into the App Group container; the NSE template should read it
as a second-tier fallback — above the raw placeholder, below real composed content.
Follow-up to the NSE work on feat/alert-push; related: #78.
Current behavior (src/ios/Sources/WaveSyncPush/WaveSyncNotificationService.swift)
applyResult(_:to:) (line ~130) only overwrites best.title/best.body when the FFI
returned non-empty JSON fields:
private func applyResult(_ json: String?, to best: UNMutableNotificationContent) {
guard let json = json, ... else {
deliver(best) // ← placeholder delivered untouched
return
}
if let title = obj["title"] as? String, !title.isEmpty { best.title = title }
if let body = obj["body"] as? String, !body.isEmpty { best.body = body }
deliver(best)
}
The early-exit guards in didReceive (missing config dir, unencodable payload) have
the same effect: the user sees the relay's generic placeholder.
Proposed behavior
Downstream apps (Mediterranea does this today, every launch) write
<app group container>/.wavesync_notification_fallback.json:
{
"es": { "title": "Mediterranea", "body": "Hay novedades en tu hogar" },
"en": { "title": "Mediterranea", "body": "There's news in your household" }
}
In applyResult's no-content path (and the didReceive early-exit guards):
- Resolve the container the same way
resolveConfigDir(groupId:) already does.
- If
.wavesync_notification_fallback.json exists, parse it, pick the entry matching
the device/app locale (fall back to the first entry).
- Apply its
title/body before deliver(best).
- Any read/parse failure → deliver the placeholder as today (never fail the push).
Precedence: FFI-composed content > app fallback file > APNs placeholder.
Why
The placeholder is operator-branded and non-localized, so every degraded push (cold
cache is guaranteed for the first push after reinstall; short budgets on constrained
networks are common) surfaces text the app has no control over. The fallback file
gives apps a localized, branded degraded mode with zero protocol changes.
Notes
- File format above is what Mediterranea already writes
(write_notification_fallback, one JSON object per locale key).
- Reading is NSE-side only; nothing writes from the extension (consistent with the
load-only group-key cache design).
Summary
When
wavesync_nse_handle_pushproduces no notification content (sync timeout, coldgroup-key cache, no matching
SyncNotifypolicy),WaveSyncNotificationServicedelivers the operator's APNs placeholder text untouched. Apps can already write a
localized fallback file into the App Group container; the NSE template should read it
as a second-tier fallback — above the raw placeholder, below real composed content.
Follow-up to the NSE work on
feat/alert-push; related: #78.Current behavior (
src/ios/Sources/WaveSyncPush/WaveSyncNotificationService.swift)applyResult(_:to:)(line ~130) only overwritesbest.title/best.bodywhen the FFIreturned non-empty JSON fields:
The early-exit guards in
didReceive(missing config dir, unencodable payload) havethe same effect: the user sees the relay's generic placeholder.
Proposed behavior
Downstream apps (Mediterranea does this today, every launch) write
<app group container>/.wavesync_notification_fallback.json:{ "es": { "title": "Mediterranea", "body": "Hay novedades en tu hogar" }, "en": { "title": "Mediterranea", "body": "There's news in your household" } }In
applyResult's no-content path (and thedidReceiveearly-exit guards):resolveConfigDir(groupId:)already does..wavesync_notification_fallback.jsonexists, parse it, pick the entry matchingthe device/app locale (fall back to the first entry).
title/bodybeforedeliver(best).Precedence: FFI-composed content > app fallback file > APNs placeholder.
Why
The placeholder is operator-branded and non-localized, so every degraded push (cold
cache is guaranteed for the first push after reinstall; short budgets on constrained
networks are common) surfaces text the app has no control over. The fallback file
gives apps a localized, branded degraded mode with zero protocol changes.
Notes
(
write_notification_fallback, one JSON object per locale key).load-only group-key cache design).