From 36e99059fef134b20481aff6f326075da1e74de0 Mon Sep 17 00:00:00 2001 From: Josh Burton Date: Tue, 30 Jul 2019 14:14:25 +1200 Subject: [PATCH 1/3] [iOS] Always passes full notification data to dart --- ios/Classes/FlutterLocalNotificationsPlugin.h | 2 +- ios/Classes/FlutterLocalNotificationsPlugin.m | 42 +++++++++---------- lib/src/flutter_local_notifications.dart | 21 ++++++---- lib/src/notification_app_launch_details.dart | 5 ++- lib/src/pending_notification_request.dart | 3 +- 5 files changed, 40 insertions(+), 33 deletions(-) diff --git a/ios/Classes/FlutterLocalNotificationsPlugin.h b/ios/Classes/FlutterLocalNotificationsPlugin.h index 5dcffa815..7245e04a6 100644 --- a/ios/Classes/FlutterLocalNotificationsPlugin.h +++ b/ios/Classes/FlutterLocalNotificationsPlugin.h @@ -3,5 +3,5 @@ @interface FlutterLocalNotificationsPlugin : NSObject + (bool) resumingFromBackground; -+ (void)handleSelectNotification:(NSString *)payload; ++ (void)handleSelectNotification:(NSDictionary *)data; @end diff --git a/ios/Classes/FlutterLocalNotificationsPlugin.m b/ios/Classes/FlutterLocalNotificationsPlugin.m index 1b0aca740..1a7a84486 100644 --- a/ios/Classes/FlutterLocalNotificationsPlugin.m +++ b/ios/Classes/FlutterLocalNotificationsPlugin.m @@ -50,8 +50,9 @@ @implementation FlutterLocalNotificationsPlugin NSString *const NOTIFICATION_ID = @"NotificationId"; NSString *const PAYLOAD = @"payload"; +NSString *const DATA = @"data"; NSString *const NOTIFICATION_LAUNCHED_APP = @"notificationLaunchedApp"; -NSString *launchPayload; + bool displayAlert; bool playSound; bool updateBadge; @@ -61,7 +62,7 @@ @implementation FlutterLocalNotificationsPlugin NSObject *_registrar; + (bool) resumingFromBackground { return appResumingFromBackground; } -UILocalNotification *launchNotification; +NSDictionary *launchNotification; typedef NS_ENUM(NSInteger, RepeatInterval) { EveryMinute, @@ -96,7 +97,8 @@ - (void)pendingNotificationRequests:(FlutterResult _Nonnull)result { @"id" : request.content.userInfo[NOTIFICATION_ID], @"title" : request.content.title, @"body" : request.content.body, - @"payload": request.content.userInfo[PAYLOAD] + @"payload": request.content.userInfo[PAYLOAD], + @"data": request.content.userInfo, }]; } result(pendingNotificationRequests); @@ -110,7 +112,8 @@ - (void)pendingNotificationRequests:(FlutterResult _Nonnull)result { @"id" : localNotification.userInfo[NOTIFICATION_ID], @"title" : localNotification.userInfo[TITLE], @"body" : localNotification.alertBody, - @"payload": localNotification.userInfo[PAYLOAD] + @"payload": localNotification.userInfo[PAYLOAD], + @"data": localNotification.userInfo }]; } result(pendingNotificationRequests); @@ -160,8 +163,8 @@ - (void)initialize:(FlutterMethodCall * _Nonnull)call result:(FlutterResult _Non authorizationOptions += UNAuthorizationOptionBadge; } [center requestAuthorizationWithOptions:(authorizationOptions) completionHandler:^(BOOL granted, NSError * _Nullable error) { - if(launchPayload != nil) { - [FlutterLocalNotificationsPlugin handleSelectNotification:launchPayload]; + if(launchNotification != nil) { + [channel invokeMethod:@"selectNotification" arguments:launchNotification]; } result(@(granted)); }]; @@ -179,8 +182,7 @@ - (void)initialize:(FlutterMethodCall * _Nonnull)call result:(FlutterResult _Non UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:notificationTypes categories:nil]; [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; if(launchNotification != nil) { - NSString *payload = launchNotification.userInfo[PAYLOAD]; - [channel invokeMethod:@"selectNotification" arguments:payload]; + [channel invokeMethod:@"selectNotification" arguments:launchNotification]; } result(@YES); } @@ -282,13 +284,8 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { } else if([CANCEL_ALL_METHOD isEqualToString:call.method]) { [self cancelAllNotifications:result]; } else if([GET_NOTIFICATION_APP_LAUNCH_DETAILS_METHOD isEqualToString:call.method]) { - NSString *payload; - if(launchNotification != nil) { - payload = launchNotification.userInfo[PAYLOAD]; - } else { - payload = launchPayload; - } - NSDictionary *notificationAppLaunchDetails = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:launchingAppFromNotification], NOTIFICATION_LAUNCHED_APP, payload, PAYLOAD, nil]; + NSDictionary *data = launchNotification; + NSDictionary *notificationAppLaunchDetails = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:launchingAppFromNotification], NOTIFICATION_LAUNCHED_APP, data, DATA, nil]; result(notificationAppLaunchDetails); } else if([INITIALIZED_HEADLESS_SERVICE_METHOD isEqualToString:call.method]) { result(nil); @@ -464,8 +461,8 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNot completionHandler(presentationOptions); } -+ (void)handleSelectNotification:(NSString *)payload { - [channel invokeMethod:@"selectNotification" arguments:payload]; ++ (void)handleSelectNotification:(NSDictionary *)data { + [channel invokeMethod:@"selectNotification" arguments:data]; } - (void)userNotificationCenter:(UNUserNotificationCenter *)center @@ -473,11 +470,11 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center withCompletionHandler:(void (^)(void))completionHandler NS_AVAILABLE_IOS(10.0) { if ([response.actionIdentifier isEqualToString:UNNotificationDefaultActionIdentifier]) { - NSString *payload = (NSString *) response.notification.request.content.userInfo[PAYLOAD]; + NSDictionary *data = response.notification.request.content.userInfo; if(initialized) { - [FlutterLocalNotificationsPlugin handleSelectNotification:payload]; + [FlutterLocalNotificationsPlugin handleSelectNotification:data]; } else { - launchPayload = payload; + launchNotification = data; launchingAppFromNotification = true; } @@ -486,7 +483,8 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { if (launchOptions != nil) { - launchNotification = (UILocalNotification *)[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey]; + UILocalNotification *notification = (UILocalNotification *)[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey]; + launchNotification = notification.userInfo; launchingAppFromNotification = launchNotification != nil; } @@ -503,7 +501,7 @@ - (void)applicationDidBecomeActive:(UIApplication *)application { - (void)application:(UIApplication*)application didReceiveLocalNotification:(UILocalNotification*)notification { - NSDictionary *arguments = [NSDictionary dictionaryWithObjectsAndKeys:notification.userInfo[NOTIFICATION_ID], ID,notification.userInfo[TITLE], TITLE,notification.alertBody, BODY, notification.userInfo[PAYLOAD], PAYLOAD, nil]; + NSDictionary *arguments = [NSDictionary dictionaryWithObjectsAndKeys:notification.userInfo[NOTIFICATION_ID], ID,notification.userInfo[TITLE], TITLE,notification.alertBody, BODY, notification.userInfo, DATA, nil]; [channel invokeMethod:DID_RECEIVE_LOCAL_NOTIFICATION arguments:arguments]; } diff --git a/lib/src/flutter_local_notifications.dart b/lib/src/flutter_local_notifications.dart index f0faed5c2..28dd1e971 100644 --- a/lib/src/flutter_local_notifications.dart +++ b/lib/src/flutter_local_notifications.dart @@ -1,19 +1,21 @@ -import 'dart:io'; import 'dart:async'; +import 'dart:io'; + import 'package:flutter/services.dart'; import 'package:meta/meta.dart'; import 'package:platform/platform.dart'; + import 'initialization_settings.dart'; import 'notification_app_launch_details.dart'; import 'notification_details.dart'; import 'pending_notification_request.dart'; /// Signature of callback passed to [initialize]. Callback triggered when user taps on a notification -typedef SelectNotificationCallback = Future Function(String payload); +typedef SelectNotificationCallback = Future Function(String payload, Map data); // Signature of the callback that is triggered when a notification is shown whilst the app is in the foreground. Applicable to iOS versions < 10 only typedef DidReceiveLocalNotificationCallback = Future Function( - int id, String title, String body, String payload); + int id, String title, String body, String payload, Map data); /// The available intervals for periodically showing notifications enum RepeatInterval { EveryMinute, Hourly, Daily, Weekly } @@ -107,7 +109,9 @@ class FlutterLocalNotificationsPlugin { Future getNotificationAppLaunchDetails() async { var result = await _channel.invokeMethod('getNotificationAppLaunchDetails'); return NotificationAppLaunchDetails(result['notificationLaunchedApp'], - result.containsKey('payload') ? result['payload'] : null); + result["data"], + result["data"]?.containsKey('payload') == true ? result['data']["payload"] : null, + ); } /// Show a notification with an optional payload that will be passed back to the app when a notification is tapped @@ -233,7 +237,8 @@ class FlutterLocalNotificationsPlugin { pendingNotification['id'], pendingNotification['title'], pendingNotification['body'], - pendingNotification['payload'])) + pendingNotification['payload'], + pendingNotification['data'])) .toList(); } @@ -262,14 +267,16 @@ class FlutterLocalNotificationsPlugin { Future _handleMethod(MethodCall call) { switch (call.method) { case 'selectNotification': - return selectNotificationCallback(call.arguments); + return selectNotificationCallback(call.arguments["payload"], call.arguments); case 'didReceiveLocalNotification': return didReceiveLocalNotificationCallback( call.arguments['id'], call.arguments['title'], call.arguments['body'], - call.arguments['payload']); + call.arguments['payload'], + call.arguments['data'] + ); default: return Future.error('method not defined'); } diff --git a/lib/src/notification_app_launch_details.dart b/lib/src/notification_app_launch_details.dart index 1d3be0315..f25421871 100644 --- a/lib/src/notification_app_launch_details.dart +++ b/lib/src/notification_app_launch_details.dart @@ -5,6 +5,7 @@ class NotificationAppLaunchDetails { /// The payload of the notification that launched the app final String payload; - const NotificationAppLaunchDetails( - this.didNotificationLaunchApp, this.payload); + final Map data; + + const NotificationAppLaunchDetails(this.didNotificationLaunchApp, this.data, this.payload); } diff --git a/lib/src/pending_notification_request.dart b/lib/src/pending_notification_request.dart index f4cb68e25..02191e759 100644 --- a/lib/src/pending_notification_request.dart +++ b/lib/src/pending_notification_request.dart @@ -3,7 +3,8 @@ class PendingNotificationRequest { final String title; final String body; final String payload; + final Map data; const PendingNotificationRequest( - this.id, this.title, this.body, this.payload); + this.id, this.title, this.body, this.payload, this.data); } From 0822696fc0c5e9f34711122361d9ce620f963035 Mon Sep 17 00:00:00 2001 From: Josh Burton Date: Tue, 30 Jul 2019 15:05:50 +1200 Subject: [PATCH 2/3] [android] passes notification data as map to dart side --- .../FlutterLocalNotificationsPlugin.java | 9 +++++++-- example/lib/main.dart | 7 +++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java b/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java index d45e50cf2..c3a8adbc3 100644 --- a/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java +++ b/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java @@ -14,6 +14,7 @@ import android.media.RingtoneManager; import android.net.Uri; import android.os.Build; +import android.os.Bundle; import android.text.Html; import android.text.Spanned; @@ -48,6 +49,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; @@ -821,8 +823,11 @@ public boolean onNewIntent(Intent intent) { private Boolean sendNotificationPayloadMessage(Intent intent) { if (SELECT_NOTIFICATION.equals(intent.getAction())) { - String payload = intent.getStringExtra(PAYLOAD); - channel.invokeMethod("selectNotification", payload); + + Map data = new HashMap(); + data.put(PAYLOAD, intent.getStringExtra(PAYLOAD)); + + channel.invokeMethod("selectNotification", data); return true; } return false; diff --git a/example/lib/main.dart b/example/lib/main.dart index 43874d1bf..53ebfdc16 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -523,10 +523,13 @@ class _HomePageState extends State { await flutterLocalNotificationsPlugin.cancelAll(); } - Future onSelectNotification(String payload) async { + Future onSelectNotification(String payload, Map data) async { if (payload != null) { debugPrint('notification payload: ' + payload); } + if (data != null) { + debugPrint('notification data: ' + payload.toString()); + } await Navigator.push( context, @@ -684,7 +687,7 @@ class _HomePageState extends State { } Future onDidReceiveLocalNotification( - int id, String title, String body, String payload) async { + int id, String title, String body, String payload, Map data) async { // display a dialog with the notification details, tap ok to go to another page await showDialog( context: context, From c7c4af06a681d110c2dc116d129ec502272149b4 Mon Sep 17 00:00:00 2001 From: Josh Burton Date: Tue, 30 Jul 2019 15:06:57 +1200 Subject: [PATCH 3/3] Removes unnecessary changes --- ios/Classes/FlutterLocalNotificationsPlugin.m | 2 -- lib/src/flutter_local_notifications.dart | 3 +-- lib/src/pending_notification_request.dart | 3 +-- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/ios/Classes/FlutterLocalNotificationsPlugin.m b/ios/Classes/FlutterLocalNotificationsPlugin.m index 1a7a84486..c940842b3 100644 --- a/ios/Classes/FlutterLocalNotificationsPlugin.m +++ b/ios/Classes/FlutterLocalNotificationsPlugin.m @@ -98,7 +98,6 @@ - (void)pendingNotificationRequests:(FlutterResult _Nonnull)result { @"title" : request.content.title, @"body" : request.content.body, @"payload": request.content.userInfo[PAYLOAD], - @"data": request.content.userInfo, }]; } result(pendingNotificationRequests); @@ -113,7 +112,6 @@ - (void)pendingNotificationRequests:(FlutterResult _Nonnull)result { @"title" : localNotification.userInfo[TITLE], @"body" : localNotification.alertBody, @"payload": localNotification.userInfo[PAYLOAD], - @"data": localNotification.userInfo }]; } result(pendingNotificationRequests); diff --git a/lib/src/flutter_local_notifications.dart b/lib/src/flutter_local_notifications.dart index 28dd1e971..27c2dd04c 100644 --- a/lib/src/flutter_local_notifications.dart +++ b/lib/src/flutter_local_notifications.dart @@ -237,8 +237,7 @@ class FlutterLocalNotificationsPlugin { pendingNotification['id'], pendingNotification['title'], pendingNotification['body'], - pendingNotification['payload'], - pendingNotification['data'])) + pendingNotification['payload'])) .toList(); } diff --git a/lib/src/pending_notification_request.dart b/lib/src/pending_notification_request.dart index 02191e759..f4cb68e25 100644 --- a/lib/src/pending_notification_request.dart +++ b/lib/src/pending_notification_request.dart @@ -3,8 +3,7 @@ class PendingNotificationRequest { final String title; final String body; final String payload; - final Map data; const PendingNotificationRequest( - this.id, this.title, this.body, this.payload, this.data); + this.id, this.title, this.body, this.payload); }