Skip to content

feat(inbox): let apps configure visual inbox accessibility labels - #658

Merged
mahmoud-elmorabea merged 5 commits into
mainfrom
mbl-2366-inbox-a11y-labels
Sep 15, 2026
Merged

mahmoud-elmorabea merged 5 commits into
mainfrom
mbl-2366-inbox-a11y-labels

Conversation

@mahmoud-elmorabea

@mahmoud-elmorabea mahmoud-elmorabea commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Exposes the visual notification inbox accessibility labels through the React Native config, so host apps supply their own localized strings instead of the SDK shipping English text.

Fixes MBL-2366

Notes

  • iOS needs no native change: the whole config object already reaches MessagingInAppConfigBuilder.build(from:), which parses these keys.
  • Android builds the labels and converts the {count} template into the (Int) -> String closure the SDK takes — the bridge carries data, not callbacks.
  • A bellWithUnreadCount missing its {count} placeholder is announced verbatim with no count. param-validation warns about it rather than throwing, since a label typo must degrade an announcement and never fail initialization. The check lives in JavaScript because neither native layer can report it where the developer would see it: Android would log at debug, which the default ERROR level discards, and iOS does not check at all.
  • Pins bumped to the native releases that added this config: iOS 4.8.0, Android 4.21.1.
  • jest.config.js now defines __DEV__, which the bare node test environment lacks; without it any test reaching assert.* throws a ReferenceError instead of exercising the validation.
  • The example app supplies labels at its single initialize() call rather than storing them in the editable Settings config, which leaves Settings and storage untouched. No other sample changes: the inbox screen already exists on main, and the empty state is reached by logging in with a profile that has no inbox messages.

Verification

  • npm test — 25 passed (8 new)
  • npx tsc --noEmit, eslint, npx api-extractor run all clean

Not covered

The Android mapper has no unit test. This package has no Kotlin test source set and no CI job that runs Gradle unit tests, so adding one is its own change rather than a rider on this PR. The equivalent mapper is covered on the Flutter side, and the placeholder validation — the part with real logic — is now in JavaScript, where Jest covers it.

🤖 Generated with Claude Code

The native SDKs stopped shipping hardcoded English labels for the visual
notification inbox, so apps now supply their own. Expose that config through
the wrapper: four optional strings on `inApp`, with the unread-count label as
a `{count}` template because the bridge carries data but not callbacks.

iOS needs no native change — the whole config already reaches
MessagingInAppConfigBuilder.build(from:), which parses these keys. Android
builds the labels and converts the template into the closure the SDK expects.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Sample app builds 📱

Below you will find the list of the latest versions of the sample apps. It's recommended to always download the latest builds of the sample apps to accurately test the pull request.


Builds are in progress. This comment will be updated when they finish.

  • iOS FCM: 658.5.0 (29824635)
  • Android APN: 658.5.0 (29824635)

mahmoud-elmorabea and others added 4 commits September 12, 2026 01:45
Review of the wrapper PRs found two ways the example lost the accessibility
labels it exists to demonstrate:

- loadFromStorage merged persisted config over defaults shallowly, so any
  device that had ever opened Settings replaced the defaults' `inApp` wholesale
  and demonstrated the unlabeled inbox.
- Toggling in-app messaging off clears `inApp`, so re-enabling had nothing to
  spread and dropped the labels permanently.

Also corrects the `loadingIndicator` doc, which described Android's behaviour
as if it were cross-platform: on iOS an unset label makes the spinner not an
accessibility element at all, so VoiceOver skips it rather than announcing a
progress role.

Adds a debug log when `bellWithUnreadCount` carries no `{count}` placeholder —
a typo like `{COUNT}` or `%d` is otherwise read aloud verbatim with the count
never announced, and nothing else in the stack can surface that.

Pins Android to 4.21.1, which adds an in-app open-url query fix at no cost, and
narrows the test docstring to what it actually verifies: the JavaScript half,
not the native key names.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The empty state is driven entirely by SDK data — NotificationInboxView takes no
props that could force it — so seeing the dimmed bell previously meant finding a
profile that happened to have no messages. Identifying a fresh random user
reaches it through the real SDK path instead of faking a view state.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…nges

The mistyped-placeholder warning lived in the Android mapper at debug level,
which the default ERROR log level discards, and iOS had no check at all — so a
typo like `{COUNT}` produced a screen reader announcing the template verbatim
with no diagnostic on either platform. The check now runs in param-validation
alongside the other config checks, warning rather than throwing since a label
typo must not fail initialization.

The sample app now supplies the labels at its single initialize() call instead
of storing them in the editable Settings config, which keeps Settings and
storage untouched. Drops the debug identify button: testers reach the empty
state by logging in with a profile that has no inbox messages.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…alize

The previous commit put the labels in `onSetConfig`, describing it as the
sample's single initialize() call. It is not called at all: the callback is
defined, typed and given a no-op default, but no screen consumes it. The live
paths are app start, which initializes from stored config, and the Settings
save. Native initialize ignores every call after the first, so the app-start
path won and the labels never reached the SDK — the sample demonstrated an
unlabeled inbox on every launch.

Moves the labels into a shared helper and applies it at every initialize call
site, the unused callback included, so wiring that callback up later cannot
silently lose them again. They stay out of the persisted, user-editable
Settings config.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@mahmoud-elmorabea
mahmoud-elmorabea marked this pull request as ready for review September 15, 2026 12:39
@mahmoud-elmorabea
mahmoud-elmorabea requested a review from a team as a code owner September 15, 2026 12:39
@mahmoud-elmorabea
mahmoud-elmorabea merged commit 1d911c2 into main Sep 15, 2026
19 checks passed
@mahmoud-elmorabea
mahmoud-elmorabea deleted the mbl-2366-inbox-a11y-labels branch September 15, 2026 21:36
cio-mobile-release Bot pushed a commit that referenced this pull request Sep 15, 2026
## [6.11.0](6.10.0...6.11.0) (2026-09-15)

### Features

* **inbox:** let apps configure visual inbox accessibility labels ([#658](#658)) ([1d911c2](1d911c2))
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