I am building a chat part in my flutter app. I was pushing my notifications as Notifications
and not as only-data messages
using FCM service. I faced a problem of firebase collapsing notifications if the user wasn’t online, where it will only push the last notification, but I was relying on the notifications for payload to update the chats and chat messages. I had to change to only-data messages to avoid the collapsing issue. it was wroking in debug mode when the app was in foreground and background on both Android
and iOS
. I wanted to test if the app was terminated, and I found that the data messages will not be received until the user opens the app, whether the app was in background or terminated. While if I use normal notifications, it would always be received. Can someone help me understand and solve this issue ?
Laravel FCM function:
public function sendDataMessage($deviceTokens, $data = [], $priority = "high")
{
$messaging = app('firebase.messaging');
$clean_data = $data;
if (isset($data["type"]) && $data["type"] == "chat" && $data["action"] == "receiveMessage") {
unset($clean_data["fcm_message"]);
}
$messages = [];
foreach ($deviceTokens as $token) {
try {
if (isset($data["type"]) && $data["type"] == "chat" && $data["action"] == "receiveMessage") {
$chat_message = $data["fcm_message"];
$clean_data["title"] = Chats::select("name")->find($data["chat_id"])->name;
$clean_data["body"] = $chat_message["sender"]["name"] . ": " . ($chat_message["content"]["type"] == "Text" ? $chat_message["content"]["body"] : $chat_message["content"]["type"]);
}
$messages[] = CloudMessage::withTarget('token', $token)
->withData($clean_data)
// ->withNotification(Notification::create("Asdasdoqoijwdioqs", "asdasd"))
->withAndroidConfig(AndroidConfig::fromArray([
'priority' => 'high', // Use high priority
'ttl' => 86400 * 28, // 4 weeks in seconds
// 'notification' => [
// 'tag' => isset($data["type"]) && $data["type"] == "chat" && $data["action"] == "receiveMessage" ? strval($chat_message["id"]) : "1",
// 'sound' => 'default', // Ensure notification has sound
// 'channel_id' => 'high_importance', // Use the notification channel defined in your Android app
// ],
]))
->withApnsConfig(ApnsConfig::fromArray([
'headers' => [
'apns-collapse-id' => isset($data["type"]) && $data["type"] == "chat" && $data["action"] == "receiveMessage" ? strval($chat_message["id"]) : "1",
'apns-expiration' => strval(time() + 86400 * 28), // Expiry timestamp
'apns-priority' => '10',
],
'payload' => [
'aps' => [
// 'sound' => 'default',
"content-available" => 1,
"mutable-content" => 1
],
],
]));
} catch (Exception $e) {
return $e;
}
}
try {
$report = $messaging->sendAll($messages);
} catch (NotFound $e) {
return $e;
} catch (Exception $e) {
return $e;
}
return $report->successes()->count();
}
EDIT
I tried re-running the app in profile
mode and it worked just fine. seems like it’s a flutter release mode problem. I don’t know if release mode behaviour is the one that will happen if uploaded to app store and play store. I’ll try and update soon.
2
Answers
The problem specific to not receiving data messages was not because of Firebase but becauses of the background handler as it didn't have
@pragma('vm:entry-point')
so that Flutter doesn't remove the function when shaking down when trying to run in release as descibed in Firebase receive message documentationFCM messages aren’t instantaneous or completely reliable. They can be delayed, and they can be dropped. This is true about any messaging technology over the internet. They tend to be fairly fast, but there’s no promise of that.
You should not be using the payload of FCM messages to keep your chats up to date. You can do that optimistically, but you should still be pinging your servers on some cadence (generally any time they open the messaging app) to get anything that was missed. This isn’t just a rule of thumb for FCM, but for any way of pushing data. For example, you can never rely on a web hook working, and should always have a backup job to pull that data and process any misses.