Capacitor: iOS PushNotifications.register listener not firing

Created on 28 Mar 2020  路  14Comments  路  Source: ionic-team/capacitor

Bug Report

Capacitor Version

npx cap doctor output:

馃拪   Capacitor Doctor  馃拪 

Latest Dependencies:

  @capacitor/cli: 1.5.2

  @capacitor/core: 1.5.2

  @capacitor/android: 1.5.2

  @capacitor/ios: 1.5.2

Installed Dependencies:

  @capacitor/android not installed

  @capacitor/cli 1.5.2

  @capacitor/ios 1.5.2

  @capacitor/core 1.5.2


  Found 0 Capacitor plugins for ios:
[success] iOS looking great! 馃憣

Affected Platform(s)

  • [ ] Android
  • [x] iOS
  • [ ] Electron
  • [ ] Web

Current Behavior


When I call PushNotifications.register() and listen for the function to resolve neither registration nor registrationError are called.

On my phone I see the permission popup and I hit "Allow" or "Don't Allow". In the XCode debugger I see the register is happening natively, but my callback is never triggered.

鈿★笍  To Native ->  PushNotifications register 130675206
鈿★笍  [log] - Attempt register
鈿★笍  To Native ->  PushNotifications addListener 130675207
鈿★笍  To Native ->  PushNotifications addListener 130675208
鈿★笍  To Native ->  PushNotifications addListener 130675209
鈿★笍  To Native ->  PushNotifications addListener 130675210

Expected Behavior


After hitting "Allow" I'd expect to see logs like this:

鈿★笍  To Native ->  PushNotifications register 130675206
鈿★笍  [log] - Attempt register
鈿★笍  To Native ->  PushNotifications addListener 130675207
鈿★笍  To Native ->  PushNotifications addListener 130675208
鈿★笍  To Native ->  PushNotifications addListener 130675209
鈿★笍  To Native ->  PushNotifications addListener 130675210
鈿★笍  [log] - Push registration success, token: XXX

and have my callback triggered.

Sample Code or Sample Application Repo

import React from 'react';
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonButton } from '@ionic/react';
import { Plugins, PushNotification, PushNotificationToken, PushNotificationActionPerformed } from '@capacitor/core';

import './Tab2.css';

const { PushNotifications } = Plugins;

class Tab2 extends React.Component {
  constructor(props) {
    super(props);
    this.state = { notifications: [] };
  }
  registerPushNotifications() {
    console.log('Attempt register');
    PushNotifications.register();

    // On success, we should be able to receive notifications
    PushNotifications.addListener('registration', 
      (token) => {
        console.log('Push registration success, token: ' + token.value);
      }
    );

    // Some issue with our setup and push will not work
    PushNotifications.addListener('registrationError', 
      (error) => {
        console.log('Error on registration: ' + JSON.stringify(error));
      }
    );

    // Show us the notification payload if the app is open on our device
    PushNotifications.addListener('pushNotificationReceived', 
      (notification) => {
        console.log('Push received: ' + JSON.stringify(notification));
      }
    );

    // Method called when tapping on a notification
    PushNotifications.addListener('pushNotificationActionPerformed', 
      (notification) => {
        console.log('Push action performed: ' + JSON.stringify(notification));
      }
    );
  }

  render() {
    return (
      <IonPage>
        <IonHeader>
          <IonToolbar>
            <IonTitle>Tab 2</IonTitle>
          </IonToolbar>
        </IonHeader>
        <IonContent>
          <IonHeader collapse="condense">
            <IonToolbar>
              <IonTitle size="large">Tab 2</IonTitle>
            </IonToolbar>
          </IonHeader>
          <div className="container">
            <IonButton color="primary" onClick={this.registerPushNotifications}>Register Push Notifications</IonButton>
          </div>
        </IonContent>
      </IonPage>
    );
  }
};

export default Tab2;

My package JSON:

{
  "name": "myproject",
  "version": "0.0.1",
  "private": true,
  "dependencies": {
    "@capacitor/core": "1.5.2",
    "@capacitor/ios": "^1.5.2",
    "@ionic/react": "^5.0.0",
    "@ionic/react-router": "^5.0.0",
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.4.0",
    "@testing-library/user-event": "^8.0.3",
    "@types/jest": "^24.0.25",
    "@types/node": "^12.12.24",
    "@types/react": "^16.9.17",
    "@types/react-dom": "^16.9.4",
    "@types/react-router": "^5.1.4",
    "@types/react-router-dom": "^5.1.3",
    "ionicons": "^5.0.0",
    "react": "^16.12.0",
    "react-dom": "^16.12.0",
    "react-router": "^5.1.2",
    "react-router-dom": "^5.1.2",
    "react-scripts": "3.4.0"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "@capacitor/cli": "1.5.2"
  },
  "description": "An Ionic project"
}

AppDelegate.swift

...
  func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    NotificationCenter.default.post(name: Notification.Name(CAPNotifications.DidRegisterForRemoteNotificationsWithDeviceToken.name()), object: deviceToken)
    /*Messaging.messaging().apnsToken = deviceToken
    InstanceID.instanceID().instanceID { (result, error) in
        if let error = error {
            NotificationCenter.default.post(name: Notification.Name(CAPNotifications.DidFailToRegisterForRemoteNotificationsWithError.name()), object: error)
        } else if let result = result {
            NotificationCenter.default.post(name: Notification.Name(CAPNotifications.DidRegisterForRemoteNotificationsWithDeviceToken.name()), object: result.token)
        }
    }*/
  }
...

Reproduction Steps


Follow this setup guide. Try running iOS app from XCode.

Also note, I've tried with and without removing didRegisterForRemoteNotificationsWithDeviceToken code from AppDelegate.swift as suggested by Issue 2614.

Other Technical Details

npm --version output: 6.11.3

node --version output: v12.11.1

pod --version output (iOS issues only): 1.9.1

Other Information


I've seen similar github issues (only some resolved), but following them hasn't resolved my issue. Issue 2268, Issue 2247, Issue 2614

Most helpful comment

Fixed it again. Previously I was trying version 2.0.0 of capacitor/core, capacitor/ios and capacitor/android. It didn't work with either PushNotifications.requestPermission() or PushNotifications.register(). Previously after downgrading to version 1.5.2, npx cap sync, and cd ios/app pod install then ionic capacitor copy it worked.

This time I was running just 1.5.2 and PushNotifications.register() didn't work. But after upgrading back to version 2.0.0 and using PushNotifications.requestPermission() it worked. Not sure why the build originally broke; but seems like changing capacitor packages and syncing fixes it. I suspect whatever ended up breaking; changing the npm packages cleared the cache in a way that clearing in XCode didn't.

I still don't fully understand what exactly happened. But changing version, syncing, pod install, then copy seemed to fix the issue.

All 14 comments

@DevonBernard What did you do to resolve this?

@NiklasWilson I have no clue. I just kept running npx cap sync ios, cleaning XCode build, re-building project, swapping target devices, then suddenly it started working. Unfortunately, after a few releases, I was just debugging and after swapping my provisioning profile and swapping it back, it's totally broken again. If I find a fix, I'll post it here. 馃槥

Fixed it again. Previously I was trying version 2.0.0 of capacitor/core, capacitor/ios and capacitor/android. It didn't work with either PushNotifications.requestPermission() or PushNotifications.register(). Previously after downgrading to version 1.5.2, npx cap sync, and cd ios/app pod install then ionic capacitor copy it worked.

This time I was running just 1.5.2 and PushNotifications.register() didn't work. But after upgrading back to version 2.0.0 and using PushNotifications.requestPermission() it worked. Not sure why the build originally broke; but seems like changing capacitor packages and syncing fixes it. I suspect whatever ended up breaking; changing the npm packages cleared the cache in a way that clearing in XCode didn't.

I still don't fully understand what exactly happened. But changing version, syncing, pod install, then copy seemed to fix the issue.

Actually I think I have the answer for any future readers. I was using v2.0.0 for capacitor iOS but my capacitor core was still pre-v2 (maybe 1.5).

Now that everything related to capacitor is running v2 everything seems to be working. I also did a lot of what you said, so maybe it was a combo but Im fairly certain that the core being on v2 as well was key to the solution.

Thanks for your response though. Im sure someone else will run into your post eventually.

Version switching and/or combination of syncing, copying and installing Pods was only a temporary and unstable solution in my case (the listener would not be notified after the app was relaunched, for example).

I did some debugging and research and it seems that the problem lies in thedidRegisteredForRemoteNotificationsWithDeviceToken method not being called after device has been successfully registered with Firebase. From what I've found the reason may be method swizzling performed by the FCM SDK. It can be disabled, though, by setting FirebaseAppDelegateProxyEnabled flag to NO in Info.plist. And it was what eventually resolved the problem for me. At least for now 馃.

It would be good to confirm if that's actually the source of the issue. If yes, then perhaps it should be included it in the setup guide.

Ah interesting. I only use Firebase for Android so maybe that's why I have not noticed that yet.

I am also having this issue, registration event fires as expected on android, but on iOS the event does not fire anymore, although it was firing reliably before. This is prohibiting me from registering the app with the backend (notifications hub). I have tried all the options above but no luck. I am currenlty running capacitor 2.1.2 on all packages. Did anybody find a more concrete solution, I am not using firebase so that's not the issue in my case.


[UPDATE] I tried again this morning and it's working. Maybe Apple just needed 12 hours to make my certificate available on their end. Still not sure why it would work on one phone and not others but now it's working across all device.


I have 3 iPhones, an 11 and 2x6s. The 11 gets a token, the other's don't. Running the exact same code. Is apple just hating on me for using old hardware?! All phones running iOS 13.5.1.

PushNotifications.requestPermission().then(
        (result) => {
          console.log('[NOTIFICATIONS] permission: ', result);
          if (result.granted) {
            // Register with Apple / Google to receive push via APNS/FCM
            PushNotifications.register().then((response) => {
              console.log('[NOTIFICATIONS] register complete: ', response);
            }, (err) => {
              console.error('[NOTIFICATIONS] register error: ', err);
            });
          } else {
            // Show some error
            alert('Push notifications not allowed');
          }
        },
        (err) =>
          console.error('[NOTIFICATIONS] ERROR requesting permission: ', err)
      );

      // On success, we should be able to receive notifications
      PushNotifications.addListener(
        'registration',
        (token: PushNotificationToken) => {
          // token.value contains the FCM token needed to register with firebase.
          console.log(
            '[NOTIFICATIONS] Push registration success, token: ' + token.value
          );
          localStorage.setItem('FCM_TOKEN', JSON.stringify(token.value));
          this.token.next(token.value);
          this.userSvc.user$.subscribe((user) => {
            if (user) {
              console.log(
                '[NOTIFICATIONS] adding FCM token to user: ',
                user.UID
              );
              user.FCM_TOKEN = token.value;
              this.userSvc.updateUser(user);
            }
          });
        }
      );

iPhone 6 result:

鈿★笍  [log] - [NOTIFICATIONS] permission:  {"granted":true}
鈿★笍  [log] - [NOTIFICATIONS] register complete:  {}

iPhone 11 result:

鈿★笍  [log] - [NOTIFICATIONS] permission:  {"granted":true}
鈿★笍  [log] - [NOTIFICATIONS] register complete:  {}
鈿★笍  [log] - [NOTIFICATIONS] Push registration success, token: d2euglUPVl0...long string

Running ionic 5.0.7. capacitor 2.2.0 cli/core/ios.

[UPDATE] : tried on an iPad Pro. No token despite permission granted = true.

I still don't fully understand what exactly happened. But changing version, syncing, pod install, then copy seemed to fix the issue.

For me, pod install fixed it.

For me nothing helped. On my iPhone 11 it worked fine, but somehow it stopped working. On my iPad (2018) it is working. Same code base.

Anybody have an idea?

For me also nothing worked. Trying for days, finally I got this error on iPhone XS

[Firebase/Messaging][I-FCM012002] Error in application:didFailToRegisterForRemoteNotificationsWithError: no valid \M-b\M^@\M^\aps-environment\M-b\M^@\M^] entitlement string found for application

But in iPhone 6, I got this log
[Firebase/Messaging][I-FCM001000] FIRMessaging Remote Notifications proxy enabled, will swizzle remote notification receiver handlers. If you'd prefer to manually integrate Firebase Messaging, add "FirebaseAppDelegateProxyEnabled" to your Info.plist, and set it to NO. Follow the instructions at: https://firebase.google.com/docs/cloud-messaging/ios/client#method_swizzling_in_firebase_messaging

I tried with both .p8 and .p12 certificates.

Any help?

I had the same issue on iOS. Calling PushNotifications.addListener('registration', ... BEFORE PushNotifications.register() fixed the issue. This is the opposite of the official example code.

I had the same issue on iOS. Calling PushNotifications.addListener('registration', ... BEFORE PushNotifications.register() fixed the issue. This is the opposite of the official example code.

You suggest to call PushNotifications.addListener('registration', ...) before PushNotifications.register() ?

I had the same issue on iOS. Calling PushNotifications.addListener('registration', ... BEFORE PushNotifications.register() fixed the issue. This is the opposite of the official example code.

You suggest to call PushNotifications.addListener('registration', ...) before PushNotifications.register() ?

Do you have an code example?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

gnesher picture gnesher  路  3Comments

alexcroox picture alexcroox  路  3Comments

ebk46 picture ebk46  路  3Comments

MatanYadaev picture MatanYadaev  路  3Comments

peterpeterparker picture peterpeterparker  路  3Comments