Stop_smoking_website_ver2/ios_pwa_push_notifications.md
2026-01-27 17:36:48 -07:00

2.6 KiB

Case Study: PWA Push Notifications on iOS (Cloudflare Workers)

Implementing push notifications for iOS PWAs on Cloudflare Workers requires addressing several unique runtime and OS-specific constraints.

🛠 Tech Stack

  • Framework: Next.js (OpenNext)
  • Runtime: Cloudflare Workers (Edge)
  • Database: Cloudflare D1
  • Library: web-push

🚀 Key Implementation Details

1. Edge Runtime Compatibility (Crucial)

The standard webPush.sendNotification() relies on Node.js's https module, which is not supported in Cloudflare Workers. Solution: Use webPush.generateRequestDetails() to create the encrypted payload, and then send it using the Edge-native fetch.

const requestDetails = await webPush.generateRequestDetails(
    { endpoint, keys: { p256dh, auth } },
    JSON.stringify(payload)
);

const response = await fetch(requestDetails.endpoint, {
    method: 'POST',
    headers: requestDetails.headers,
    body: requestDetails.body // Note: This is a Buffer/ArrayBuffer
});

2. VAPID Key Generation

VAPID keys must be generated using the native crypto module to avoid dependency issues in restricted environments.

3. iOS PWA Manifest Requirements

For "Add to Home Screen" to trigger the correct push capabilities:

  • display: standalone or fullscreen is required.
  • The user must trigger the permission request via a direct interaction (e.g., clicking an "Enable" button).

4. Background Cron Trigger

Since Next.js API routes on Cloudflare don't support long-running processes, a separate Cron Worker is needed to ping the API every minute.

  • Workflow: Cron Worker (triggers every minute) -> Ping /api/cron/reminders -> App logic checks D1 -> App sends push via fetch.

5. Local Timezone Management

iOS background alerts are only useful if they fire at the user's local time.

  • The fix: Explicitly capture the user's timezone on the client (Intl.DateTimeFormat().resolvedOptions().timeZone) and save it to the database.
  • Verification: Ensure the backend API updates the timezone column alongside reminder settings to avoid defaulting to UTC.

💡 Lessons Learned

  • Minute-Precision: For hourly reminders, sync the minute value (e.g., :18 past the hour) between the UI and the backend checker.
  • Visual Feedback: iOS users are often skeptical of web-based push. Providing a "Test & Sync" button that sends an immediate notification builds trust and verifies the connection.
  • Authentication: Protect the cron endpoint with a CRON_SECRET header to prevent unauthorized trigger pings.