Add custom notification icons for automations#4672
Conversation
There was a problem hiding this comment.
Hi @Roei-Bracha
It seems you haven't yet signed a CLA. Please do so here.
Once you do that we will be able to review and accept this pull request.
Thanks!
|
Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍 |
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds end-to-end support for custom notification “sender avatars” on iOS by parsing existing Android payload fields (notification_icon, color, icon_url) and decorating notifications into iOS Communication Notification style using INSendMessageIntent, with caching + tests and accompanying design/plan docs.
Changes:
- Introduces
NotificationSenderInfo+NotificationSenderParserto extract sender/icon info fromUNNotificationContent.userInfo. - Adds
NotificationCommunicationDecoratorto apply Communication Notification styling (MDI render or downloaded URL icon) and a disk-backedNotificationIconCache. - Wires the decorator into the Notification Service Extension pipeline and adds unit tests + a sample
.apnspayload.
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/superpowers/specs/2026-05-24-custom-notification-icons-design.md | New design spec describing payload contract, architecture, caching, and compliance considerations |
| docs/superpowers/plans/2026-05-24-custom-notification-icons.md | New task-by-task implementation plan and test strategy |
| Sources/Shared/Notifications/NotificationSender/NotificationSenderInfo.swift | Defines parsed sender/icon value type used by parser/decorator |
| Sources/Shared/Notifications/NotificationSender/NotificationSenderParser.swift | Parses notification_icon / icon_url / colors into NotificationSenderInfo |
| Sources/Shared/Notifications/NotificationSender/NotificationIconCache.swift | Adds disk cache with App Group + cross-process coordination |
| Sources/Shared/Notifications/NotificationSender/NotificationCommunicationDecorator.swift | Builds/donates INSendMessageIntent and applies content.updating(from:) with avatar image generation |
| Sources/Shared/Environment/Environment.swift | Registers decorator in DI container (Current) |
| Sources/Extensions/NotificationService/NotificationService.swift | Adds decorator step after existing attachment pipeline |
| Sources/Extensions/NotificationContent/Resources/TestNotifications/communication_notification.apns | Adds reproducible test payload for manual simulator/device verification |
| Tests/Shared/NotificationSender/NotificationSenderInfoTests.swift | Unit tests for value-type equality |
| Tests/Shared/NotificationSender/NotificationSenderParserTests.swift | Unit tests for field precedence, defaults, and malformed inputs |
| Tests/Shared/NotificationSender/NotificationIconCacheTests.swift | Unit tests for cache behavior + eviction + key stability |
| Tests/Shared/NotificationSender/NotificationCommunicationDecoratorTests.swift | Unit tests for intent construction, conversation grouping, URL download/cache behavior |
| HomeAssistant.xcodeproj/project.pbxproj | Adds new files to targets/groups (and incidental project-file churn) |
| Gemfile | Adds abbrev gem dependency |
| Gemfile.lock | Locks abbrev and bumps Bundler version |
7eb3bac to
7ccd851
Compare
There was a problem hiding this comment.
Hi @Roei-Bracha
It seems you haven't yet signed a CLA. Please do so here.
Once you do that we will be able to review and accept this pull request.
Thanks!
|
For the linter you can run |
|
Please mark as "Ready for review" after you finish |
- Support 'notification_icon', 'notification_icon_color', and 'color' keys in the push payload. - Promote custom notification icon fields in local push / websocket parser. - Register 'INSendMessageIntent' in NotificationService Extension Info.plist to support communication notification decoration. - Ensure notification intent donation completes before finishing decoration. - Add unit tests for local push event, notification sender parser, and legacy parser.
…e URL cache key collision
|
@Roei-Bracha can you check the conflicts? |
|
@Roei-Bracha are you still planning to work on it? |
|
@bgoncal, sorry I couldn't get to this earlier; I believe it should be fine now. |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #4672 +/- ##
=======================================
Coverage ? 45.62%
=======================================
Files ? 279
Lines ? 17068
Branches ? 0
=======================================
Hits ? 7787
Misses ? 9281
Partials ? 0 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
@Roei-Bracha Sorry, I've been very busy these last days, I added a reminder to check this PR during this week, meanwhile can you check the conflicts and resolve them? |
bgoncal
left a comment
There was a problem hiding this comment.
Review the comments added (maybe it came from an AI? they are usually verbose), reduce to only add comments to content not understandable by reading the code (and of course avoid adding non-obvious code)
|
|
||
| guard let server = Current.servers.server(for: request.content), let api = Current.api(for: server) else { | ||
| contentHandler(request.content) | ||
| guard let server = Current.servers.server(for: request.content), |
There was a problem hiding this comment.
Use guard let here to improve readability
| case iconURL = "icon_url" | ||
| case notificationIcon = "notification_icon" | ||
| case notificationIconColor = "notification_icon_color" | ||
| case color |
There was a problem hiding this comment.
Double check if this does not exist somewhere else in the code base, live activity just has added these keys as well
| } | ||
| } | ||
|
|
||
| /// MDI path is synchronous (no network). URL path downloads, caches, and downsamples the avatar. |
There was a problem hiding this comment.
| /// MDI path is synchronous (no network). URL path downloads, caches, and downsamples the avatar. |
|
Sorry, I won't be able to work on this right away. I'll be able to start on it in about two weeks. @bgoncal |
|
@Roei-Bracha No problem, thanks for letting me know, I'm here to help if you need, also in discord (@ bgoncal2) |
This PR adds support for custom notification icons (iMessage-style communication notifications) when a push payload contains
notification_iconoricon_url. Matches the Android companion app's payload schema.Testing status
This currently works with local push. I verified it in the iOS simulator by sending a Home Assistant notification with:
After enabling local push for the simulator server, the notification displayed the custom cellphone icon instead of the app icon.
Nabu Casa / remote push rollout
For Nabu Casa cloud push and other non-local notifications to work, the push relay/server must deploy the matching
SharedPushparser change from this PR. The server-side notification normalization currently needs to:icon_url,notification_icon,notification_icon_color, andcolorfrom the Home Assistant notificationdataobject into the top-level APNs custom payloadaps["mutable-content"] = truewhen eithericon_urlornotification_iconis present, so iOS launches the notification service extensionExpected APNs payload shape for
notification_icon: mdi:cellphone:{ "aps": { "alert": { "title": "Phone", "body": "test" }, "sound": "default", "mutable-content": true }, "notification_icon": "mdi:cellphone", "notification_icon_color": "#FFFFFF", "color": "#03A9F4" }Until that server-side relay code is deployed, cloud pushes can still arrive without
notification_iconand withoutmutable-content, so they will keep showing the normal app icon.