showNotification method
Displays a local notification.
Supports rich notifications including:
- Images (downloaded and cached automatically)
- Action buttons (up to 3 per notification)
- Custom sounds
- Badge updates
Parameters:
payload: The notification content and configuration
Returns the notification ID that was used.
Implementation
Future<int> showNotification(NotificationPayload payload) async {
if (!_initialized) {
throw StateError('NotificationService not initialized. Call initialize() first.');
}
try {
final id = payload.id ?? DateTime.now().millisecondsSinceEpoch.remainder(100000);
// Download image if provided
String? imagePath;
if (payload.imageUrl != null && payload.imageUrl!.isNotEmpty) {
imagePath = await NotificationImageLoader.downloadImage(payload.imageUrl!);
if (imagePath != null) {
logi('Notification image downloaded: $imagePath');
} else {
logi('Failed to download notification image, displaying without image');
}
}
// Build action buttons for Android
List<AndroidNotificationAction>? androidActions;
if (payload.actions.isNotEmpty && !kIsWeb && Platform.isAndroid) {
androidActions = payload.actions.map((action) {
return AndroidNotificationAction(
action.id,
action.label,
icon: action.icon != null ? DrawableResourceAndroidBitmap(action.icon!) : null,
showsUserInterface: action.launchesApp,
contextual: false,
);
}).toList();
}
// Android-specific settings
// Use channel from payload, or default to standard channel
final channelId = payload.channelId ?? NotificationChannelManager.channelDefault;
final androidDetails = AndroidNotificationDetails(
channelId,
_getChannelName(channelId),
channelDescription: _getChannelDescription(channelId),
importance: Importance.high,
playSound: true,
enableVibration: true,
enableLights: true,
styleInformation: imagePath != null
? BigPictureStyleInformation(
FilePathAndroidBitmap(imagePath),
contentTitle: payload.title,
summaryText: payload.body,
hideExpandedLargeIcon: false,
)
: null,
actions: androidActions,
category: payload.category != null
? AndroidNotificationCategory.values.firstWhere(
(c) => c.toString().split('.').last == payload.category,
orElse: () => AndroidNotificationCategory.message,
)
: null,
);
// Build iOS/macOS attachment for image
List<DarwinNotificationAttachment>? iosAttachments;
if (imagePath != null && !kIsWeb && (Platform.isIOS || Platform.isMacOS)) {
iosAttachments = [
DarwinNotificationAttachment(imagePath),
];
}
// iOS-specific settings
final iosDetails = DarwinNotificationDetails(
presentAlert: true,
presentBadge: true,
presentSound: true,
badgeNumber: payload.badge,
categoryIdentifier: payload.category,
attachments: iosAttachments,
);
final notificationDetails = NotificationDetails(
android: androidDetails,
iOS: iosDetails,
macOS: iosDetails,
);
// Serialize payload data for tap handling
final payloadJson = _serializePayload(payload);
await _localNotifications!.show(
id,
payload.title ?? 'Notification',
payload.body,
notificationDetails,
payload: payloadJson,
);
logi('Displayed notification: $id with ${payload.actions.length} actions');
return id;
} catch (e, stackTrace) {
loge(e, 'Error showing notification', stackTrace);
_onError?.call('Error showing notification: $e', stackTrace);
rethrow;
}
}