amplify-flutter
amplify-flutter copied to clipboard
Amplify.Notifications.Push.launchNotification returns null
Description
Hello, Amplify.Notifications.Push.launchNotification returns null each time I sent push notification to terminated app. Both foreground and background notifications are delivered and read properly. I tested this behavior on both Android and iOS devices (in release mode for iOS). App is killed (by swipe - not from editor), I sent push notification, it is delivered to phone, after clicking on it app is opened but launchNotification returns null. Here is log example from Android device in release mode:
W/FlutterJNI(29654): FlutterJNI.loadLibrary called more than once
W/FlutterJNI(29654): FlutterJNI.init called more than once
I/flutter (29654): 🚀 launchNotificationFromTerminated: null
I checked and launchNotification is not consumed anywhere before.
I attach code of my configuration and notifications service:
Configuration:
Future<void> main() async {
await configureApp();
runMain();
}
void runMain() {
runApp(MyApp());
}
Future<void> configureApp() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
const environment =
String.fromEnvironment('ENVIRONMENT_F', defaultValue: Environment.prod);
if (kDebugMode) {
await firebaseCrashlyticsInstance.setCrashlyticsCollectionEnabled(false);
}
FlutterError.onError = (errorDetails) {
firebaseCrashlyticsInstance.recordFlutterFatalError(errorDetails);
};
PlatformDispatcher.instance.onError = (error, stack) {
firebaseCrashlyticsInstance.recordError(error, stack, fatal: true);
return true;
};
await configureInjection(environment);
try {
if (Amplify.isConfigured) {
safePrint('Amplify is already configured. Skipping configuration.');
} else {
final auth = AmplifyAuthCognito();
final dataStorePlugin =
AmplifyDataStore(modelProvider: ModelProvider.instance);
final api = AmplifyAPI(modelProvider: ModelProvider.instance);
final pushPlugin = AmplifyPushNotificationsPinpoint();
PushNotificationsService.initalize(getIt<INotificationsRepository>());
pushPlugin.onNotificationReceivedInBackground(
PushNotificationsService.backgroundNotificationReceivedHandler);
await Amplify.addPlugins([dataStorePlugin, api, auth, pushPlugin]);
await Amplify.configure(amplifyconfig);
PushNotificationsService.launchNotificationFromTerminated();
PushNotificationsService.startListeningToForeground();
PushNotificationsService.onNotificationOpened();
}
} catch (e) {
safePrint('An error occurred while configuring Amplify: $e');
reportError(
exception: 'Aws Amplify framework could not be initialised',
reason: 'An error occurred while configuring Amplify: $e');
}
}
Service:
@injectable
@pragma('vm:entry-point')
class PushNotificationsService {
static late final PushNotificationsService _self;
static late final INotificationsRepository _notificationsRepository;
static late final StreamSubscription<PushNotificationMessage>
_foregroundStream;
static late final StreamSubscription<PushNotificationMessage>
_notificationsOpenedStream;
static late final StreamSubscription<String> _tokenStream;
PushNotificationsService._internal(
INotificationsRepository notificationsRepository) {
_notificationsRepository = notificationsRepository;
}
@factoryMethod
static PushNotificationsService initalize(
INotificationsRepository notificationsRepository) {
_self = PushNotificationsService._internal(notificationsRepository);
return _self;
}
static Future<bool> requestPermission() async {
final status = await Amplify.Notifications.Push.getPermissionStatus();
if (status == PushNotificationPermissionStatus.granted) {
return true;
}
if (status == PushNotificationPermissionStatus.shouldRequest ||
status == PushNotificationPermissionStatus.shouldExplainThenRequest) {
final status = await Amplify.Notifications.Push.requestPermissions();
await _notificationsRepository.saveNotifications(status);
return status;
}
return false;
}
static void startListeningToForeground() {
_foregroundStream = Amplify
.Notifications.Push.onNotificationReceivedInForeground
.listen(_foregroundNotificationReceivedHandler);
}
static void onNotificationOpened() {
_notificationsOpenedStream = Amplify.Notifications.Push.onNotificationOpened
.listen(_notificationOpenedHandler);
}
///Used to get device id in order to test notifications
static void onTokenReceived() {
_tokenStream = Amplify.Notifications.Push.onTokenReceived
.listen(_tokenReceivedHandler);
}
static void launchNotificationFromTerminated() {
final notification = Amplify.Notifications.Push.launchNotification;
print('🚀 launchNotificationFromTerminated: $notification');
if (notification != null) {
//do sth
}
}
static void _foregroundNotificationReceivedHandler(
PushNotificationMessage notification) {
print('🚀 foregroundNotificationReceivedHandler: $notification');
if (notification.title != null && notification.body != null) {
//display local notification
}
}
static Future<void> backgroundNotificationReceivedHandler(
PushNotificationMessage notification) async {
print('🚀 backgroundNotificationReceivedHandler: $notification');
///onNotificationOpened won't work on iOS because of flutter_local_notifications config
///https://github.com/aws-amplify/amplify-flutter/issues/3273 -> that's why navigation is done here
if (Platform.isIOS) {
//do sth
}
}
static void _notificationOpenedHandler(PushNotificationMessage notification) {
///Works only on Android as per comment above
print('🚀 _notificationOpenedHandler: $notification');
}
static void cancelStreams() {
_foregroundStream.cancel();
_notificationsOpenedStream.cancel();
_tokenStream.cancel();
}
}
Categories
- [ ] Analytics
- [ ] API (REST)
- [ ] API (GraphQL)
- [ ] Auth
- [ ] Authenticator
- [ ] DataStore
- [X] Notifications (Push)
- [ ] Storage
Steps to Reproduce
No response
Screenshots
No response
Platforms
- [X] iOS
- [X] Android
- [ ] Web
- [ ] macOS
- [ ] Windows
- [ ] Linux
Flutter Version
3.13.0
Amplify Flutter Version
1.4.0
Deployment Method
Amplify CLI
Schema
No response
Hi @szymondobrzanski
For iOS, if you enabled the background mode for your app, when a PN arrives on the phone after the app is killed, it will launch the app in the background. In this case, the message will be emitted via onNotificationReceivedInBackground. And then, when you click on the PN to open the app, as the app has already launched in the background, the message will be emitted via onNotificationOpened. If the background mode is not enabled, when you click the PN to launch the app, the message should be accessible via Amplify.Notifications.Push.launchNotification.
For android, while you are seeing Amplify.Notifications.Push.launchNotification returns null, do you receive any message event from other channels (onNotificationReceivedInBackground etc.)?
Hi @HuiSF, nope the only log I'm getting is from Amplify.Notifications.Push.launchNotification as stated above, other channels don't invoke any notifications.
@HuiSF any update from your side? Did you try to reproduce it?
Hey @HuiSF @dnys1 any update?
@szymondobrzanski, apologies on the delayed response. Can you share details of the android environment that you're using? Is it an emulator or a real, physical device? There was a similar issue (#3143) that we couldn't reproduce, and has since been closed tied to Android behavior .
On the iOS side, I believe it's expected behavior if the you have enabled background mode. We're still investigating this, so any further context/answers would be helpful! Thank you.
Hey @cwomack , thanks for response. I was using Android physical device with API Level 26. Why returning null after opening app from terminated state in iOS device would be expected behavior? Enabling background modes for iOS is one of configuration steps in Amplify documentation and there is none information that getLaunchNotification will return null for iOS by default.
@cwomack I am experiencing the same behavior on iOS. I have tried with both with background notification mode on and off based on your comment above. I have my notification code register with onNotificationOpened and check Amplify.Notifications.Push.launchNotification for notifications after the app has initialized with no luck.
Foreground notifications and background notifications both work as expected 100% of the time but when I kill the app trigger a notification, tap it to launch the app, it is not received by the launchNotification or onNotificationOpened.
Same issue on iOS, launchNotification and onNotificationOpened are both not trigged from terminated state.
@rest950 Do you have firebase messaging as part of the project?
If you are using firebase_messaging in any way in the project, iOS will stop behaving as expected, the two libraries are currently incompatible.
see #4237
Just to add to this, I am also experiencing this issue, but only on Android. I receive tokens, foreground and background notifications as expected but am unable to get access to the notification that launched the app. iOS works fine providing the firebase_messaging library isn't used in conjunction with Amplify. Frustratingly, I didn't experience this issue using Firebase, so we've swapped one problem for another.
@bitsplash-andy
My project no longer utilizes Firebase Messaging; it only relies on other Firebase services. However, on iOS in the terminated state, I am unable to trigger launchNotification or onNotificationOpened.
Regarding Android's ability to obtain launchNotification, in my tests, I found that it can only be trigged in a release build; it is not trigged in a debug build. Please give it a try and see if you encounter the same issue.
Hi @rest950
However, on iOS in the terminated state, I am unable to trigger launchNotification
Have you enabled the background mode for you iOS app?
If you have enabled background mode for your iOS app, when a push notification arrives on the device and your app is in the terminated state - the notification wakes your app up in the background. In this case, the notification will be sent to the callback of onNotificationReceivedInBackground - so there won't be a launchNotification.
I am unable to trigger onNotificationOpened.
Is this happening when you tap on a notification in the notification center or the PN banner to open the app?
I am still seeing this on iOS and we do not use any Firebase dependencies.
In our case this didn’t work on Android because we were using google-services 4.4.1 in our build.gradle.
Downgrading google-services to 4.3.15 resolved the issue. Not sure if the library is incompatible with 4.4.x versions at this time?
I am unable to trigger onNotificationOpened.
Is this happening when you tap on a notification in the notification center or the PN banner to open the app?
@HuiSF
After my attempts, I found that tap from notification center successfully triggered onNotificationOpened. However, tap from the PN Banner did not trigger onNotificationOpened. Is this the expected behavior?
Apologies for the delay. Thank you for the additional info. We will attempt to reproduce this with the additional info provided.