[solved] android receive data from a fcm-push notification in detached app

#1

Environment:
target: android
“expo”: “^29.0.0”,
“expokit”: “1.5.0”,
type of app: android-standalone-apk detached with exp detach

Currently working:

  • I use FCM (Firebase Cloud Messaging)
  • I can retrieve the firebase-token
  • I can send a notification to the app
  • When the app is closed or in the background, the notification appears
  • when I click on the notification, the app opens or (when in background) comes to the foreground

Not working:
I cannot extract data from the push-notification. I thought I can use the same logic which is in the documentation for expo-push (not fcm-push) which I found here:
https://docs.expo.io/versions/v29.0.0/guides/push-notifications#3-handle-receiving-andor-selecting-the-notification

But this does not work. When I use the code

componentDidMount() {
    // ... do some things...
    this._notificationSubscription = Notifications.addListener(this._handleNotification);
  }

…then the method _handleNotification is never called

My Question:
Do I miss something? Or is my implementation wrong? How do I get data from a notification when I use FCM-push in a android-detached-app?

#2

Push Notifications don’t work on Detached apps.

You need to use for exemple, One Signal:

#3

Thanks @victorwads - yes I think this was in the past, but the developers from expo did a good job for fcm-push in the last months.

So after many hours with trial and error I can joyfully say that firebase-push-notifications are now fully working on android when I use exp detach :tada: :tada: :tada:.

The important thing is the format of the payload.

difference between debug and production

The key notificationExperienceUrl should be set different in the payload depending on using a debug-build or a production build.

For the example we assume that the scheme of your app is mycooldemoapp
More informations about setting the scheme (before detaching)
https://docs.expo.io/versions/latest/workflow/configuration#scheme

We need the specific different treating for the following usecase:

  • app is closed (app was open before)
  • push notification received by the device
  • user taps push-notification
  • app opens

when you don’t respect the different treating, then your app will try to open a second window.

When you are in debug mode

check the url in your running expo-development server
(in our example host=lan, ip=192.168.0.23 port=19000)

"notificationExperienceUrl": "mycooldemoapp://192.168.0.23:19000"

When you are in production mode

"notificationExperienceUrl": "exp://exp.host/@your_community_name/your-expo-project"

old firebase api

In our environment we use the Legacy HTTP protocol documented here:
https://firebase.google.com/docs/cloud-messaging/http-server-ref

And now comes the tricky part. Currently (sdk 29) you need to provide your data in multiple places in a json. Yes - thats not crazy - thats really true. The reason is, that expo treats notifications differently on the following use-cases:

  • app is closed
  • app is open and in foreground
  • app is open and in background

to use the following template you have to replace

  • firebase-token
  • @your_community_name/your-expo-project
{
  "to": "FIREBASETOKEN",
  "notification": {
    "title": "the real title",
    "body": "the real bodytext"
  },
  "data": {
    "notificationExperienceUrl": "exp://exp.host/@your_community_name/your-expo-project",
    "title": "data.title",
    "message": "data.message",
    "body": {
      "pathInJson": "data.body",
      "key2": "value2 in data.body"
    },
    "experienceId": "@your_community_name/your-expo-project",
    "notificationId": -1,
    "isMultiple": false,
    "remote": true,
    "notification_object": {
      "title": "notification_object.title",
      "experienceId": "@your_community_name/your-expo-project",
      "notificationId": -1,
      "isMultiple": false,
      "remote": true,
      "data": {
        "pathInJson": "data.notification_object.data",
        "key2": "value2 in data.notification_object.data"
      }
    }
  }
}

new firebase api

Documentation here FCM HTTP v1 API
https://firebase.google.com/docs/cloud-messaging/send-message

The new firebase-api

  • encloses all data with the key message
  • works with oauth
  • does not allow deep-level json; so you must provide a string to the keys message.data.body and message.data.notification_object; but the good news is, that the guys from expo where smart enough to extract an escaped Json-string to a json.object, so you can use the following template:
{
  "message": {
    "token": "FIREBASETOKEN",
    "notification": {
      "title": "the real title",
      "body": "the real bodytext"
    },
    "data": {
      "notificationExperienceUrl": "exp://exp.host/@your_community_name/your-expo-project",
      "title": "data.title",
      "message": "data.message",
      "body": "{\"pathInJson\": \"data.body\", \"key2\": \"value2\"}",
      "experienceId": "@your_community_name/your-expo-project",
      "notificationId": "-1",
      "isMultiple": "false",
      "remote": "true",`Preformatted text`
      "notification_object": "{\"title\": \"notification_object.title\",\r\n\"experienceId\": \"@your_community_name/your-expo-project\",\r\n\"notificationId\": -1,\r\n\"isMultiple\": false,\r\n\"remote\": true,\r\n\"data\": {\"pathInJson\": \"data.notification_object.data\", \"key2\": \"value2\"}}"
    }
  }
}

steps for android-studio

Before detaching:

  • get google-services.json from firebase console and place it on the top-level of your expo-project
  • in app.json
    • set the keyexpo.android.googleServicesFile to "./google-services.json"
    • set the key expo.scheme to "mycooldemoapp"
  • run exp detach

After detaching

in AndroidManifest.xml

  • comment (disable) the GCM-part
  • keep the FCM-part untouched

app/build.gradle

  • comment (disable)
    implementation 'com.google.android.gms:play-services-gcm:15.0.1'
  • insert (maybe versions you have to update)
    implementation 'com.google.firebase:firebase-core:16.0.1'
    implementation 'com.google.firebase:firebase-messaging:17.3.0'

in app/src/main/java/host/exp/exponent/generated/AppConstants.java

  • public static boolean FCM_ENABLED = true;

in App.js

  • get your firebase-token with await Notifications.getDevicePushTokenAsync();
  • for reacting on the notifications you can use Notifications.addListener

I think thats all
good luck everybody

5 Likes
closed #4

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.