Skip to content

Commit 6d22034

Browse files
author
Franco Bugnano
committed
Notifications now work on Android in background
1 parent 94837ee commit 6d22034

File tree

1 file changed

+36
-44
lines changed

1 file changed

+36
-44
lines changed

lib/src/notification.dart

Lines changed: 36 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import 'dart:core';
22
import 'dart:typed_data';
33
import 'dart:ui';
44
import 'dart:convert';
5-
import 'package:flutter/services.dart';
5+
import 'dart:isolate';
66
import 'package:firebase_messaging/firebase_messaging.dart';
77
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
88
import 'package:http/http.dart' as http;
@@ -106,6 +106,7 @@ AndroidChannel? _androidChannel;
106106
final _activeNotifications = <String, List<String>>{};
107107
int _nextId = 0;
108108
final _showIdFromNotificationId = <String, int>{};
109+
final _receivePort = ReceivePort();
109110

110111
Future<ByteArrayAndroidBitmap?> _androidBitmapFromUrl(String? url) async {
111112
if (url == null) {
@@ -115,7 +116,7 @@ Future<ByteArrayAndroidBitmap?> _androidBitmapFromUrl(String? url) async {
115116
// TODO: maybe we can keep a cache in case _androidBitmapFromUrl gets called
116117
// multiple times with the same URL
117118
final response = await http.get(Uri.parse(url));
118-
print("📘 _androidBitmapFromUrl ($url): ${response}");
119+
print("📘 _androidBitmapFromUrl ($url): $response");
119120
return ByteArrayAndroidBitmap(response.bodyBytes);
120121
}
121122

@@ -127,7 +128,7 @@ Future<ByteArrayAndroidIcon?> _androidIconFromUrl(String? url) async {
127128
// TODO: maybe we can keep a cache in case _androidIconFromUrl gets called
128129
// multiple times with the same URL
129130
final response = await http.get(Uri.parse(url));
130-
print("📘 _androidIconFromUrl ($url): ${response}");
131+
print("📘 _androidIconFromUrl ($url): $response");
131132
return ByteArrayAndroidIcon(response.bodyBytes);
132133
}
133134

@@ -140,6 +141,13 @@ Future<void> _onFCMBackgroundMessage(RemoteMessage firebaseMessage) async {
140141
print('📘 Message also contained a notification: ${firebaseMessage.notification}');
141142
}
142143

144+
// onBackgroundMessage runs on a separate isolate, so we're passing the message to the main isolate
145+
IsolateNameServer.lookupPortByName('talkjsFCMPort')?.send(firebaseMessage);
146+
}
147+
148+
Future<void> _onReceiveMessageFromPort(RemoteMessage firebaseMessage) async {
149+
print("📘 _onReceiveMessageFromPort: ${firebaseMessage.messageId}");
150+
143151
final data = firebaseMessage.data;
144152
StyleInformation styleInformation;
145153
styleInformation = MessagingStyleInformation(Person(name: 'me'));
@@ -198,6 +206,7 @@ Future<void> _onFCMBackgroundMessage(RemoteMessage firebaseMessage) async {
198206
}
199207
} else {
200208
print("📘 _onFCMBackgroundMessage: activeNotifications != null");
209+
activeNotifications.add(data['talkjs']);
201210
final messages = <Message>[];
202211
for (final talkjsString in activeNotifications) {
203212
final Map<String, dynamic> messageTalkjsData = json.decode(talkjsString);
@@ -217,20 +226,6 @@ Future<void> _onFCMBackgroundMessage(RemoteMessage firebaseMessage) async {
217226
);
218227
}
219228

220-
final sender = talkjsData['sender'];
221-
222-
messages.add(
223-
Message(
224-
talkjsData['message']['text'],
225-
timestamp,
226-
Person(
227-
icon: await _androidIconFromUrl(sender['photoUrl']),
228-
key: sender['id'],
229-
name: sender['name'],
230-
),
231-
),
232-
);
233-
234229
styleInformation = MessagingStyleInformation(
235230
Person(
236231
name: 'me',
@@ -278,58 +273,55 @@ Future<void> _onFCMBackgroundMessage(RemoteMessage firebaseMessage) async {
278273
);
279274
}
280275

276+
void _onSelectNotification(String? payload) {
277+
print('📘 _onSelectNotification: $payload');
278+
279+
if (payload != null) {
280+
final Map<String, dynamic> talkjsData = json.decode(payload);
281+
final String notificationId = talkjsData['conversation']['id'];
282+
_activeNotifications.remove(notificationId);
283+
}
284+
}
285+
281286
void _onFCMTokenRefresh(String token) {
282287
print('📘 Firebase onTokenRefresh: $token');
283288

284289
fcmToken = token;
285290
}
286291

287292
Future<void> registerAndroidPushNotificationHandlers(AndroidChannel androidChannel) async {
288-
FirebaseMessaging.onBackgroundMessage(_onFCMBackgroundMessage);
289-
290-
FirebaseMessaging.onMessage.listen(_onFCMBackgroundMessage); // Only for testing
291-
292293
// Get the token each time the application loads
293294
fcmToken = await FirebaseMessaging.instance.getToken();
294295
print('📘 Firebase token: $fcmToken');
295296

296297
// Update the token each time it refreshes
297298
FirebaseMessaging.instance.onTokenRefresh.listen(_onFCMTokenRefresh);
298299

299-
await _flutterLocalNotificationsPlugin.initialize(InitializationSettings(
300-
android: AndroidInitializationSettings('@mipmap/ic_launcher'),
301-
));
300+
await _flutterLocalNotificationsPlugin.initialize(
301+
InitializationSettings(
302+
android: AndroidInitializationSettings('@mipmap/ic_launcher'),
303+
),
304+
onSelectNotification: _onSelectNotification,
305+
);
302306

303307
_androidChannel = androidChannel;
304308

305309
// TODO: Handle already existing notifications
310+
/* Already existing notifications cannot be handled at the moment because
311+
* the ActiveNotification class doesn't have enough information
306312
try {
307313
final activeNotifications = await _flutterLocalNotificationsPlugin
308314
.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
309315
?.getActiveNotifications();
310-
311-
/*
312-
for (final displayedNotification in activeNotifications) {
313-
const notification = displayedNotification.notification;
314-
315-
if (JSON.stringify(notification.data) !== '{}') {
316-
let activeNotifications = this.#activeNotifications[notification.id!];
317-
if (!activeNotifications) {
318-
activeNotifications = [];
319-
this.#activeNotifications[notification.id!] = activeNotifications;
320-
}
321-
322-
const talkjs = JSON.parse(notification.data!.talkjs);
323-
activeNotifications.push({
324-
sender: talkjs.sender,
325-
message: talkjs.message,
326-
});
327-
}
328-
}
329-
*/
330316
} on PlatformException {
331317
// PlatformException is raised on Android < 6.0
332318
// Simply ignoring this part
333319
}
320+
*/
321+
322+
IsolateNameServer.registerPortWithName(_receivePort.sendPort, 'talkjsFCMPort');
323+
_receivePort.listen((message) async => await _onReceiveMessageFromPort(message));
324+
325+
FirebaseMessaging.onBackgroundMessage(_onFCMBackgroundMessage);
334326
}
335327

0 commit comments

Comments
 (0)