fix(ios): New Activity dual notification – handle updateStarredPlans and BGTaskScheduler errors
- Treat updateStarredPlans as optional: catch UNIMPLEMENTED and continue to scheduleDualNotification so missing native method no longer blocks scheduling. - Show specific toast when BGTaskSchedulerErrorDomain error 1 occurs (e.g. Simulator): explain that a real device and Background App Refresh are required. - Add PluginHeaders diagnostic in AccountViewView and main.capacitor.ts to debug UNIMPLEMENTED (log DNP methods at call time and at launch). - Fix main.capacitor.ts build: use CapacitorWindow type and safe cap assignment so vite build --mode capacitor succeeds. - Docs: add UNIMPLEMENTED troubleshooting and updateStarredPlans note in plugin-feedback-ios-scheduleDualNotification.md; add section 8.3 in notification-new-activity-lay-of-the-land.md. - Lockfile updates (package-lock.json, Podfile.lock).
This commit is contained in:
@@ -209,6 +209,12 @@ Comparison with the **daily-notification-plugin** repo (e.g. `daily-notification
|
||||
- **iOS `scheduleDailyNotification` and stable `id`:** On **Android**, the plugin uses `options.getString("id")` as the stable `scheduleId` for “one per day” semantics and cleanup. On **iOS**, the implementation in the repo was observed to build notification content with an internally generated id (e.g. `daily_<timestamp>`) and not obviously use the app-provided `id` from the call. If the app ever relies on a stable id on iOS for the single reminder (e.g. to cancel or replace only that reminder), it’s worth confirming in the plugin’s iOS code whether the call’s `id` is read and used; if not, consider requesting or contributing a change so iOS also uses the app-provided id for consistency with Android.
|
||||
- **Dual schedule and content fetch:** The plugin’s dual schedule runs the content-fetch job on its cron and then the user notification at the configured time; our config uses a 5-minute gap and `relationship.contentTimeout` / `fallbackBehavior: "show_default"`. The native fetcher is invoked by the plugin’s background layer when the content-fetch schedule fires; we don’t rely on JS `callbacks` in the config (we pass `callbacks: {}`). That matches the “native fetcher does the work” design.
|
||||
|
||||
### 8.3 Summary
|
||||
### 8.3 iOS `UNIMPLEMENTED` on `scheduleDualNotification` (other methods work)
|
||||
|
||||
If iOS logs `scheduleNewActivityDualNotification failed: {"code":"UNIMPLEMENTED"}` while `configureNativeFetcher` succeeds, Capacitor is often rejecting the call in **JavaScript** because `scheduleDualNotification` is missing from `window.Capacitor.PluginHeaders` for `DailyNotification` (stale **Pods / Xcode binary** after upgrading the plugin). **Not** usually a missing Swift handler if `node_modules` already lists the method in `pluginMethods`.
|
||||
|
||||
**Recovery:** `npx cap sync ios`, `cd ios/App && pod install`, Xcode **Clean Build Folder**, rebuild. See **`doc/plugin-feedback-ios-scheduleDualNotification.md`** (troubleshooting section).
|
||||
|
||||
### 8.4 Summary
|
||||
|
||||
The plugin repo aligns with how we use it for New Activity (dual schedule + native fetcher, no generic polling, exact alarm optional). The main follow-ups are: (1) clarify or align `cancelDailyReminder` argument shape in the plugin if needed for typing/tooling, and (2) confirm on iOS whether `scheduleDailyNotification` uses the app-provided `id` for stable single-reminder semantics.
|
||||
|
||||
@@ -6,6 +6,31 @@
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting: `UNIMPLEMENTED` on iOS (Capacitor 6)
|
||||
|
||||
If **`configureNativeFetcher`** (or other DailyNotification methods) work but **`scheduleDualNotification`** still fails with **`{"code":"UNIMPLEMENTED"}`** and you **do not** see a native log line like `To Native -> DailyNotification scheduleDualNotification`, the failure is often **not** missing Swift code—it is **Capacitor’s JavaScript layer** rejecting the call because the method is **not listed** in `window.Capacitor.PluginHeaders` for `DailyNotification`. Those headers are built at runtime from the **compiled** plugin’s `pluginMethods` list (`CAPBridgedPlugin`).
|
||||
|
||||
**Fix in the consuming app (usual cause: stale Pods / binary):**
|
||||
|
||||
1. Ensure `node_modules/@timesafari/daily-notification-plugin` includes `scheduleDualNotification` in `DailyNotificationPlugin.swift`’s `pluginMethods` (v2.1.0+).
|
||||
2. From the project root: `npx cap sync ios`
|
||||
3. `cd ios/App && pod install` (or delete `Pods` + `Podfile.lock` and `pod install` if upgrading the plugin).
|
||||
4. Xcode: **Product → Clean Build Folder**, then rebuild and run on device/simulator.
|
||||
|
||||
**Verify:** Safari → Develop → attach to the app WebView → Console: inspect `window.Capacitor.PluginHeaders` and confirm the `DailyNotification` entry’s `methods` array includes `{ name: "scheduleDualNotification", ... }`.
|
||||
|
||||
If a full clean rebuild still doesn't fix it, clear Xcode's **system** DerivedData (quit Xcode, run `rm -rf ~/Library/Developer/Xcode/DerivedData/*TimeSafari*`, reopen and rebuild). On launch the app logs `[Capacitor] DNP PluginHeaders methods: [...]`; if that list omits `scheduleDualNotification`, the native binary is still stale.
|
||||
|
||||
If the method **is** present in headers but scheduling still fails, debug the Swift implementation (reject message, BG tasks, etc.).
|
||||
|
||||
### Misleading `UNIMPLEMENTED` before `scheduleDualNotification`
|
||||
|
||||
Capacitor’s `registerPlugin` proxy returns a **callable stub for every property name**. So `if (DailyNotification?.updateStarredPlans)` is **always truthy** even when iOS does not expose `updateStarredPlans` in `pluginMethods`. Calling that stub throws **`UNIMPLEMENTED`** in JS **before** any `To Native -> DailyNotification scheduleDualNotification` line appears—so logs look like “dual schedule is unimplemented” when the real failure was **`updateStarredPlans`**.
|
||||
|
||||
**Consuming-app fix:** treat `updateStarredPlans` as optional: catch `UNIMPLEMENTED` and continue, or only call after verifying the method name exists on `PluginHeaders` for `DailyNotification`. If the plugin adds `updateStarredPlans` natively later, starred-plan filtering will start working without app changes.
|
||||
|
||||
---
|
||||
|
||||
## Current behavior
|
||||
|
||||
- The **consuming app** calls `DailyNotification.scheduleDualNotification({ config })` from TypeScript when the user turns on “New Activity Notification” and picks a time (native iOS).
|
||||
|
||||
Reference in New Issue
Block a user