Bluesky app fork with some witchin' additions 馃挮
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

1# expo-background-notification-handler 2 3A custom Expo module for managing shared notification preferences and handling background notifications in the Bluesky Social app. This module enables communication between the main app and notification service extensions through shared storage. 4 5## Purpose 6 7This module solves a critical problem in native notification handling: notification service extensions run in a separate process from the main app and cannot directly access React Native state or APIs. The module provides a bridge by storing notification preferences in shared storage that both the main app and notification service extension can access. 8 9The primary use case is storing user preferences (like notification sound settings) while the app is foregrounded or backgrounded, minimizing the need for background fetches when processing notifications. 10 11## Platform Support 12 13- **iOS**: Full support via UserDefaults with App Groups 14- **Android**: Full support via SharedPreferences 15- **Web**: Stub implementation (no-op) 16 17## Architecture 18 19### iOS Implementation 20 21Uses iOS App Groups (`group.app.bsky`) to share UserDefaults between the main app and the notification service extension. This allows the notification service extension to read preferences set by the main app without launching the app. 22 23**Key Files:** 24- `ios/ExpoBackgroundNotificationHandlerModule.swift` - Native module implementation 25- `ios/ExpoBackgroundNotificationHandler.podspec` - CocoaPods specification 26 27### Android Implementation 28 29Uses SharedPreferences with Firebase Cloud Messaging (FCM) to handle background notifications. The module tracks app foreground/background state and conditionally processes notifications based on whether the app is foregrounded. 30 31**Key Files:** 32- `android/src/main/java/expo/modules/backgroundnotificationhandler/ExpoBackgroundNotificationHandlerModule.kt` - Expo module definition 33- `android/src/main/java/expo/modules/backgroundnotificationhandler/NotificationPrefs.kt` - SharedPreferences wrapper 34- `android/src/main/java/expo/modules/backgroundnotificationhandler/BackgroundNotificationHandler.kt` - Notification processing logic 35- `android/src/main/java/expo/modules/backgroundnotificationhandler/BackgroundNotificationHandlerInterface.kt` - Interface for showing notifications 36- `android/build.gradle` - Build configuration 37 38### TypeScript/React API 39 40**Key Files:** 41- `index.ts` - Module entry point 42- `src/ExpoBackgroundNotificationHandlerModule.ts` - Native module binding (iOS/Android) 43- `src/ExpoBackgroundNotificationHandlerModule.web.ts` - Web stub 44- `src/ExpoBackgroundNotificationHandler.types.ts` - TypeScript type definitions 45- `src/BackgroundNotificationHandlerProvider.tsx` - React Context provider for preferences 46 47## Stored Preferences 48 49The module manages the following notification preferences: 50 51```typescript 52{ 53 playSoundChat: boolean, // Currently exposed to TypeScript 54 playSoundFollow: boolean, // Native only (not yet exposed) 55 playSoundLike: boolean, // Native only (not yet exposed) 56 playSoundMention: boolean, // Native only (not yet exposed) 57 playSoundQuote: boolean, // Native only (not yet exposed) 58 playSoundReply: boolean, // Native only (not yet exposed) 59 playSoundRepost: boolean, // Native only (not yet exposed) 60 mutedThreads: [String: [String]], // iOS only 61 badgeCount: number // iOS only 62} 63``` 64 65Default values are initialized when the module is created, with most sound preferences defaulting to `false` except `playSoundChat` which defaults to `true`. 66 67## API 68 69### Core Methods 70 71```typescript 72// Get all preferences 73getAllPrefsAsync(): Promise<BackgroundNotificationHandlerPreferences> 74 75// Get individual values 76getBoolAsync(forKey: string): Promise<boolean> 77getStringAsync(forKey: string): Promise<string> 78getStringArrayAsync(forKey: string): Promise<string[]> 79 80// Set individual values 81setBoolAsync(forKey: string, value: boolean): Promise<void> 82setStringAsync(forKey: string, value: string): Promise<void> 83setStringArrayAsync(forKey: string, value: string[]): Promise<void> 84 85// Array manipulation 86addToStringArrayAsync(forKey: string, value: string): Promise<void> 87removeFromStringArrayAsync(forKey: string, value: string): Promise<void> 88addManyToStringArrayAsync(forKey: string, value: string[]): Promise<void> 89removeManyFromStringArrayAsync(forKey: string, value: string[]): Promise<void> 90 91// Badge count (iOS only) 92setBadgeCountAsync(count: number): Promise<void> 93``` 94 95### React Context API 96 97The module provides a React Context provider for managing preferences in the app: 98 99```typescript 100import { 101 BackgroundNotificationPreferencesProvider, 102 useBackgroundNotificationPreferences, 103} from 'expo-background-notification-handler/src/BackgroundNotificationHandlerProvider' 104 105function App() { 106 return ( 107 <BackgroundNotificationPreferencesProvider> 108 <YourApp /> 109 </BackgroundNotificationPreferencesProvider> 110 ) 111} 112 113function SettingsScreen() { 114 const {preferences, setPref} = useBackgroundNotificationPreferences() 115 116 return ( 117 <Toggle 118 value={preferences.playSoundChat} 119 onValueChange={(value) => setPref('playSoundChat', value)} 120 /> 121 ) 122} 123``` 124 125## Android Notification Handling 126 127The Android implementation includes logic for processing notifications while the app is backgrounded: 128 129- **Chat messages**: Applies custom notification channels based on `playSoundChat` preference 130 - Sound enabled: Uses `chat-messages` channel (or `dm.mp3` sound on older Android) 131 - Sound disabled: Uses `chat-messages-muted` channel 132 133- **Other notification types**: On Android Oreo+ (API 26+), assigns notifications to channels based on reason: 134 - Supported reasons: `like`, `repost`, `follow`, `mention`, `reply`, `quote`, `like-via-repost`, `repost-via-repost`, `subscribed-post` 135 - Each reason maps to its corresponding notification channel 136 137When the app is foregrounded, the module defers to `expo-notifications` for notification handling. 138 139## Configuration 140 141### iOS 142 143Requires App Group entitlement configured in Xcode: 144- App Group ID: `group.app.bsky` 145 146### Android 147 148Requires Firebase Cloud Messaging (FCM) integration: 149- Dependency: `com.google.firebase:firebase-messaging-ktx:24.0.0` 150- SharedPreferences name: `xyz.blueskyweb.app` 151 152## Usage in the App 153 154The module is used to: 155 1561. Store notification preferences that need to be accessed by notification service extensions 1572. Track app foreground/background state on Android 1583. Process and mutate notification payloads based on user preferences before display 1594. Manage notification badge counts on iOS 1605. Handle thread muting and other notification filtering logic 161 162By keeping preferences in shared storage, the notification service extension can make intelligent decisions about notification presentation without waking up the React Native runtime or making network requests.