Files
crowd-funder-for-time-pwa/doc/daily-notification-alignment-outline.md
Jose Olarte III 22c3ac80c2 feat(notifications): enable foreground notifications and rollover recovery
- iOS: set UNUserNotificationCenter delegate and implement willPresent
  so notifications show in foreground and DailyNotificationDelivered is
  posted for rollover; implement didReceive for tap handling; re-set
  delegate in applicationDidBecomeActive
- Android: move DailyNotificationReceiver and BootReceiver inside
  <application>; add NotifyReceiver; extend BootReceiver with
  LOCKED_BOOT_COMPLETED, MY_PACKAGE_REPLACED, directBootAware
- main.capacitor: import daily-notification-plugin at startup so
  plugin (and recovery) load on launch
- doc: add daily-notification-alignment-outline.md

Fixes foreground notifications not showing and rollover recovery;
Android receivers were previously declared outside <application>.
2026-01-29 21:10:34 +08:00

5.9 KiB
Raw Blame History

Daily Notification Plugin: Alignment Outline

Purpose: Checklist of changes/additions needed in this app to align with the test app (daily-notification-plugin/test-apps/daily-notification-test) so that:

  1. Rollover recovery (and rollover itself) works.
  2. Notifications show when the app is in the foreground (not only background/closed).
  3. Plugin loads at app launch so recovery runs after reboot without the user opening notification UI.

Reference: Test app at
/Users/aardimus/Sites/trentlarson/daily-notification-plugin_test/daily-notification-plugin/test-apps/daily-notification-test


1. iOS AppDelegate

File: ios/App/App/AppDelegate.swift

1.1 Add imports

  • import UserNotifications
  • Import the Daily Notification plugin framework (Swift module name: TimesafariDailyNotificationPlugin per this apps Podfile; test app uses DailyNotificationPlugin)

1.2 Conform to UNUserNotificationCenterDelegate

  • Add , UNUserNotificationCenterDelegate to the class declaration:
    class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate

1.3 Force-load plugin at launch

  • In application(_:didFinishLaunchingWithOptions:), before other setup, add logic to force-load the plugin class (e.g. _ = DailyNotificationPlugin.self or the class exposed by the TimesafariDailyNotificationPlugin pod) so that the plugins load() (and thus performRecovery()) runs at app launch, not only when JS first calls the plugin.

1.4 Set notification center delegate

  • In didFinishLaunchingWithOptions, set:
    UNUserNotificationCenter.current().delegate = self
  • In applicationDidBecomeActive, re-set the same delegate (in case Capacitor or another component clears it).

1.5 Implement userNotificationCenter(_:willPresent:withCompletionHandler:)

  • When a notification is delivered (including in foreground), read notification_id and scheduled_time from notification.request.content.userInfo.
  • Post rollover event:
    NotificationCenter.default.post(name: NSNotification.Name("DailyNotificationDelivered"), object: nil, userInfo: ["notification_id": id, "scheduled_time": scheduledTime])
  • Call completion handler with presentation options so the notification is shown in foreground, e.g.
    completionHandler([.banner, .sound, .badge]) (use .alert on iOS 13 if needed).

1.6 Implement userNotificationCenter(_:didReceive:withCompletionHandler:)

  • Handle notification tap/interaction; call completionHandler() when done.

2. Android Manifest

File: android/app/src/main/AndroidManifest.xml

2.1 Fix receiver placement

  • Move the two <receiver> elements (DailyNotificationReceiver and BootReceiver) inside the <application> block (e.g. after <activity>...</activity> and before <provider>...</provider>).
  • Remove the stray second </application> so there is a single <application>...</application> containing activity, receivers, and provider.

2.2 (Optional) Add NotifyReceiver

  • If the plugins Android integration expects NotifyReceiver for alarm-based delivery, add a <receiver> for com.timesafari.dailynotification.NotifyReceiver inside <application> (see test app manifest for exact declaration).

2.3 (Optional) BootReceiver options

  • Consider aligning with test app: add android:directBootAware="true", android:exported="true", and intent-filter actions LOCKED_BOOT_COMPLETED, MY_PACKAGE_REPLACED, PACKAGE_REPLACED if you need the same boot/update behavior.

File: src/main.capacitor.ts (or the main entry used for native builds)

3.1 Load plugin at startup

  • Add a top-level import or an early call that touches the Daily Notification plugin so the JS side loads it at app startup (e.g. import "@timesafari/daily-notification-plugin" or a small init that calls getRebootRecoveryStatus() or configure()).
    This ensures the plugin is loaded as soon as the app runs; together with the iOS force-load in AppDelegate, recovery runs at launch.

4. Plugin configuration (optional)

  • If you use the native fetcher or need plugin config (db path, storage, etc.), call DailyNotification.configure() and/or configureNativeFetcher() when appropriate (e.g. after login or when notification UI is first used), similar to the test apps configureNativeFetcher() in HomeView.

5. Summary table

Area Change / addition
iOS AppDelegate Conform to UNUserNotificationCenterDelegate; set delegate; force-load plugin; implement willPresent (post DailyNotificationDelivered + show in foreground) and didReceive.
Android manifest Move DailyNotificationReceiver and BootReceiver inside <application>; remove duplicate </application>; optionally add NotifyReceiver and BootReceiver options.
main.capacitor.ts Optionally import or call plugin at startup so it (and recovery) load at launch.
Plugin config Optionally call configure() / configureNativeFetcher() where appropriate.

6. Verification

After making the changes:

  • iOS: Build and run; trigger a daily notification and confirm it appears when the app is in the foreground.
  • iOS: Confirm rollover (next days schedule) still occurs after a notification fires (check logs for DNP-ROLLOVER / DailyNotificationDelivered).
  • iOS: Restart the app (or reboot) and confirm recovery runs without opening the notification settings screen (e.g. logs show plugin load and recovery).
  • Android: Build and run; confirm receivers are registered (no manifest errors) and that notifications and boot recovery behave as expected.