displayNotification method
Display a notification from FCM data payload
Expected data fields:
- title: Notification title
- body: Notification body
- imageUrl: (optional) Image URL to display
- button: (optional) Action button text
- target: Navigation target (screen/url)
- navigate_to_screen: Screen name to navigate to
- navigate_to_url: URL to open
- callbackUrl: URL to track notification click
Implementation
Future<void> displayNotification(Map<String, dynamic> data) async {
if (!_initialized) {
debugPrint('NotificationDisplayService not initialized, skipping notification display');
return;
}
debugPrint('=== DISPLAYING NOTIFICATION ===');
debugPrint('Data payload: $data');
final String title = data['title'] ?? 'Notification';
final String body = data['body'] ?? '';
final String? imageUrl = data['imageUrl'];
final String? buttonText = data['button'];
debugPrint('Title: $title');
debugPrint('Body: $body');
debugPrint('ImageUrl: $imageUrl');
debugPrint('Button: $buttonText');
// For iOS: Register dynamic category if button text is provided
String? categoryId;
if (Platform.isIOS && buttonText != null && buttonText.isNotEmpty) {
// Generate the same category ID that the service extension would use
categoryId = 'RELEVA_DYNAMIC_${buttonText.hashCode}';
debugPrint('iOS: Using dynamic category ID: $categoryId');
// Register the category with iOS native code for foreground notifications
try {
await _platformChannel.invokeMethod('registerNotificationCategory', {
'buttonText': buttonText,
});
debugPrint('iOS: Registered notification category with button: $buttonText');
} catch (e) {
debugPrint('iOS: Error registering notification category: $e');
}
}
// Generate unique notification ID
final int notificationId = DateTime.now().millisecondsSinceEpoch.remainder(100000);
// Download image if provided
final String? largeIconPath = await _downloadAndSaveImage(imageUrl);
final String? bigPicturePath = await _downloadAndSaveImage(imageUrl);
// Android notification details
AndroidNotificationDetails androidDetails = AndroidNotificationDetails(
'releva_notifications',
'Releva Notifications',
channelDescription: 'Notifications from Releva SDK',
importance: Importance.high,
priority: Priority.high,
largeIcon: largeIconPath != null ? FilePathAndroidBitmap(largeIconPath) : null,
styleInformation: bigPicturePath != null
? BigPictureStyleInformation(
FilePathAndroidBitmap(bigPicturePath),
hideExpandedLargeIcon: true,
)
: null,
);
// Add action button if provided
if (buttonText != null && buttonText.isNotEmpty) {
androidDetails = AndroidNotificationDetails(
'releva_notifications',
'Releva Notifications',
channelDescription: 'Notifications from Releva SDK',
importance: Importance.high,
priority: Priority.high,
largeIcon: largeIconPath != null ? FilePathAndroidBitmap(largeIconPath) : null,
styleInformation: bigPicturePath != null
? BigPictureStyleInformation(
FilePathAndroidBitmap(bigPicturePath),
hideExpandedLargeIcon: true,
)
: null,
actions: [
AndroidNotificationAction(
'action_1',
buttonText,
showsUserInterface: true,
),
],
);
}
// iOS notification details
DarwinNotificationDetails iosDetails = const DarwinNotificationDetails(
presentAlert: true,
presentBadge: true,
presentSound: true,
);
// Add category identifier for iOS if button text is provided
if (Platform.isIOS && categoryId != null) {
iosDetails = DarwinNotificationDetails(
presentAlert: true,
presentBadge: true,
presentSound: true,
categoryIdentifier: categoryId,
);
}
final NotificationDetails details = NotificationDetails(
android: androidDetails,
iOS: iosDetails,
);
// Convert data to payload string for later retrieval
final String payload = _mapToPayload(data);
await _notificationsPlugin.show(
notificationId,
title,
body,
details,
payload: payload,
);
debugPrint('Displayed notification: $title - $body');
}