ReviewOS

craft-native/craft

iOS: notifications.schedule({ scheduleAt }) fires immediately, because neither scheduler reads scheduleAt

#261
Closed glennmichael123 opened this 9 days ago ·
9 days ago

Found while fixing #258.

The SDK's NotificationOptions says to schedule with scheduleAt (a timestamp), and its own example uses it:

await notifications.schedule({ title: 'Reminder', body: 'Time to take a break', scheduleAt: Date.now() + 3600000 })

notifications.schedule hands the options to craft.notifications.schedule, which posts scheduleNotification with them unchanged. The contract layer in CraftApp.swift only rewrites show, which adds its own scheduleAt: Date.now(). Neither iOS scheduler reads that field:

  • Swift: scheduleLocalNotification builds its trigger from timestamp (ms) or delay (ms).
  • Zig: triggerFrom in bridge_mobile_notifications.zig does the same.

So with no timestamp or delay, the trigger is nil, and the reminder meant for an hour from now fires immediately. Only callers who know the bridge's private field names (timestamp, delay) get a scheduled notification.

Fix: map scheduleAt onto the bridge's timestamp, either in the SDK or in the page contract's schedule, or have both schedulers read it. Mapping at one layer keeps the native readers unchanged. Add a test that fails without the fix. The mobile E2E harness's local-notification stage (#258) can check the timing end to end.

Sign in to comment on this issue.