Skip to content

Commit a7ae884

Browse files
committed
feat(notifications): enhance OneSignal integration with detailed send results
- Update sendNotification and sendBulkNotifications to return PushNotificationResult - Implement logic to handle failed notifications within batches - Process OneSignal API response to identify invalid player IDs - Refactor _sendBatch to return detailed result of the send operation - Improve
1 parent 6dd93e8 commit a7ae884

File tree

1 file changed

+57
-11
lines changed

1 file changed

+57
-11
lines changed

lib/src/services/onesignal_push_notification_client.dart

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,25 +27,25 @@ class OneSignalPushNotificationClient implements IPushNotificationClient {
2727
final Logger _log;
2828

2929
@override
30-
Future<void> sendNotification({
30+
Future<PushNotificationResult> sendNotification({
3131
required String deviceToken,
3232
required PushNotificationPayload payload,
33-
}) async {
33+
}) {
3434
// For consistency, delegate to the bulk sending method with a single token.
35-
await sendBulkNotifications(
35+
return sendBulkNotifications(
3636
deviceTokens: [deviceToken],
3737
payload: payload,
3838
);
3939
}
4040

4141
@override
42-
Future<void> sendBulkNotifications({
42+
Future<PushNotificationResult> sendBulkNotifications({
4343
required List<String> deviceTokens,
4444
required PushNotificationPayload payload,
4545
}) async {
4646
if (deviceTokens.isEmpty) {
4747
_log.info('No device tokens provided for OneSignal bulk send. Aborting.');
48-
return;
48+
return const PushNotificationResult();
4949
}
5050

5151
_log.info(
@@ -55,6 +55,9 @@ class OneSignalPushNotificationClient implements IPushNotificationClient {
5555

5656
// OneSignal has a limit of 2000 player_ids per API request.
5757
const batchSize = 2000;
58+
final allSentTokens = <String>[];
59+
final allFailedTokens = <String>[];
60+
5861
for (var i = 0; i < deviceTokens.length; i += batchSize) {
5962
final batch = deviceTokens.sublist(
6063
i,
@@ -63,15 +66,26 @@ class OneSignalPushNotificationClient implements IPushNotificationClient {
6366
: i + batchSize,
6467
);
6568

66-
await _sendBatch(
69+
final batchResult = await _sendBatch(
6770
deviceTokens: batch,
6871
payload: payload,
6972
);
73+
74+
allSentTokens.addAll(batchResult.sentTokens);
75+
allFailedTokens.addAll(batchResult.failedTokens);
7076
}
77+
78+
return PushNotificationResult(
79+
sentTokens: allSentTokens,
80+
failedTokens: allFailedTokens,
81+
);
7182
}
7283

7384
/// Sends a single batch of notifications to the OneSignal API.
74-
Future<void> _sendBatch({
85+
///
86+
/// This method processes the API response to distinguish between successful
87+
/// and failed sends, returning a [PushNotificationResult].
88+
Future<PushNotificationResult> _sendBatch({
7589
required List<String> deviceTokens,
7690
required PushNotificationPayload payload,
7791
}) async {
@@ -95,17 +109,49 @@ class OneSignalPushNotificationClient implements IPushNotificationClient {
95109
);
96110

97111
try {
98-
await _httpClient.post<void>(url, data: requestBody);
112+
// The OneSignal API returns a JSON object with details about the send,
113+
// including errors for invalid player IDs.
114+
final response = await _httpClient.post<Map<String, dynamic>>(
115+
url,
116+
data: requestBody,
117+
);
118+
119+
final sentTokens = <String>{...deviceTokens};
120+
final failedTokens = <String>{};
121+
122+
// Check for errors in the response body.
123+
if (response.containsKey('errors') && response['errors'] != null) {
124+
final errors = response['errors'];
125+
if (errors is Map && errors.containsKey('invalid_player_ids')) {
126+
final invalidIds = List<String>.from(
127+
errors['invalid_player_ids'] as List,
128+
);
129+
if (invalidIds.isNotEmpty) {
130+
_log.info(
131+
'OneSignal reported ${invalidIds.length} invalid player IDs. '
132+
'These will be marked as failed.',
133+
);
134+
failedTokens.addAll(invalidIds);
135+
sentTokens.removeAll(invalidIds);
136+
}
137+
}
138+
}
139+
99140
_log.info(
100-
'Successfully sent OneSignal batch of ${deviceTokens.length} '
101-
'notifications for app ID "$appId".',
141+
'OneSignal batch complete. Success: ${sentTokens.length}, '
142+
'Failed: ${failedTokens.length}.',
143+
);
144+
return PushNotificationResult(
145+
sentTokens: sentTokens.toList(),
146+
failedTokens: failedTokens.toList(),
102147
);
103148
} on HttpException catch (e) {
104149
_log.severe(
105150
'HTTP error sending OneSignal batch notification: ${e.message}',
106151
e,
107152
);
108-
rethrow;
153+
// If the entire request fails, all tokens in this batch are considered failed.
154+
return PushNotificationResult(failedTokens: deviceTokens);
109155
} catch (e, s) {
110156
_log.severe(
111157
'Unexpected error sending OneSignal batch notification.',

0 commit comments

Comments
 (0)