Skip to content

Commit

Permalink
Small refactor. Update readme.
Browse files Browse the repository at this point in the history
  • Loading branch information
ulezkin committed Jun 27, 2024
1 parent 54603e1 commit 246f490
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 117 deletions.
4 changes: 4 additions & 0 deletions flutter_local_notifications/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ This is fork of [flutter_local_notifications](https://github.com/MaikuB/flutter_
* Ability to set your own custom layout for notifications.
* More detailed exceptions in `ScheduledNotificationReceiver.onReceive()`.
* Ability to set notification window for inexact alarm. See `AndroidNotificationDetails.inexactWindowLengthMillis`
* Ability to store info about shown notifications. See `AndroidNotificationDetails.shownNotificationsInfo`. If you pass this param
it will save in local store if notification show.
* You can load this stored information by `FlutterLocalNotificationsPlugin.getShownNotificationsInfo()`
method and clear stored info by `FlutterLocalNotificationsPlugin.cleanShownNotificationsInfo()` method.

### iOS

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,130 +21,131 @@
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/** Created by michaelbui on 24/3/18. */
/**
* Created by michaelbui on 24/3/18.
*/
@Keep
public class ScheduledNotificationReceiver extends BroadcastReceiver {

private ShownNotificationsPreferences preferences;
private static final String TAG = "ScheduledNotifReceiver";

@Override
@SuppressWarnings("deprecation")
public void onReceive(final Context context, Intent intent) {
preferences = preferences == null ? new ShownNotificationsPreferences(context) : preferences;

String notificationDetailsJson =
intent.getStringExtra(FlutterLocalNotificationsPlugin.NOTIFICATION_DETAILS);
if (StringUtils.isNullOrEmpty(notificationDetailsJson)) {
// This logic is needed for apps that used the plugin prior to 0.3.4

Notification notification;
int notificationId = intent.getIntExtra("notification_id", 0);

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
notification = intent.getParcelableExtra("notification", Notification.class);
} else {
notification = intent.getParcelableExtra("notification");
}

if (notification == null) {
// This means the notification is corrupt
FlutterLocalNotificationsPlugin.removeNotificationFromCache(context, notificationId);
Log.e(TAG, "Failed to parse a notification from Intent. ID: " + notificationId);
fault("Notification is null - invalid data.", intent);
return;
}

notification.when = System.currentTimeMillis();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(notificationId, notification);
boolean repeat = intent.getBooleanExtra("repeat", false);
if (!repeat) {
FlutterLocalNotificationsPlugin.removeNotificationFromCache(context, notificationId);
}
} else {
Gson gson = FlutterLocalNotificationsPlugin.buildGson();
Type type = new TypeToken<NotificationDetails>() {}.getType();
NotificationDetails notificationDetails = gson.fromJson(notificationDetailsJson, type);

if (notificationDetails == null) {
fault("NotificationDetails is null - gson.fromJson can't parse it.", intent);
return;
}

try {
FlutterLocalNotificationsPlugin.showNotification(context, notificationDetails);
} catch (Exception e) {

DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;

LocalDateTime scheduledDateTime =
LocalDateTime.parse(notificationDetails.scheduledDateTime, formatter);

LocalDateTime currentDateTime = LocalDateTime.now();

// TODO: временное решение, удалить как все починим!
// Проблема: у части давних пользователей остались очень древние оповещения,
// которые планировались по старому методу, который сейчас вызывает ошибку при показе.
// Если мы ловим ошибку при показе именно такого старого оповещения, то отменяем его.
if (scheduledDateTime.isBefore(currentDateTime.minusYears(1))) {
FlutterLocalNotificationsPlugin.cancelByNotificationDetails(context, notificationDetails);
fault("Wrong notification! Date older than a year.", intent);
private static final String TAG = "ScheduledNotifReceiver";

@Override
@SuppressWarnings("deprecation")
public void onReceive(final Context context, Intent intent) {

String notificationDetailsJson =
intent.getStringExtra(FlutterLocalNotificationsPlugin.NOTIFICATION_DETAILS);
if (StringUtils.isNullOrEmpty(notificationDetailsJson)) {
// This logic is needed for apps that used the plugin prior to 0.3.4

Notification notification;
int notificationId = intent.getIntExtra("notification_id", 0);

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
notification = intent.getParcelableExtra("notification", Notification.class);
} else {
notification = intent.getParcelableExtra("notification");
}

if (notification == null) {
// This means the notification is corrupt
FlutterLocalNotificationsPlugin.removeNotificationFromCache(context, notificationId);
Log.e(TAG, "Failed to parse a notification from Intent. ID: " + notificationId);
fault("Notification is null - invalid data.", intent);
return;
}

notification.when = System.currentTimeMillis();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(notificationId, notification);
boolean repeat = intent.getBooleanExtra("repeat", false);
if (!repeat) {
FlutterLocalNotificationsPlugin.removeNotificationFromCache(context, notificationId);
}
} else {
fault("Exception while showing notification.", e, intent);
Gson gson = FlutterLocalNotificationsPlugin.buildGson();
Type type = new TypeToken<NotificationDetails>() {
}.getType();
NotificationDetails notificationDetails = gson.fromJson(notificationDetailsJson, type);

if (notificationDetails == null) {
fault("NotificationDetails is null - gson.fromJson can't parse it.", intent);
return;
}

try {
FlutterLocalNotificationsPlugin.showNotification(context, notificationDetails);
} catch (Exception e) {

DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;

LocalDateTime scheduledDateTime =
LocalDateTime.parse(notificationDetails.scheduledDateTime, formatter);

LocalDateTime currentDateTime = LocalDateTime.now();

// TODO: временное решение, удалить как все починим!
// Проблема: у части давних пользователей остались очень древние оповещения,
// которые планировались по старому методу, который сейчас вызывает ошибку при показе.
// Если мы ловим ошибку при показе именно такого старого оповещения, то отменяем его.
if (scheduledDateTime.isBefore(currentDateTime.minusYears(1))) {
FlutterLocalNotificationsPlugin.cancelByNotificationDetails(context, notificationDetails);
fault("Wrong notification! Date older than a year.", intent);
} else {
fault("Exception while showing notification.", e, intent);
}
return;
}

final String info = notificationDetails.shownNotificationsInfo;
if (!StringUtils.isNullOrEmpty(info)) {
final ShownNotificationsPreferences preferences = new ShownNotificationsPreferences(context);
preferences.saveShownNotificationInfo(info);
}

try {
FlutterLocalNotificationsPlugin.scheduleNextNotification(context, notificationDetails);
} catch (Exception e) {
fault("Exception while preparing next notification.", e, intent);
return;
}
}
return;
}

final String info = notificationDetails.shownNotificationsInfo;
if (!StringUtils.isNullOrEmpty(info)) {
preferences.saveShownNotificationInfo(info);
}

try {
FlutterLocalNotificationsPlugin.scheduleNextNotification(context, notificationDetails);
} catch (Exception e) {
fault("Exception while preparing next notification.", e, intent);
return;
}
}
}

private void fault(String message, Intent intent) {
fault(message, null, intent);
}

private void fault(String message, Exception e, Intent intent) {
Bundle bundle = intent.getExtras();
StringBuilder sb = new StringBuilder();
if (bundle != null) {
sb.append("{\n");
for (String key : bundle.keySet()) {
sb.append("\t")
.append(key)
.append(" : ")
.append(bundle.get(key) != null ? bundle.get(key) : "NULL");
sb.append("\n");
}
sb.append("}");
} else {
sb.append("NULL");
}

StringBuilder msg = new StringBuilder(message);
msg.append("\n");
if (e != null) {
msg.append("Exception: ").append(e).append("\n");
private void fault(String message, Intent intent) {
fault(message, null, intent);
}
msg.append("Intent extras: ");
msg.append(sb);

if (e != null) {
StringWriter errors = new StringWriter();
e.printStackTrace(new PrintWriter(errors));
msg.append("\n").append("Exception Stack trace:\n").append(errors);
}
private void fault(String message, Exception e, Intent intent) {
Bundle bundle = intent.getExtras();
StringBuilder sb = new StringBuilder();
if (bundle != null) {
sb.append("{\n");
for (String key : bundle.keySet()) {
sb.append("\t")
.append(key)
.append(" : ")
.append(bundle.get(key) != null ? bundle.get(key) : "NULL");
sb.append("\n");
}
sb.append("}");
} else {
sb.append("NULL");
}

throw new RuntimeException(msg.toString());
}
StringBuilder msg = new StringBuilder(message);
msg.append("\n");
if (e != null) {
msg.append("Exception: ").append(e).append("\n");
}
msg.append("Intent extras: ");
msg.append(sb);

if (e != null) {
StringWriter errors = new StringWriter();
e.printStackTrace(new PrintWriter(errors));
msg.append("\n").append("Exception Stack trace:\n").append(errors);
}

throw new RuntimeException(msg.toString());
}
}

0 comments on commit 246f490

Please sign in to comment.