coopcycle / coopcycle-app

CoopCycle native app
MIT License
152 stars 33 forks source link

FCM token may not be synchronized #697

Open alexsegura opened 4 years ago

alexsegura commented 4 years ago

There is a recurring issue, where notifications stop being sent to devices after a short period of time.

On the server, it is materialised by an 404 error returned by the FCM send API:

Requested entity was not found.

So, it means that at some point, the Firebase Instance ID we have on the server expired, and the app didn't send the updated token.


When the app starts, the token is sent to the server

https://github.com/coopcycle/coopcycle-app/blob/e0185876fe2801090a1bf09551b954bbf2f2bcb7/src/notifications/index.android.js#L105-L111

When the token is refreshed, it should also be sent to the server

https://github.com/coopcycle/coopcycle-app/blob/e0185876fe2801090a1bf09551b954bbf2f2bcb7/src/notifications/index.android.js#L139-L140

My understanding is that the token refresh mechanism does not work. This may be due to the fact that the Redux middleware that sends the token to the server has this piece of code

https://github.com/coopcycle/coopcycle-app/blob/e0185876fe2801090a1bf09551b954bbf2f2bcb7/src/redux/middlewares/PushNotificationMiddleware/index.js#L38-L40

It means that if the token was sent when the app starts, and gets refreshed, it is considered as already saved, and is ignored.


To fix this, we need a way to simulate a token refresh when the app is running. It seems possible to simulate it by using the Firebase Instance ID API, and delete the token. More information on how Instance IDs may expire

alexsegura commented 4 years ago

Confirmed it is possible to simulate the onTokenRefresh callback, by using:

firebase.messaging().deleteToken()

Once the token has been deleted, the callback is called within a few seconds.

But... it actually works, the new token is sent to the server.

alexsegura commented 4 years ago

~After some debugging, it appears that the onTokenRefresh callback does not get called immediately when receiving a new token, but after a user interaction (for example, navigating to another screen, putting the app to background).~

onTokenRefresh gets called as expected. It is called after a user interaction when using setTimeout.