Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/2248.analytics for notify #17

Merged
merged 4 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions flutter_local_notifications/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
# [17.0.3]

* [Android] Added `shownNotificationsInfo` param to `NotificationDetails`. If you pass this param
greymag marked this conversation as resolved.
Show resolved Hide resolved
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.

* [Android] Fixed: `inexactWindowLengthMillis` always null in `NotificationDetails`.

# [17.0.2]

* [Android] Remove old corrupted notifications.
Expand Down
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 @@ -152,6 +152,8 @@ public class FlutterLocalNotificationsPlugin
private static final String GET_NOTIFICATION_CHANNELS_METHOD = "getNotificationChannels";
private static final String START_FOREGROUND_SERVICE = "startForegroundService";
private static final String STOP_FOREGROUND_SERVICE = "stopForegroundService";
private static final String GET_SHOWN_NOTIFICATIONS_INFO = "getShownNotificationsInfo";
private static final String CLEAR_SHOWN_NOTIFICATIONS_INFO = "clearShownNotificationsInfo";
private static final String PENDING_NOTIFICATION_REQUESTS_METHOD = "pendingNotificationRequests";
private static final String GET_ACTIVE_NOTIFICATIONS_METHOD = "getActiveNotifications";
private static final String SHOW_METHOD = "show";
Expand Down Expand Up @@ -1645,12 +1647,32 @@ public void fail(String message) {
case STOP_FOREGROUND_SERVICE:
stopForegroundService(result);
break;
case GET_SHOWN_NOTIFICATIONS_INFO:
getShownNotificationsInfo(result);
break;
case CLEAR_SHOWN_NOTIFICATIONS_INFO:
clearShownNotificationsInfo(result);
break;
default:
result.notImplemented();
break;
}
}

private void getShownNotificationsInfo(Result result) {
final ShownNotificationsPreferences prefs =
new ShownNotificationsPreferences(applicationContext);
final ArrayList<String> res = prefs.getShownNotificationsInfo();
result.success(res);
}

private void clearShownNotificationsInfo(Result result) {
final ShownNotificationsPreferences prefs =
new ShownNotificationsPreferences(applicationContext);
prefs.clearShownNotificationsInfo();
result.success(true);
}

private void pendingNotificationRequests(Result result) {
ArrayList<NotificationDetails> scheduledNotifications =
loadScheduledNotifications(applicationContext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@
/** Created by michaelbui on 24/3/18. */
@Keep
public class ScheduledNotificationReceiver extends BroadcastReceiver {

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)) {
Expand Down Expand Up @@ -93,6 +93,13 @@ public void onReceive(final Context context, Intent intent) {
return;
}

final String info = notificationDetails.shownNotificationsInfo;
greymag marked this conversation as resolved.
Show resolved Hide resolved
if (!StringUtils.isNullOrEmpty(info)) {
final ShownNotificationsPreferences preferences =
new ShownNotificationsPreferences(context);
preferences.saveShownNotificationInfo(info);
}

try {
FlutterLocalNotificationsPlugin.scheduleNextNotification(context, notificationDetails);
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.dexterous.flutterlocalnotifications;

import android.content.Context;
import android.content.SharedPreferences;

import java.util.ArrayList;
import java.util.Arrays;

public class ShownNotificationsPreferences {
private static final String SHARED_PREFS_FILE_NAME =
"flutter_local_notifications_plugin_shown_info";
private final String SHOWN_NOTIFICATIONS_INFO_KEY =
"com.dexterous.flutterlocalnotifications.SHOWN_NOTIFICATIONS_INFO_KEY";
private final String SHOWN_NOTIFICATIONS_INFO_DIVIDER = "/";

private final Context context;

public ShownNotificationsPreferences(Context context) {

this.context = context;
}

public void saveShownNotificationInfo(String info) {
final SharedPreferences pref = get();
final SharedPreferences.Editor editor = pref.edit();
String currentInfo = pref.getString(SHOWN_NOTIFICATIONS_INFO_KEY, "");
if (!currentInfo.isEmpty()) {
currentInfo = currentInfo + SHOWN_NOTIFICATIONS_INFO_DIVIDER + info;
} else {
currentInfo = info;
}
editor.putString(SHOWN_NOTIFICATIONS_INFO_KEY, currentInfo);
editor.apply();
}

public ArrayList<String> getShownNotificationsInfo() {
final SharedPreferences pref = get();
final String currentInfo = pref.getString(SHOWN_NOTIFICATIONS_INFO_KEY, "");
if (currentInfo.isEmpty()) {
return new ArrayList<>();
}
final String[] list = currentInfo.split(SHOWN_NOTIFICATIONS_INFO_DIVIDER);
return new ArrayList<>(Arrays.asList(list));
}

public void clearShownNotificationsInfo() {
final SharedPreferences pref = get();
final SharedPreferences.Editor editor = pref.edit();
editor.remove(SHOWN_NOTIFICATIONS_INFO_KEY);
editor.apply();
}

private SharedPreferences get() {
return context.getSharedPreferences(SHARED_PREFS_FILE_NAME, Context.MODE_PRIVATE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ public class NotificationDetails implements Serializable {
private static final String CUSTOM_LAYOUT_COLLAPSED_NAME = "customLayoutCollapsedName";
private static final String CUSTOM_LAYOUT_EXPANDED_NAME = "customLayoutExpandedName";
private static final String INEXACT_WINDOW_LENGTH_MILLIS = "inexactWindowLengthMillis";
private static final String SHOWN_NOTIFICATION_INFO = "shownNotificationsInfo";

public Integer id;
public String title;
Expand Down Expand Up @@ -208,6 +209,8 @@ public class NotificationDetails implements Serializable {
public Integer iconResourceId;
public Long inexactWindowLengthMillis;

public String shownNotificationsInfo;

public static NotificationDetails from(Map<String, Object> arguments) {
NotificationDetails notificationDetails = new NotificationDetails();
notificationDetails.payload = (String) arguments.get(PAYLOAD);
Expand Down Expand Up @@ -244,13 +247,6 @@ public static NotificationDetails from(Map<String, Object> arguments) {
notificationDetails.day = (Integer) arguments.get(DAY);
}

if (arguments.containsKey(INEXACT_WINDOW_LENGTH_MILLIS)) {
notificationDetails.inexactWindowLengthMillis =
(Long) arguments.get(INEXACT_WINDOW_LENGTH_MILLIS);
} else {
notificationDetails.inexactWindowLengthMillis = 0L;
}

readPlatformSpecifics(arguments, notificationDetails);
return notificationDetails;
}
Expand Down Expand Up @@ -325,6 +321,20 @@ private static void readPlatformSpecifics(
}
}
}

if (platformChannelSpecifics.containsKey(INEXACT_WINDOW_LENGTH_MILLIS)) {
notificationDetails.inexactWindowLengthMillis =
(Long) platformChannelSpecifics.get(INEXACT_WINDOW_LENGTH_MILLIS);
} else {
notificationDetails.inexactWindowLengthMillis = 0L;
}

if (platformChannelSpecifics.containsKey(SHOWN_NOTIFICATION_INFO)) {
notificationDetails.shownNotificationsInfo =
(String) platformChannelSpecifics.get(SHOWN_NOTIFICATION_INFO);
} else {
notificationDetails.shownNotificationsInfo = "";
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,42 @@ class FlutterLocalNotificationsPlugin {
}
}

/// Returns info that stored when notifications was shown.
/// See [AndroidNotificationDetails.shownNotificationsInfo]
Future<List<Map<String, dynamic>>> getShownNotificationsInfo() async {
if (defaultTargetPlatform != TargetPlatform.android) {
assert(
false,
'The method getShownNotificationsInfo available only for android.',
);
return const <Map<String, dynamic>>[];
}

final List<Map<String, dynamic>> res =
(await resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.getShownNotificationsInfo()) ??
const <Map<String, dynamic>>[];
return res;
}

/// Clear all stored info obout shown notifications.
Future<bool> clearShownNotificationsInfo() async {
if (defaultTargetPlatform != TargetPlatform.android) {
assert(
false,
'The method clearShownNotificationsInfo available only for android.',
);
return false;
}

final bool res = (await resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.clearShownNotificationsInfo()) ??
false;
return res;
}

/// Cancel/remove the notification with the specified id.
///
/// This applies to notifications that have been scheduled and those that
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'dart:ui';

import 'package:clock/clock.dart';
Expand Down Expand Up @@ -107,7 +108,7 @@ class MethodChannelFlutterLocalNotificationsPlugin
/// Android implementation of the local notifications plugin.
class AndroidFlutterLocalNotificationsPlugin
extends MethodChannelFlutterLocalNotificationsPlugin {
DidReceiveNotificationResponseCallback? _ondidReceiveNotificationResponse;
DidReceiveNotificationResponseCallback? _onDidReceiveNotificationResponse;

/// Initializes the plugin.
///
Expand All @@ -131,7 +132,7 @@ class AndroidFlutterLocalNotificationsPlugin
DidReceiveBackgroundNotificationResponseCallback?
onDidReceiveBackgroundNotificationResponse,
}) async {
_ondidReceiveNotificationResponse = onDidReceiveNotificationResponse;
_onDidReceiveNotificationResponse = onDidReceiveNotificationResponse;
_channel.setMethodCallHandler(_handleMethod);

final Map<String, Object> arguments = initializationSettings.toMap();
Expand Down Expand Up @@ -513,6 +514,27 @@ class AndroidFlutterLocalNotificationsPlugin
Future<bool?> canScheduleExactNotifications() async =>
await _channel.invokeMethod<bool>('canScheduleExactNotifications');

/// Returns info that stored when notifications was shown.
/// See [AndroidNotificationDetails.shownNotificationsInfo]
Future<List<Map<String, dynamic>>> getShownNotificationsInfo() async {
final List<Object?>? res =
await _channel.invokeMethod<List<Object?>>('getShownNotificationsInfo');
if (res == null || res.isEmpty) {
return <Map<String, dynamic>>[];
}
return res
.map((Object? e) => jsonDecode(e as String) as Map<String, dynamic>)
.toList();
}

/// Clear all stored info obout shown notifications.
Future<bool> clearShownNotificationsInfo() async {
final bool? res =
await _channel.invokeMethod<bool?>('clearShownNotificationsInfo');

return res ?? false;
}

AndroidNotificationSound? _getNotificationChannelSound(
Map<dynamic, dynamic> channelMap) {
final int? soundSourceIndex = channelMap['soundSource'];
Expand All @@ -531,7 +553,7 @@ class AndroidFlutterLocalNotificationsPlugin
Future<void> _handleMethod(MethodCall call) async {
switch (call.method) {
case 'didReceiveNotificationResponse':
_ondidReceiveNotificationResponse?.call(
_onDidReceiveNotificationResponse?.call(
NotificationResponse(
id: call.arguments['notificationId'],
actionId: call.arguments['actionId'],
Expand Down Expand Up @@ -637,7 +659,7 @@ class IOSFlutterLocalNotificationsPlugin
);
},
);

/// Sets badge number.
Future<void> setBadgeNumber(int value) =>
_channel.invokeMethod<bool>('setBadgeNumber', <String, int>{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ extension AndroidNotificationDetailsMapper on AndroidNotificationDetails {
'colorized': colorized,
'number': number,
'audioAttributesUsage': audioAttributesUsage.value,
'inexactWindowLengthMillis': inexactWindowLengthMillis,
'shownNotificationsInfo': shownNotificationsInfo,
}
..addAll(_convertActionsToMap(actions))
..addAll(_convertStyleInformationToMap())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ class AndroidNotificationDetails {
this.customLayoutCollapsedName,
this.customLayoutExpandedName,
this.inexactWindowLengthMillis,
this.shownNotificationsInfo,
}) : customLayoutLegacyName = customLayoutLegacyName ?? customLayoutName;

/// The icon that should be used when displaying the notification.
Expand Down Expand Up @@ -458,4 +459,9 @@ class AndroidNotificationDetails {
/// zero, inexact alarm will plan in this length, should be 10 minutes
/// or more, see more in docs https://developer.android.com/about/versions/14/changes/schedule-exact-alarms#use-cases
final int? inexactWindowLengthMillis;

/// Some info that will save in local store if notification show, to get
/// it from store use
/// [AndroidFlutterLocalNotificationsPlugin.getShownNotificationsInfo()].
final String? shownNotificationsInfo;
}
2 changes: 1 addition & 1 deletion flutter_local_notifications/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: flutter_local_notifications_plus
description: A cross platform plugin for displaying and scheduling local
notifications for Flutter applications with the ability to customise for each
platform.
version: 17.0.2
version: 17.0.3
homepage: https://github.com/Innim/flutter_local_notifications
repository: https://github.com/Innim/flutter_local_notifications
issue_tracker: https://github.com/Innim/flutter_local_notifications/issues
Expand Down