EddyVerbruggen / nativescript-plugin-firebase

:fire: NativeScript plugin for Firebase
https://firebase.google.com
MIT License
1.01k stars 448 forks source link

Push notifications for iOS work in Pusher, but not in PushTry or with PushSharp #1779

Open dpdragnev opened 3 years ago

dpdragnev commented 3 years ago

Hello,

When I run our NS 6.5 on Android, the generated token works fine and I can send push notifications from our server (using PushSharp). However, on iOS, I get the APN token and I can use it in Pusher (with the generated .p12 sandbox certificate), but when I try to send the push notification via https://www.pushtry.com/ , using the same certificate and token, I get a generic error.

The same happens if I try to send a notification via our internal API (using PushSharp with the same certificate). I get "Apns notification error. Connection Error.".

Here is my setup:

{
    "using_ios": true,
    "using_android": true,
    "analytics": true,
    "firestore": false,
    "realtimedb": false,
    "authentication": false,
    "remote_config": true,
    "performance_monitoring": true,
    "external_push_client_only": true,
    "messaging": false,
    "in_app_messaging": true,
    "crashlytics": false,
    "storage": false,
    "functions": false,
    "facebook_auth": false,
    "google_auth": false,
    "admob": false,
    "dynamic_links": false,
    "ml_kit": false
}

I know PushTry and PushSharp are out of the scope of this plugin, but I am wondering why our server cannot send the notifications, but Pusher can.

I checked and re-checked my Apple and Firebase setups and everything is according to the documentation. I am really out of ideas on how to make this work.

Any help would be greatly appreciated. Thank you

bradmartin commented 3 years ago

Are you using the token given during the getCurrentPushToken() method? I ran into something where a third party push service did not work with this token and I had to take the token from the actual iOS delegate method when the user allows permissions to register my device with this service on iOS.

dpdragnev commented 3 years ago

Yes, I am using getCurrentPushToken(). This is a good suggestion. I will try that.

In the meantime, I turned the messaging on and used the FCM, not APNs token with the HTTP call to the firebase messaging api. This works, but I was just curious why this was happening.

Thanks @bradmartin

bradmartin commented 3 years ago

Setting up the app delegate snippet:

if (global.isIOS) {
  // Custom iOS App Delegate
  @NativeClass()
  class MyDelegate extends UIResponder implements UIApplicationDelegate {
    public static ObjCProtocols = [UIApplicationDelegate];

    /// THIS IS WHERE YOU GET THE TOKEN FOR PUSH
    applicationDidRegisterForRemoteNotificationsWithDeviceToken(
      application,
      deviceToken: NSData
    ) {
      const token = deviceToken.debugDescription.replace(/[< >]/g, '');
      const eventData = {
        eventName: 'iosAppDidRegisterForRemoteNotifications',
        object: this,
        data: {
          token
        }
      };

      Application.notify(eventData);
    }

/// THIS IS WHEN THE USER DECLINES PUSH PERMISSION :(
    applicationDidFailToRegisterForRemoteNotificationsWithError() {
      const eventData = {
        eventName: 'iosAppDidFailRegisterForRemoteNotifications',
        object: this
      };

      Application.notify(eventData);
    }

/// THIS LOCKS THE ORIENTATION :)
    applicationSupportedInterfaceOrientationsForWindow(application, window) {
      return UIInterfaceOrientationMask.Portrait;
    }

    applicationWillFinishLaunchingWithOptions(
      application: UIApplication,
      launchOptions: NSDictionary<any, any>
    ): boolean {
      const eventData = {
        eventName: 'iosAppWillFinishLaunching',
        object: this,
        data: {
          application,
          launchOptions
        }
      };
      Application.notify(eventData);

      return true;
    }

    applicationDidFinishLaunchingWithOptions(
      application: UIApplication,
      launchOptions: NSDictionary<any, any>
    ): boolean {
      const eventData = {
        eventName: 'iosAppDidFinishLaunching',
        object: this,
        data: {
          application,
          launchOptions
        }
      };
      Application.notify(eventData);

      return true;
    }

    applicationDidBecomeActive(application: UIApplication): void {
      const eventData = {
        eventName: 'iosAppDidBecomeActive',
        object: this,
        data: {
          application
        }
      };
      Application.notify(eventData);
    }

    applicationWillEnterForeground() {
      const eventData = {
        eventName: 'iosAppWillEnterForeground',
        object: this
      };
      Application.notify(eventData);
    }

    applicationDidEnterBackground(application: UIApplication): void {
      const eventData = {
        eventName: 'iosAppDidEnterBackground',
        object: this,
        data: {
          application
        }
      };
      Application.notify(eventData);
      return;
    }

    applicationWillTerminate() {
      const eventData = {
        eventName: 'iosAppWillTerminate',
        object: this
      };
      Application.notify(eventData);
    }
  }
  Application.ios.delegate = MyDelegate;
}

Here is a custom app delegate in a production app where I was getting the token after the user confirms push permission on iOS, I added a comment to the delegate method so you can see. Using import { Application } from '@nativescript/core I then just emit the events, and have event listeners in my first actual app page, where I init the firebase instance and add the callback (which starts the permission prompt on iOS)

import { Application } from '@nativescript/core;

  // the user confirmed wanting to allow notifications on iOS
        Application.on('iosAppDidRegisterForRemoteNotifications', args => {
          someMethodToSendMyPushTokenToBackend(args.data.token);
        });

Hopefully this helps you. I didn't have time to look into the firebase plugin to sort through it all, this was just what got the app working on iOS. The backend is Kinvey if you're curious.

dpdragnev commented 3 years ago

Thank you @bradmartin Appreciate you taking the time to provide me with this code.