Upgrading to v5
What's new in native-notify v5, and how to upgrade — including the one breaking change to the five follow helpers.
native-notify v5 is a drop-in upgrade for most apps. There is exactly one breaking change — the five follow helpers now return structured result objects (see below).
What's new in v5
New exports:
| Export | What it does |
|---|---|
NativeNotify.init({ appId, appToken }) | Set your credentials once at module scope — every function picks them up. |
<NativeNotifyProvider appId appToken> | The same for hooks and components, as a React provider for your app tree (plain functions read NativeNotify.init()). |
useNativeNotify() | Read the active { appId, appToken } config inside a component. |
useNativeNotifyPress<T>() | Cold-start-safe notification tap handling — see Push Data & Taps. |
registerForPushNotificationsAsync() | The raw token-minting flow, exported — never throws, it reports { status, reason, expoPushToken, ... }. |
getNotificationInboxPage() / getIndieNotificationInboxPage() | One page of inbox rows plus the server's total row count — { rows, total }. |
Other additions that do not break anything:
registerNNPushToken(appId, appToken, options)gains an optional third argument:{ onRegistered, onError, watchTokenRotation }.appId/appTokenare optional everywhere — when omitted, plain functions (registerIndieID, the follow and inbox functions, the send helpers) resolve them fromNativeNotify.init(), and hooks and components from<NativeNotifyProvider>, thenNativeNotify.init().- The Notification Inbox syncs the unread count to the app icon badge (
syncBadge, defaulttrue), and both inboxes support exact pagination via the new page functions.
Breaking change: the follow helpers
These five helpers now return a structured NativeNotifyActionResult instead of a plain string:
registerFollowMasterIDregisterFollowerIDpostFollowingIDunfollowMasterIDupdateFollowersList
interface NativeNotifyActionResult {
success: boolean;
status:
| 'registered'
| 'already_registered'
| 'posted'
| 'already_posted'
| 'unfollowed'
| 'not_following'
| 'removed'
| 'not_found'
| 'error';
message: string; // the string the previous versions returned
error?: any; // the underlying failure, when status is 'error'
}
Before v5 (a plain string):
const result = await registerFollowMasterID('master-id', appId, appToken);
if (result === 'Follow Master Indie ID already registered.') {
// ...
}
In v5 (an object):
const result = await registerFollowMasterID('master-id', appId, appToken);
if (result.success || result.status === 'already_registered') {
// registered now, or it already was — branch on result.status for details
}
if (result.status === 'error') {
console.warn(result.message, result.error);
}
message still contains the text the previous versions returned, so upgrading is mostly a matter of replacing string checks with result.status (or result.success). The practical improvement: network failures now surface as status: 'error' with the underlying error attached, instead of being misreported as "already registered".
v5.1 — Analytics (additive, no breaking changes)
Version 5.1 adds the opt-in analytics features: trackScreen / useNativeNotifyScreenTracking (screen views), session tracking, push-open reporting, the stable deviceId option, and the analytics config flags on NativeNotify.init and registerNNPushToken.
Everything is off by default — nothing changes for an app that doesn't opt in. See Analytics to get started.
v5.1.1 — token-rotation stability
Version 5.1.1 hardens the token-rotation listener: it skips no-op same-token events, checks at most once per minute, never overlaps, and only re-registers when the token payload actually changed. No API changes — upgrading is recommended for apps using 5.0.x or 5.1.0.
v5.2 — inbox read state, rich fields, Android channels (additive)
Version 5.2 surfaces the rest of the server-capability wave. Every change is additive — existing calls keep making their exact same requests. Get it once it is published with:
npm install native-notify@^5.2.0
Per-notification inbox read state. The prebuilt inbox accepts perNotificationRead (off by default): pages are fetched with each row's real read flag and rows are marked read as they are opened, instead of the legacy "mark the whole inbox read on fetch". For custom UIs, the page functions take { perNotification: true } as the argument after take and skip — getNotificationInboxPage(appId, appToken, take, skip, { perNotification: true }) / getIndieNotificationInboxPage(subId, appId, appToken, take, skip, { perNotification: true }) — and two new helpers mark a single row read: markMassNotificationRead(notificationId, appId?, appToken?) / markIndieNotificationRead(notificationId, subId, appId?, appToken?) (they resolve false without sending anything when notificationId is missing — the endpoint would otherwise mark the whole inbox read). useNotificationInbox() also returns perNotificationRead and markNotificationRead().
Rich-field send helpers. sendMassNotification, sendIndieNotification, sendIndieGroupNotification, and sendNotificationToFollowers pass the modern Expo message fields — subtitle, badge, ttl, interruptionLevel, categoryId, channelId, collapseId, contentAvailable, mutableContent, sound — straight through to every send path, and setAndroidNotificationChannel() creates the Android channel a channelId refers to. See Rich Notifications.
New exported types: RichPushFields, SendNotificationOptions, AndroidNotificationChannelOptions, and PerNotificationReadOptions.
Fixes in 5.2 (they only change requests for apps that turned analytics on — those apps now send the events they asked for):
- Analytics reports (screens, sessions, opens) also work when the ids are passed only to
registerNNPushToken(appId, appToken, { analytics })— 5.1 read them fromNativeNotify.init()only and dropped every report otherwise. The flags and ids from that call now apply before the components under it mount, so a cold-start tap or the first tracked screen is no longer lost. useNativeNotifyScreenTracking(() => currentRouteName)(React Navigation, or any navigator other than Expo Router) tracks every screen change — 5.1 tracked only the first screen.sendMassNotificationstamps the inbox date, so its inbox rows carry one.