havesource / cordova-plugin-push

Register and receive push notifications
MIT License
148 stars 283 forks source link

Background mode notifications not receiving data in latest Firebase Cloud Messaging APIs and SDKs #266

Closed viking2917 closed 5 months ago

viking2917 commented 6 months ago

Bug Report

As noted in (https://github.com/havesource/cordova-plugin-push/issues/257), Firebase Cloud Messaging is obsoleting the old way of sending notifications and as of June 2024 will require an upgrade to v1 (https://firebase.google.com/docs/cloud-messaging/migrate-v1)

The documentation for this plugin states that in order for the on('notification') handler to be triggered, one must omit the "data" section of the message payload and instead use the "notifications" field. This is the only way to handle custom data to be passed to an application when it is in background mode and receives a notification.

My app works correctly when used with the legacy endpoint for FCM (https://fcm.googleapis.com/fcm/send), and receives custom data used to process the notification. When using the new FCM endpoint and associated new auth methodology (e.g. https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send), the app notifications correctly receive the custom data when the app gets a notification in foreground, but NOT when the app is in background.

Google's documentation says the message payload should look more or less as follows:

{
  "message": {
    "topic": "news", OR ("token": < A Device Token >,)
    "notification": {
      "title": "Breaking News",
      "body": "New news story available."
    },
    "data": {
      "story_id": "story_12345"
    }
  }
}

Whereas this documentation (https://github.com/havesource/cordova-plugin-push/blob/master/docs/PAYLOAD.md#notification-vs-data-payloads)_ says that to trigger the on('notification') from a background notification one should effectively do this:

{
   "message": {
    "topic": "news", (OR "token": < A Device Token >,)
    "data": {
      "title": "Test Notification",
      "body": "This offer expires at 11:30 or whatever",
      "notId": 10,
      "surveyID": "ewtawgreg-gragrag-rgarhthgbad"
  }
}

thereby omitting the "data" field of the message.

In the old FCM, this works. In the new FCM, not only does the on('notification') not get triggered, but the notification displayed to the user has no title or body (because the "notifications" were not specified.)

Therefore it seems impossible to receive custom data from a background notification.

Has anyone successfully done this?

Expected Behaviour

Background notifications should invoke the on('notification') handler

Actual Behaviour

Background notifications, when used with the latest FCM V1 HTTP APi, do not raise the on('notification') handler

Reproduce Scenario (including but not limited to)

Steps to Reproduce

Platform and Version (eg. Android 5.0 or iOS 9.2.1)

(Android) Device Vendor (e.g. Samsung, HTC, Sony...)

cordova info Printout

Cordova Packages:

cli: 11.1.0
    common: 4.1.0
    create: 4.1.0
    lib: 11.1.0
        common: 4.1.0
        fetch: 3.1.0
        serve: 4.0.1

Project Installed Platforms:

android: 10.1.2
browser: 5.0.4
ios: 6.3.0

Project Installed Plugins:

@havesource/cordova-plugin-push: 4.0.0-dev.0
branch-cordova-sdk: 5.1.0
cordova-clipboard: 1.3.0
cordova-plugin-add-swift-support: 2.0.2
cordova-plugin-androidx-adapter: 1.1.3
cordova-plugin-androidx: 3.0.0
cordova-plugin-app-version: 0.1.12
cordova-plugin-camera-preview: 0.11.1
cordova-plugin-camera: 6.0.1-dev
cordova-plugin-chooser: 1.3.1
cordova-plugin-contacts: 3.0.1
cordova-plugin-device: 2.0.3
cordova-plugin-email-composer: 0.8.15
cordova-plugin-fbsdk: 4.0.2
cordova-plugin-file: 7.0.0
cordova-plugin-inappbrowser: 4.1.0
cordova-plugin-ionic-keyboard: 2.2.0
cordova-plugin-ionic-webview: 5.0.0
cordova-plugin-jitsi-meet-sdk: 4.0.9
cordova-plugin-network-information: 3.0.0
cordova-plugin-purchase: 13.10.0
cordova-plugin-sign-in-with-apple: 0.0.1
cordova-plugin-splashscreen: 6.0.2
cordova-plugin-x-socialsharing: 6.0.4
cordova-sms-plugin: 1.0.3
cordova-support-android-plugin: 1.0.1
es6-promise-plugin: 4.2.2
phonegap-plugin-barcodescanner: 8.1.1-dev

Environment:

OS: macOS 14.3 (23D56) (darwin 23.3.0) x64
Node: v14.15.4
npm: 6.14.10

android Environment:

android:

ERROR: Command failed with exit code 1: avdmanager list target Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema at com.android.repository.api.SchemaModule$SchemaModuleVersion.(SchemaModule.java:156) at com.android.repository.api.SchemaModule.(SchemaModule.java:75) at com.android.sdklib.repository.AndroidSdkHandler.(AndroidSdkHandler.java:81) at com.android.sdklib.tool.AvdManagerCli.run(AvdManagerCli.java:213) at com.android.sdklib.tool.AvdManagerCli.main(AvdManagerCli.java:200) Caused by: java.lang.ClassNotFoundException: javax.xml.bind.annotation.XmlSchema at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522) ... 5 more

ios Environment:

xcodebuild:

Xcode 15.1 Build version 15C65

Project Setting Files:

config.xml:

<?xml version='1.0' encoding='utf-8'?>

So you can post pictures to your Readings chat windows So you can post pictures to your Readings chat windows So you can post pictures to your Readings chat windows So you can save and post pictures to your Readings chat windows When you invite people to Readings, we'll upload their contact information to our servers so we can send them Reading Invitations on your behalf. fb instagram twitter
package.json:

--- Start of Cordova JSON Snippet --- { "plugins": { "cordova-plugin-email-composer": {}, "cordova-clipboard": {}, "cordova-plugin-camera-preview": { "ANDROID_SUPPORT_LIBRARY_VERSION": "26+" }, "cordova-plugin-sign-in-with-apple": {}, "cordova-plugin-inappbrowser": {}, "cordova-plugin-app-version": {}, "cordova-plugin-device": {}, "cordova-plugin-androidx-adapter": {}, "cordova-plugin-chooser": {}, "cordova-plugin-androidx": {}, "cordova-plugin-jitsi-meet-sdk": {}, "cordova-plugin-network-information": {}, "cordova-plugin-ionic-keyboard": {}, "cordova-plugin-file": { "ANDROIDX_WEBKIT_VERSION": "1.4.0" }, "cordova-plugin-x-socialsharing": {}, "cordova-sms-plugin": {}, "cordova-plugin-contacts": {}, "branch-cordova-sdk": {}, "cordova-plugin-fbsdk": { "APP_ID": "", "APP_NAME": "", "FACEBOOK_ADVERTISER_ID_COLLECTION": "false", "CLIENT_TOKEN": "", "FACEBOOK_URL_SCHEME_SUFFIX": " ", "OTHER_APP_SCHEMES": " ", "FACEBOOK_AUTO_LOG_APP_EVENTS": "true", "FACEBOOK_HYBRID_APP_EVENTS": "false", "FACEBOOK_ANDROID_SDK_VERSION": "14.1.1", "FACEBOOK_IOS_SDK_VERSION": "14.1.0", "FACEBOOK_BROWSER_SDK_VERSION": "v14.0" }, "cordova-plugin-camera": { "ANDROIDX_CORE_VERSION": "1.6.+" }, "@havesource/cordova-plugin-push": { "ANDROIDX_CORE_VERSION": "1.6.+", "FCM_VERSION": "23.+", "IOS_FIREBASE_MESSAGING_VERSION": "~> 8.1.1" }, "cordova-plugin-purchase": {}, "cordova-plugin-ionic-webview": {}, "cordova-plugin-splashscreen": {}, "phonegap-plugin-barcodescanner": { "ANDROID_SUPPORT_V4_VERSION": "27.+" } }, "platforms": [ "browser", "android" ] } --- End of Cordova JSON Snippet ---

Sample Push Data Payload

Sample Code that illustrates the problem

Logs taken while reproducing problem

ksch10bob commented 6 months ago

@viking2917

We ran into the same issue: The Documentation https://github.com/havesource/cordova-plugin-push/blob/master/docs/PAYLOAD.md#notification-vs-data-payloads pointed us to the right direction:

If we want the on notification handler to be called by clicking on the push notification when app is in backround we have to use the mixed payload with a special key-value pair "click_action": "com.adobe.phonegap.push.background.MESSAGING_EVENT"

{ "notification": { "title": "Test Notification", "body": "This offer expires at 11:30 or whatever", "notId": 10, "click_action": "com.adobe.phonegap.push.background.MESSAGING_EVENT" }, "data": { "surveyID": "ewtawgreg-gragrag-rgarhthgbad" } }

Did you try this? It worked for us

viking2917 commented 5 months ago

Thanks @ksch10bob. That does not work for me. When I add notId and click_action to my payload, I get an error like this:

"error": {
    "code": 400,
    "message": "Invalid JSON payload received. Unknown name "notId" at 'message.notification': Cannot find field.\nInvalid JSON payload received. Unknown name "click_action" at 'message.notification': Cannot find field.",
    ...
}

To confirm, are you using the NEW FIREBASE messaging service? i.e. you are sending to

https://fcm.googleapis.com/v1/projects/<your project>/messages:send

and not:

https://fcm.googleapis.com/fcm/send

The new API has a different payload structure, and so far as I can tell does not allow the parameters the documentation for this plugin suggests adding.

If you are using the new service, are you sending to a "topic" or a "token"? (the new payload requires a "message" field with that specified, e.g.

 "message": {
    "topic": "news", 
   ...

OR

 "message": {
   "token": <A Device Token>,
...

Thanks for your help and any further details.

ksch10bob commented 5 months ago

@viking2917 We do not call the FCM endpoints directly. We use AWS SNS and a "platform" for FCM (thats basically a container for the authentication.key) You can create a FCM platform with the new servicekey.json or the old apikey. The documentation of AWS SNS states, that they use the new FCM service, when you create the platform with the servicekey.json. For every platform Container we create so called "endpoints" with a devicetoken. So an endpoint represents a devicetoken. We then publish messages to these endpoints. But AWS SNS builds the real payload itself, we do not know how it looks like.

The FCM payload we give to AWS SNS has this structure NO notId in the notification Object

{
    "notification": {
        "title": "Test Notification",
        "body": "This offer expires at 11:30 or whatever",
        "click_action": "com.adobe.phonegap.push.background.MESSAGING_EVENT"
     },
    "data": {
        "customData": "foobar"
    }
}

We think AWS SNS handles the wrapping of this payload into the new message Object that contains notification and data as keys.

Sorry for not being specific enough about our exakt payload and Infrastructure. Maybe AWS SNS put the click_action into the data Object Did you try to add the key value pair "click_action": "com.adobe.phonegap.push.background.MESSAGING_EVENT" to the data Object?

viking2917 commented 5 months ago

@ksch10bob. Thanks for your help!

I have the click_action on the data object. When the app is in background, the app opens when the alert is tapped, but the on() notification function does not fire, so no chance to handle the custom data. If I put the click_action on the data{} field, or for that matter on the top level message{} object, the post to FCM service returns an invalid field error. So I think it has to go on the data{} field and that is what I am trying.

Its good to know it works via SNS. Maybe I will try to set that up and then wireshark the payload or something. Just need to find the right magic dance :)

Will post here if/when I figure it out :)

ksch10bob commented 5 months ago

@viking2917 i just found this: https://firebase.google.com/docs/cloud-messaging/concept-options#example-notification-message-with-platform-specific-delivery-options

{
  "message":{
     "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
     "notification":{
       "title":"Match update",
       "body":"Arsenal goal in added time, score is now 3-0"
     },
     "android":{
       "notification"{
         "click_action":"com.adobe.phonegap.push.background.MESSAGING_EVENT"
       }
     }
   }
 }

The click_action key has to be wrapped with the platform specific android key and the notification key

Hope that helps

viking2917 commented 5 months ago

tried that too already :)

viking2917 commented 5 months ago

@ksch10bob found it.

You are correct, one does need the android section in the payload.

 "android":{
       "notification"{
         "click_action":"com.adobe.phonegap.push.background.MESSAGING_EVENT"
       }
 }

I had done that, but I also just discovered that somehow, not sure how, the following lines had been deleted from my AndroidManifest.xml, so the app would not start in background:

 <activity android:name="com.adobe.phonegap.push.BackgroundHandlerActivity" android:exported="true" android:permission="${applicationId}.permission.BackgroundHandlerActivity">
    <intent-filter>
        <action android:name="com.adobe.phonegap.push.background.MESSAGING_EVENT"/>
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

(I found this by running 'adb logcat' while the background notification was happening and watching for errors, in case helpful to anyone.)

For anyone else with this issue, my full payload looks like:

{
    message: {
    token: <devicetoken>m
    notification: {
        title: "title",
        body: "body"
    },
    android: {
        notification: {
        click_action:  "com.adobe.phonegap.push.background.MESSAGING_EVENT"
        }
    },
    data: {
            'content-available' => "1",
        'customdata': 'foo',
        notId: <an integer>,
        etc
    }
    }
}

(I am passing notId, as per documentation, although in my experiments it does not seem to be required)

Thank you @ksch10bob !!!

sithwarrior commented 5 months ago

@viking2917 We do not call the FCM endpoints directly. We use AWS SNS and a "platform" for FCM (thats basically a container for the authentication.key) You can create a FCM platform with the new servicekey.json or the old apikey. The documentation of AWS SNS states, that they use the new FCM service, when you create the platform with the servicekey.json. For every platform Container we create so called "endpoints" with a devicetoken. So an endpoint represents a devicetoken. We then publish messages to these endpoints. But AWS SNS builds the real payload itself, we do not know how it looks like.

The FCM payload we give to AWS SNS has this structure NO notId in the notification Object

{
    "notification": {
        "title": "Test Notification",
        "body": "This offer expires at 11:30 or whatever",
        "click_action": "com.adobe.phonegap.push.background.MESSAGING_EVENT"
     },
    "data": {
        "customData": "foobar"
    }
}

We think AWS SNS handles the wrapping of this payload into the new message Object that contains notification and data as keys.

Sorry for not being specific enough about our exakt payload and Infrastructure. Maybe AWS SNS put the click_action into the data Object Did you try to add the key value pair "click_action": "com.adobe.phonegap.push.background.MESSAGING_EVENT" to the data Object?

Hi @ksch10bob Sorry to highlight this closed issue, but we are using SNS also, and I was wondering how your experience was, switching from the old apikey, to the new json method of auth. Was it painless?

viking2917 commented 5 months ago

@sithwarrior

@ksch10bob may have more SNS-specific info. My server side is in PHP and I found this StackOverflow answer worked pretty much as-is for me, in converting to the new API: https://stackoverflow.com/a/75482555. May be helpful.

ksch10bob commented 5 months ago

Hi @sithwarrior we did not have any problems at all.