Priority
Plugin(s) affected
@capacitor/local-notifications
Current problem behavior
Every JS call into LocalNotifications (e.g. LN.requestPermissions(), LN.checkPermissions(), LN.schedule()) rejects on iOS with:
Unhandled Promise Rejection: Error: "LocalNotifications.then()" is not implemented on ios
The .then() variant of the "not implemented" error (rather than the expected LN.requestPermissions() is not implemented) suggests Capacitor's proxy is falling back to the web implementation, which for LocalNotifications uses a chunked async import(...).then(e => new e.LocalNotificationsWeb). Something in that async chain routes back through the native bridge and fails.
No iOS permission dialog ever appears. Notifications never fire.
Expected behavior
LN.requestPermissions() shows the iOS permission dialog, resolves to a permission state, and LN.schedule() queues notifications with iOS.
Steps to reproduce
- Capacitor 8.4.2 iOS app with SPM setup (
npx cap add ios --packagemanager SPM)
npm install @capacitor/local-notifications@8.2.1
npx cap sync ios
- Add
NSUserNotificationsUsageDescription to Info.plist
- Call
LocalNotifications.requestPermissions() from JS
- Observe the "not implemented" error in the console; no permission dialog appears
What we've verified (rules out common causes)
- Plugin class IS in the compiled binary —
strings ios/App/App/Build/.../App.debug.dylib | grep LocalNotificationsPlugin returns matches. Dead-code stripping ruled out.
capacitor.config.json packageClassList contains "LocalNotificationsPlugin" — autogenerated by cap sync, unmodified.
- JS bundle correctly registers the plugin proxy —
registerPlugin("LocalNotifications", { web: () => import(...).then(...) }) appears in the built ESM chunk.
- 6 other Capacitor npm plugins in the SAME setup auto-register fine and work:
@capacitor/preferences, @capacitor/browser, @capacitor/camera, @capgo/capacitor-social-login, @ebarooni/capacitor-calendar, @aparajita/capacitor-biometric-auth. Same auto-discovery mechanism, same Info.plist workflow, same everything. Only @capacitor/local-notifications fails.
What we tried that didn't help
- Skipping
checkPermissions() and calling requestPermissions() directly (in case of an iOS 26 checkPermissions hang) — same "not implemented" result.
- Force-linking plugin imports in
AppDelegate.swift — no effect (class was already in the binary).
- Custom
MyViewController: CAPBridgeViewController subclass with bridge?.registerPluginInstance(LocalNotificationsPlugin()) in capacitorDidLoad — capacitorDidLoad was verified never called (NSLog missing from Xcode Debug Area) even with @objc(MyViewController) on the class and customClass="MyViewController" customModule="App" customModuleProvider="target" in the storyboard.
- Uninstall + reinstall + Clean Build Folder — no change.
Environment
- @capacitor/core: 8.4.2
- @capacitor/local-notifications: 8.2.1
- @capacitor/cli: 8.4.2
- @capacitor/ios: 8.4.2
- iOS deployment target: 17.0
- Xcode: 26.6
- Device: iPhone 17 Pro Max, iOS 26.6
Ask
Is there a reason @capacitor/local-notifications's auto-discovery via packageClassList + NSClassFromString("LocalNotificationsPlugin") fails when the class is present in the binary, and the other Capacitor npm plugins in the same setup succeed? Any known workaround for Capacitor 8.4.2 SPM users?
Priority
Plugin(s) affected
@capacitor/local-notifications
Current problem behavior
Every JS call into
LocalNotifications(e.g.LN.requestPermissions(),LN.checkPermissions(),LN.schedule()) rejects on iOS with:The
.then()variant of the "not implemented" error (rather than the expectedLN.requestPermissions() is not implemented) suggests Capacitor's proxy is falling back to the web implementation, which for LocalNotifications uses a chunked asyncimport(...).then(e => new e.LocalNotificationsWeb). Something in that async chain routes back through the native bridge and fails.No iOS permission dialog ever appears. Notifications never fire.
Expected behavior
LN.requestPermissions()shows the iOS permission dialog, resolves to a permission state, andLN.schedule()queues notifications with iOS.Steps to reproduce
npx cap add ios --packagemanager SPM)npm install @capacitor/local-notifications@8.2.1npx cap sync iosNSUserNotificationsUsageDescriptionto Info.plistLocalNotifications.requestPermissions()from JSWhat we've verified (rules out common causes)
strings ios/App/App/Build/.../App.debug.dylib | grep LocalNotificationsPluginreturns matches. Dead-code stripping ruled out.capacitor.config.jsonpackageClassListcontains"LocalNotificationsPlugin"— autogenerated bycap sync, unmodified.registerPlugin("LocalNotifications", { web: () => import(...).then(...) })appears in the built ESM chunk.@capacitor/preferences,@capacitor/browser,@capacitor/camera,@capgo/capacitor-social-login,@ebarooni/capacitor-calendar,@aparajita/capacitor-biometric-auth. Same auto-discovery mechanism, same Info.plist workflow, same everything. Only@capacitor/local-notificationsfails.What we tried that didn't help
checkPermissions()and callingrequestPermissions()directly (in case of an iOS 26checkPermissionshang) — same "not implemented" result.AppDelegate.swift— no effect (class was already in the binary).MyViewController: CAPBridgeViewControllersubclass withbridge?.registerPluginInstance(LocalNotificationsPlugin())incapacitorDidLoad—capacitorDidLoadwas verified never called (NSLog missing from Xcode Debug Area) even with@objc(MyViewController)on the class andcustomClass="MyViewController" customModule="App" customModuleProvider="target"in the storyboard.Environment
Ask
Is there a reason
@capacitor/local-notifications's auto-discovery viapackageClassList+NSClassFromString("LocalNotificationsPlugin")fails when the class is present in the binary, and the other Capacitor npm plugins in the same setup succeed? Any known workaround for Capacitor 8.4.2 SPM users?