modules/BlueskyNSE/README.md
BlueskyNSE is an iOS Notification Service Extension that processes push notifications before they are displayed to the user. NSE stands for "Notification Service Extension", a native iOS app extension type.
This extension intercepts incoming push notifications and performs processing before displaying them:
When a push notification arrives on iOS, the system can invoke this extension to modify the notification content before displaying it. The extension runs in a separate process from the main app and has strict time limits (approximately 30 seconds) to complete its work.
The extension uses shared UserDefaults (via App Groups) to access preferences set by the main app:
group.app.bsky allows data sharing between the main app and the extensionNSEPrefsQueue) to prevent race conditions when multiple notifications arrive simultaneouslyNotificationService.didReceive() is calledreason field):
reason == "chat-message"): Applies custom DM sound if user preference playSoundChat is enabledcontentHandlerBadge counts are managed centrally by the extension:
expo-background-notification-handler moduleTwo sound types are supported:
dm.aiff sound file for chat messagesDM sound only plays if the user has enabled the playSoundChat preference in the main app's chat settings.
| File | Purpose |
|---|---|
NotificationService.swift | Main service extension implementation |
BlueskyNSE.entitlements | iOS entitlements configuration for App Group access |
Info.plist | Extension metadata and configuration |
Contains two main classes:
NotificationService: The main extension class that implements UNNotificationServiceExtension
didReceive(_:withContentHandler:): Processes incoming notificationsserviceExtensionTimeWillExpire(): Handles timeout scenariosNSEUtil: Singleton utility class for shared state management
UserDefaults instance for the App GroupThe extension requires the group.app.bsky App Group to be configured in:
BlueskyNSE.entitlements)The following preferences are shared between the main app and extension:
| Preference Key | Type | Purpose |
|---|---|---|
badgeCount | Int | Current badge count for app icon |
playSoundChat | Bool | Whether to play sound for chat notifications |
These are managed by the expo-background-notification-handler module in the main app.
The custom DM sound file (dm.aiff) must be included in the extension's bundle. The iOS project configuration handles copying this resource during the build.
The extension coordinates with the main app through:
reason field to determine notification typeUsers can control notification sounds via the Chat Settings screen (src/screens/Messages/Settings.tsx):
import {useBackgroundNotificationPreferences} from '../../../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
const {preferences, setPref} = useBackgroundNotificationPreferences()
setPref('playSoundChat', true) // Enable DM sounds
When modifying this extension:
contentHandler with modified content, even on errors