Skip to content

fix(mobile): send Android app-drawn pushes with no notification block - #2485

Merged
DoodleBears merged 2 commits into
mainfrom
claude/project-thread-9rg7zp
Oct 21, 2026
Merged

DoodleBears merged 2 commits into
mainfrom
claude/project-thread-9rg7zp

Conversation

@DoodleBears

@DoodleBears DoodleBears commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Vain · project thread

Why

#2465 was tested on a phone (result and logcat). The foreground works, but in the background the phone still showed empty notifications posted by the FCM SDK (title/text are null, no actions). The cause: with render=app, the Host only dropped title/body but still sent sound, badge, channelId, categoryId and mutableContent. Expo therefore still built an FCM notification block, so onMessageReceived never ran in the background.

As a control, the test thread sent a truly data-only message (just to, priority and data). In the background the app drew it with the full conversation style, avatar and approval buttons, but the notification landed in expo_notifications_fallback_notification_channel.

Change outline

  • Host, delivery.ts: for an Android device with render=app, the Expo message now has only to, priority: 'high' and data. title, message, categoryId and badge all go inside data. iOS and older Android builds are unchanged.
  • App, ConversationHandlingDelegate: wraps the trigger in RequestsTrigger (a Parcelable that delegates toBundle), pinning the notification to the requests channel. The badge falls back to data.badge.
  • The README describes the new payload.

Verification

  • Push delivery tests and mobile push tests pass (34). The Android test now asserts the message has only the data, priority and to keys, and that the data carries the badge.
  • pnpm typecheck and oxfmt pass. CI compiles the Kotlin module.
  • Not yet done: a phone check of background notifications. It needs a new Android build and a Host update.

Generated by Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Android background Bot notifications now display conversation styling, avatars, and approval buttons instead of an empty system notification.
    • Android conversation notifications now preserve valid badge counts and consistently use the Requests notification channel.
    • Improved Android push handling for app-rendered notifications, including titles, badges, and conversation metadata.
  • Documentation

    • Clarified Android push payload requirements and notification behavior for background and older app versions.

The Host still sent sound, badge, channelId, categoryId and mutableContent
with render=app pushes, so Expo kept an FCM notification block and the
Firebase SDK drew an empty notification in the background. Those pushes now
carry only to, priority and data (badge moves into data), and the app pins
them to the requests channel.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JrtPca5pD72Gdx4CFkQdNi
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JrtPca5pD72Gdx4CFkQdNi
@coderabbitai

coderabbitai Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b599ea80-4276-4a50-98aa-5c823ef96a12
📥 Commits

Reviewing files that changed from the base of the PR and between b485d61 and bcade32.

📒 Files selected for processing: 5
  • apps/mobile/modules/conversation-notifications/README.md
  • apps/mobile/modules/conversation-notifications/android/src/main/java/expo/modules/conversationnotifications/ConversationNotificationsService.kt
  • changes/2485-android-background-push.md
  • packages/core/src/push/delivery.ts
  • packages/core/test/push-delivery.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 0 remain after this review.

📝 Walkthrough

Android app-rendered pushes now carry notification fields in the data payload. Android reconstructs those notifications with badge fallback and the requests channel. The payload test, module README, and release notes reflect the updated behavior.

Changes: Rendered Android push notifications

Layer / File(s) Summary
Rendered push payload construction
packages/core/src/push/delivery.ts, packages/core/test/push-delivery.test.ts, apps/mobile/modules/conversation-notifications/README.md, changes/2485-android-background-push.md
PushData.badge and ExpoMessage.badge are optional. Android app-rendered messages place title, body, badge, and optional category metadata in data. The test asserts the payload shape, and the README and release notes document the behavior.
Android notification reconstruction
apps/mobile/modules/conversation-notifications/android/src/main/java/expo/modules/conversationnotifications/ConversationNotificationsService.kt
Android preserves an existing badge or uses a nonnegative data.badge value. Reconstructed notifications wrap their original trigger with RequestsTrigger, which selects the requests channel and supports parceling.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant PushDelivery
  participant FCM
  participant ConversationHandlingDelegate
  participant RequestsTrigger
  PushDelivery->>FCM: Send rendered fields in data
  FCM->>ConversationHandlingDelegate: Deliver data-only push
  ConversationHandlingDelegate->>RequestsTrigger: Wrap original trigger
  RequestsTrigger->>ConversationHandlingDelegate: Provide requests channel
Loading

Possibly related issues

Merge Risk: ⚪ Minimal · up to bcade

No actionable merge-blocking issue was established. The reported on-device background-notification check remains to be completed as planned validation.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 3 files. (2 skipped: 2 … Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly identifies the main change: removing the Android notification block from app-drawn pushes.
Description check Passed The description explains the problem, links related discussion, outlines the changes, lists verification results, and identifies the untested phone check. It is mostly complete, although it does not e…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description explains the problem, links related discussion, outlines the changes, lists verification results, and identifies the untested phone check. It is mostly complete, although it does not explicitly document merge risk or the CI test-plan mode.

Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 3 files. (2 skipped: 2 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@DoodleBears
DoodleBears merged commit 2d0bf6e into main Oct 21, 2026
11 checks passed
DoodleBears added a commit that referenced this pull request Oct 21, 2026
…ground, avatars)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Copy link
Copy Markdown
Contributor Author

Android phone result on main 2d0bf6e (#2465 + #2483 + #2485): PASS, with one new issue (Xiaomi, Android 16 / HyperOS 3, fresh isolated QA Host and store build, device registered with render=app, battery saver unrestricted and autostart on, all Bots on the default generated avatar)

Evidence: 2465-android-push/phone-main (commit 5784528): 3-background-shade.png, 4-background-mira-dm.png, 5-foreground-shade.png, notification-fields.md

Background and foreground were each tested with a Mira DM reply, an approval (Nova in the background, Echo in the foreground), a secret-input request and a group channel reply:

Check Result
Drawn by the app (no FCM-Notification empty notifications) PASS
MessagingStyle, conversation shortcut, Conversations section PASS
Generated Bot avatars (Mira, Nova, Echo) PASS (#2483)
Group: "#QA Lounge" title with the channel image PASS
Approval: "允许这次 / 拒绝" actions PASS (not tapped)
Channel PASS: every notification, including the secret-input request, is in requests (no fallback channel)

New issue: an unread DM notification is removed by the badge push. In the background run, the Mira DM reply (posted 19:26:58) and the secret-input request were both removed in the same second, 19:27:46, the moment the Host sent a kind=badge push. Removing the secret-input notification is right, because it had just been submitted. The DM reply was still unread, so it should have stayed. A later DM reply with no badge push after it stayed in the shade. The same disappearance was seen once in the foreground on b485d61. Likely cause (inferred): on a badge push, the app removes every notification that isn't in the Host's current pending list, which also drops unread conversation replies.

Separately, on b485d61 one Mira DM reply was accepted by Expo (ticket ok) but never appeared. A resend worked, and the cause is unknown; it may be the same removal.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants