Closed cruzach closed 3 years ago
I'm having the same problem. Works on iOS in all cases and on Android if app is started but not if app is killed. SDK39, testing on Samsung Galaxy S20, Android 10.
I tried running the "should-work solution" from @sjchmiela an my device (running it through Expo) but I seem to get the same problem.
If app is open in background: => App started Listener registered in global scope => Push received by phone and clicked on Global scope listener triggered Global scope listener removed
If app + Expo are killed => Push received by phone and clicked on (This starts the app) Listener registered in global scope
=> The listner is never triggered
app + Expo
Do you mean you're testing the behavior in Expo client? Frankly speaking I haven't been testing this in Expo client, only in bare workflow. Maybe the problem lies here? π Expo client has some middleware code that in theory could consume the notification before the app would be able to receive itβ¦
Is there anyone here that wasn't able to receive the notification response in bare workflow?
Is there anyone here that that is able to reproduce this issue in a standalone app with either
Another thing is that I think in upcoming SDK40 it may actually start to work as we've introduced some behind-the-scene changes that could fix it, but we won't know for sure until we release it! π (It does work when I test it in bare workflow.)
how exactly does your solution work in the case where the addNotificationResponseReceivedListener is not getting fired at all?
Well, my solution only works if it is getting fired. π
Tested on Motorola - moto g pro device.
I actually have that one as my test device! In bare workflow I wasn't able to make it not work.
I have the same problem with the addNotificationResponseReceivedListener not getting triggered if I run it in the Expo client as if I'm running the stand alone app.
When I tried your solution I ran it in the expo client. I will have a go and try it in a stand alone app too. It just takes a little longer as I will upload it to Google play for testing since I don't have any development platform for Android.
I am testing with Expo client, but also this bug is present on a released app in production, available on Google Play store. As I said it is important for us that we could use navigation (react navigation) because tapping on notification we want to open a certain modal. Even if we use a workaround which is available with react-navigation 5 where you can access navigation in App file it will not fix this issue since the code in the response of addNotificationResponseReceivedListener will never execute. In any case since iOS obviously supports that, and that should be the main functionality of this event, we expect it to work, thus the bug.... Sorry for my tone, but this was also been the issue with older Expo versions, but then at least it worked on some Android devices, now it doesn't work at all. I think it would be to late for us to wait version Expo 40.
I'm just trying to see if my issue is specific to me or not so that maybe we can file a new issue and get a reproducible demo for the Expo team.
To be clear, I'm assuming it will always be broken through the Expo client, I don't really care about that working since it's not what users use. Branch also doesn't work through Expo client so I'm kind of already used to these quirks. π
If addNotificationResponseReceivedListener does not work for you in Standalone Managed 39.0 Android no matter where you put the listener, can you put a like on this comment?
Also, can anyone tell me, what could cause a listener to get installed to be uninstalled...perhaps there is some code running later that is invalidating it...like it's overwriting it or something, idk. I'm going to work all day today to try to get it either working or a reproducible demo for the Expo team.
After 20+ hours on this problem I think I was able to track down the issue but I tried hard to create a MCVE but could not do it :(
My app has a logged out mode and logged in mode. When I was logged out, I noticed that Android would read the notification from a killed state. When I was logged in, it wouldn't. This means I was doing something further in those components that interfered with the addNotificationResponseReceivedListener handler that I initialized literally at the very entrance to my application.
After turning things off and on and re-building...I eventually commented out this block of code:
Location.startLocationUpdatesAsync(backgroundLocationUpdateTaskName, {
// Lowest = 3KM, Low = 1 KM, Balanced = 100M, High = 10M, Highest = 1M
// We use High, which is accurate to within 10m, should be enough for this app, since we don't do maps.
accuracy: LocationAccuracy.High,
timeInterval: 60000, // in ms
// Receive updates only when the location has changed by at least this distance in meters
distanceInterval: 60000,
});
and voila, it started working again from a dead start consistently. This tells me that there is some interaction under the hood between startLocationUpdatesAsync and addNotificationResponseReceivedListener on standalone Android.
Trying to find a workaround, I tried adding a timeout to start the startLocationUpdatesAsync function and it worked the first time that the app updated to a new version, but afterwards if the app was killed without being able to turn off the background job (it is a background job after all), next time I open the app the "Location Icon" on Android on the top status bar is immediately on and I go back to the same problem.
Essentially, when the background location is on in my app, notifications on standalone Android do not get read from a dead start. However, in the test app I made, it did work so I understand why this is hard to debug.
The best I can do at this moment is turn off the background task when the user leaves the app so that it only runs when the app is not-killed and then when they do kill it, if they re-open it with a push notification it will work (assuming I also have the delay on starting startLocationUpdatesAsync).
It's all really messy but hopefully this can help get to the root of the problem and maybe others who are experiencing this will realize that they are also using background location and can potentially try turning it off and testing.
@milennaj @Maoravitan @coopbri @beDenz @KlasRobin - Are you guys using any background tasks on Standalone Android? If you are, are you also using React-Navigation as well since others reporting this problem are also using that library?
cc @cruzach - Do you have any thoughts on what might be going on or things I can try?
PS android.useNextNotificationsApi is set to true for me ;)
Want to mention that legacy notification was not firing event for me on sdk 39, even if declared globally.
Only expo-notifications package was working and only if addNotificationResponseReceivedListener
was declared globally
@Aryk - Your discovery that removing Location.startLocationUpdatesAsync
from the equation seems consistent with what I saw with my async font loading. When my app was loading fonts async before rendering my notification handler component, addNotificationResponseReceivedListener
would not fire from killed state.
Once I moved that async work to after addNotificationResponseReceivedListener
, it works from killed state.
@sealedHuman - that's interesting...all this tells me is that whatever is happening under the hood for addNotificationResponseReceivedListener is very flakey...seemingly un-related items are cross-interacting with it.
It seems like a pretty serious issue, because literally for any Expo users out there...notifications from a dead start on android could just stop working simply because they wanted to add some unrelated XYZ feature which gets enabled further down on bootup.
@cruzach @ide - Do you guys happen to have any idea what could be causing addNotificationResponseReceivedListener to get disabled by seemingly unrelated items down-the-line on bootup? This could maybe help me create a MCVE for you guys so we can get this solved.
@Aryk I recommend trying out the changes being introduced in https://github.com/expo/expo/pull/10811 (they're JS-only, so it should be perfectly doable in the managed workflow) and seeing if that helps. I would have to take a deeper look at expo-task-manager
(Location.startLocationUpdates
calls directly to the task manager) before speaking on if that was having any impact on expo-notifications
@cruzach I have tried the solution introduced in #10811 . It doesn't work. I will try again disabling async font loading.
@sjchmiela I have tried both solutions in managed workflow (standalone app)
nothing seems to be working. Do you have any working demo?
@Aryk I recommend trying out the changes being introduced in #10811 (they're JS-only, so it should be perfectly doable in the managed workflow) and seeing if that helps. I would have to take a deeper look at
expo-task-manager
(Location.startLocationUpdates
calls directly to the task manager) before speaking on if that was having any impact onexpo-notifications
I looked at that code...but how exactly can it help? It still calls addNotificationResponseReceivedListener and relies on that to actually run it's callback.
What the hook ensures is that the notification response listener gets registered as early as it can (in the global scope of the app) and not as a result of any component code which is one of the problems people have run into in the past.
I'm not yet able to explain why triggering an asynchronous function in global scope would interact with adding a notification response listener without flapping arms in the air and stating imprecise possible reasons.
Regarding the fact that removing Location.startLocationUpdatesAsync
and asynchronous font loading seemingly removes the issue β I'm not sure starting location updates or font loading in global scope is the way to do it (none of the examples available try to do so, for location you first need to ensure you have the right permissions, for fonts it simply doesn't make sense). Sorry for asking this again and again β are you sure the issue remains if you move the listener to global scope of the app?
@sjchmiela - Thanks for taking the time. I've mentioned it above in my essay comment ;) Yes I've tried putting this:
Notifications.addNotificationResponseReceivedListener(
response => Alert.alert(undefined, "first")
)
in the global scope at the very very very top of my App so that it's literally one of the first things running...and as I mentioned it does work! BUT only if I do not call Location.startLocationUpdates
at all down the line, and by down the line I mean in a component callback, it's not even in global scope.
Also, on standalone android, while the location task is on, the addNotificationResponseReceivedListener also won't receive calls from a dead start, so I need to turn it off when users kill the app.
That is why I have to essentially disable it for the first 6 seconds of my app bootup and then initialize it and only then notifications work from a dead start on standalone android.
This is why I don't understand why https://github.com/expo/expo/pull/10811 would work since it's still relying on the same call.
@sjchmiela Sorry for misleading comment about async font loading. I had a hunch that loading font taking time to initiate the app from kill mode. But it has nothing to do here.
I will try #10811 again with a fresh app. Maybe something else is preventing it to work.
I know that startLocationUpdates has event emitters and has caused problems even in the previous 38 release so my hunch is that there is some collison with the events there and that it's still not 100% stable.
When you mentioned about the async font loading, I was suspicious that it was actually related because doesn't really do anything with event emitters that could interrupt receiving the notifications.
is there a useInitialNotificationResponse class components example?
new bug? now addNotificationResponseReceivedListener and addNotificationReceivedListener not work at all in Android not background and not foreground and not killed... π€―
Hi @sjchmiela, as @Aryk I have refactored the code and put addNotificationResponseReceivedListener at the top of App with appropriate navigation to modals when notifications is received. I can confirm that event is fired only when app is running in foreground, not when app process is not running. This happens on app that is available on Google Play store, and has "useNextNotificationsApi": true in app.json. Phone that is used for testing is Motorola moto g pro. Location is not used in our app. If this helps this is App.tsx of our app:
import React, { useState, useEffect } from "react"; import { StatusBar, StyleSheet } from "react-native"; import { AppearanceProvider } from "react-native-appearance"; import { Provider } from "react-redux"; import { Container, Root } from "native-base"; import { store } from "./store"; import * as Font from "expo-font"; import { AppLoading } from "expo"; import { Ionicons } from "@expo/vector-icons";
import AppNavigator from "./navigation/AppNavigator"; import interceptors from "./interceptors";
import as Notifications from "expo-notifications"; import moment from "moment"; import { CloseMonthWarningTag, CloseMonthReminderTag, dateFormat, } from "./constants/constants"; import { navigationRef } from "./RootNavigation"; import as RootNavigation from "./RootNavigation.js";
export default function App(props) { Notifications.setNotificationHandler({ handleNotification: async () => ({ shouldShowAlert: true, shouldPlaySound: false, shouldSetBadge: true, }), });
useEffect(() => { const subscription = Notifications.addNotificationResponseReceivedListener( (response) => { if (response.notification !== null) { let tag = response.notification.request.content.data.tag; tag === CloseMonthWarningTag ? RootNavigation.navigate("CloseMonthWarning", { date: moment().format(dateFormat), }) : tag === CloseMonthReminderTag ? RootNavigation.navigate("CloseMonth") : RootNavigation.navigate("Hours", { currentDate: moment().format(dateFormat), }); } } ); return () => { subscription.remove(); }; }, []);
interceptors.setupInterceptors();
const [isLoadingComplete, setLoadingComplete] = useState(false); if (!isLoadingComplete && !props.skipLoadingScreen) { return ( <AppLoading startAsync={loadResourcesAsync} onError={handleLoadingError} onFinish={() => handleFinishLoading(setLoadingComplete)} /> ); } else { return (
);
} }
async function loadResourcesAsync() { await Promise.all([ Font.loadAsync({ Ubuntu: require("./assets/fonts/Ubuntu-Regular.ttf"), Bold: require("./assets/fonts/Ubuntu-Bold.ttf"), Roboto_medium: require("native-base/Fonts/Roboto_medium.ttf"), ...Ionicons.font, }), ]); }
function handleLoadingError(error) { console.warn(error); }
function handleFinishLoading(setLoadingComplete) { setLoadingComplete(true); }
const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#EEEEEE", height: "100%", }, });
I don't see what else we can do to make it work?
Hello guys, I'm facing the same issue: foreground notifications works perfectly on android, but addNotificationResponseReceivedListener
doesn't emit when the app is closed or killed. I'm also using the expo SDK 39
@milennaj @LucasPMM - Can you guys comment if you are using background tasks like startLocationUpdatesAsync? If you are, try commenting it out and seeing if starts working.
@milennaj you are still putting the listener within your component and in a useEffect. This is the confirmed bug, reading the discussion above the potential solution they are proposing is to initiate the listener outside the component.
Did as this example showed (with a class-based App
component instead of a functional one) and using this navigation technique (because I needed to navigate to some screens when opening notifications) but got no luck either :(
Using SDK 38 and running a built .apk; received notifications in every scenario, but could handle them as I wanted to only when app is on the foreground or background (not working with the app closed).
I met this issue at Android using Expo SDK 39.0.0 with FCM. Solved using work around from above comment. Steps of my issue:
https://github.com/expo/expo/issues/9866#issuecomment-715486316 workaround -> useLayoutEffect instead of useEffect
I have try LegacyNotifications.addListener, class component, useLayoutEffect, top level, all does not work when app is killed.
I am using sdk39.
I have set useNextNotificationsApi to true.
A hint, when tap a killed expo notification, then it open the expo client. the console show this "Finished building JavaScript bundle in 276ms." why it rebuild the bundle?
As sdk40 have come out, does this issue resolved?
It is resolved. Use the new hook useLastNotificationResponse
. You can find more details in doc -https://docs.expo.io/versions/v40.0.0/sdk/notifications/#uselastnotificationresponse-undefined--notificationresponse--null
It is resolved. Use the new hook
useLastNotificationResponse
. You can find more details in doc -https://docs.expo.io/versions/v40.0.0/sdk/notifications/#uselastnotificationresponse-undefined--notificationresponse--null
I am trying to implement the example but with no success. This is part of my code:
const lastNotificationResponse = Notifications.useLastNotificationResponse();
useEffect(() => {
if (lastNotificationResponse && lastNotificationResponse.actionIdentifier === Notifications.DEFAULT_ACTION_IDENTIFIER) {
handlePush(lastNotificationResponse);
}
}, [lastNotificationResponse]);
const handlePush = async ({ notification }: any) => {
// ...more code <<<<< --------- it never reaches to this point when the app has been killed.
}
Am I doing something wrong? Thanks
It is resolved. Use the new hook
useLastNotificationResponse
. You can find more details in doc -https://docs.expo.io/versions/v40.0.0/sdk/notifications/#uselastnotificationresponse-undefined--notificationresponse--null
Just tested the issue is still there.
I still have to use exp.notification
to get launch notification on iOS and addNotificationResponseReceivedListener
outside any component on Android.
Any tips?
@maurohmartinez I am getting it to work with your exact code (only importing my async function where I destructure notification). Is your lastNotificationResponse correctly identified on app start?
I have my hook as the first hook being fired, i.e.:
export default function App() {
const lastNotificationResponse = Notifications.useLastNotificationResponse();
@alexandrius try if your hook is the first thing being initialized on app start? Works fine for me, had to do a bit of a workaround to get the navigation container to properly handle the incoming notification link as it is received before the navigationcontainer has time to initialize.
@maurohmartinez I am getting it to work with your exact code (only importing my async function where I destructure notification). Is your lastNotificationResponse correctly identified on app start?
I have my hook as the first hook being fired, i.e.:
export default function App() { const lastNotificationResponse = Notifications.useLastNotificationResponse();
@alexandrius try if your hook is the first thing being initialized on app start? Works fine for me, had to do a bit of a workaround to get the navigation container to properly handle the incoming notification link as it is received before the navigationcontainer has time to initialize.
My mistake... it works on Android (was trying on iOS). In my case, it doesn't even need to be placed right after export default function App() {
but again, it might be just in my case.
Thanks!
It is resolved. Use the new hook
useLastNotificationResponse
. You can find more details in doc -https://docs.expo.io/versions/v40.0.0/sdk/notifications/#uselastnotificationresponse-undefined--notificationresponse--null
This is not completed resolved if you are using Location.startLocationUpdates
as well. The addNotificationResponseReceivedListener
from useLastNotificationResponse
somehow interacts and causes an issue from opening a notification from a dead-start of the app.
See my comment above: https://github.com/expo/expo/issues/9866#issuecomment-724829714
Perhaps it make sense to split this out into a separate issue at this point? @cruzach
It is resolved. Use the new hook
useLastNotificationResponse
. You can find more details in doc -https://docs.expo.io/versions/v40.0.0/sdk/notifications/#uselastnotificationresponse-undefined--notificationresponse--null
Thanks a lot. Can confirm that it is now working on android with the new hook. π
It is resolved. Use the new hook
useLastNotificationResponse
. You can find more details in doc -https://docs.expo.io/versions/v40.0.0/sdk/notifications/#uselastnotificationresponse-undefined--notificationresponse--null
I confirmed that Android works now, but ios 12 does not work.
any other guys have the same issue on ios?
Hi @imhazige, I had issues on iOS 14, and still on Android for some reason (I think it had to do with the navigation mounting or something). I know this is not an ideal solution, but I switched to OneSignal for our app and it's been working great on both platforms (minus the typical FCM/APNs pitfalls, particularly slightly delayed notifications). This may be considered off-topic for the thread, but wanted to mention my success story just to indicate it as an option for you. Keep in mind it is a library with native bindings, so the Expo bare workflow is required if you choose to go that route.
I have no doubt the Expo notifications API will continue to improve over time, but I did not have time to wait, unfortunately.
Hi @imhazige, I had issues on iOS 14, and still on Android for some reason (I think it had to do with the navigation mounting or something). I know this is not an ideal solution, but I switched to OneSignal for our app and it's been working great on both platforms (minus the typical FCM/APNs pitfalls, particularly slightly delayed notifications). This may be considered off-topic for the thread, but wanted to mention my success story just to indicate it as an option for you. Keep in mind it is a library with native bindings, so the Expo bare workflow is required if you choose to go that route.
I have no doubt the Expo notifications API will continue to improve over time, but I did not have time to wait, unfortunately.
@coopbri
Thank you for the response.
I am using SDK40 and it works on android, for ios it seems to have this issue (https://github.com/expo/expo/issues/11343) need to be fixed.
I have no choice for now as I have to bind to expo managed flow. Onesignal is better choice if I can use bareflow.
Issue has been closed for fixes have been merged, please allow up to 24 hours for them to be available when you run expo build:ios
(it's pretty late where I am and although I believe there will be no problems when we deploy to production I want to be a responsible citizen and not deploy and go to sleep).
As a foretaste and to some degree proof let me share with you this video β https://www.dropbox.com/s/u2ih7umzt1zbxbp/RPReplay_Final1608160452.mp4?dl=0 π
Fix has been deployed to production Turtle builders! π All iOS apps built after December 17, 2020, 15:45 UTC will have fixes included and should not longer suffer from this problem.
This being said, let us know if this or similar problem ever rises again!
@sjchmiela - Just upgraded to SDK 40
On my Galaxy S8, standalone app, managed, with Android Version 9 (I cannot upgrade the OS bc phone is not supported), the problem still persists.
See above: https://github.com/expo/expo/issues/9866#issuecomment-724829714
Yes, I've also tried useLastNotificationResponse
, but as I suspected in my previous comment, because it relies on the same hook, it still didn't work.
I've tried to make a minimal repro case but seems I can't reproduce it without the complexity of my app.
Should I make a new issue for this?
Can anyone tell me if they can do:
1) Open notification from dead start on Android version 9. 2) Have background locations already running on Always via hasStartedLocationUpdatesAsync when the app is being opened.
While background location updates are on, the notifications are not being received from a dead start. When I turned it off, it works.
Can anyone tell me if they can do:
- Open notification from dead start on Android version 9.
- Have background locations already running on Always via hasStartedLocationUpdatesAsync when the app is being opened.
While background location updates are on, the notifications are not being received from a dead start. When I turned it off, it works.
For me notifications aren't wotking even without location updates. I still use https://github.com/expo/expo/issues/9866#issuecomment-743454778 this workaround
Some changes in the following packages that may fix this issue have just been published to npm under next
tag π
π¦ Package | π’ Version | βοΈ Pull requests | π Release notes |
---|---|---|---|
expo-notifications | 0.9.0 | #11382 | CHANGELOG.md |
If you're using bare workflow you can upgrade them right away. We kindly ask you for some feedbackβeven if it works π
They will become available in managed workflow with the next SDK release π
Happy Coding! π
Fix has been deployed to production Turtle builders! π All iOS apps built after December 17, 2020, 15:45 UTC will have fixes included and should not longer suffer from this problem.
This being said, let us know if this or similar problem ever rises again!
Just to confirm, this works for me. on ios and android. have not see problem yet. I am using SDK 40.
Fix has been deployed to production Turtle builders! π All iOS apps built after December 17, 2020, 15:45 UTC will have fixes included and should not longer suffer from this problem. This being said, let us know if this or similar problem ever rises again!
Just to confirm, this works for me. on ios and android. have not see problem yet. I am using SDK 40.
But do you received a warning expected expo-notification V 0.8.2?
Some changes in the following packages that may fix this issue have just been published to npm under
next
tag ππ¦ Package π’ Version βοΈ Pull requests π Release notes expo-notifications 0.9.0 #11382 CHANGELOG.md If you're using bare workflow you can upgrade them right away. We kindly ask you for some feedbackβeven if it works π
They will become available in managed workflow with the next SDK release π
Happy Coding! π
will work with the expo SDK 40?
@webuijorgeGL - https://github.com/expo/expo/pull/11382 is in sdk 40, if that's what you're looking for. you cannot, however, use expo-notifications 0.9.0 in sdk 40 - that includes other changes (see the changelog).
https://github.com/expo/expo/blob/sdk-40/packages/expo/bundledNativeModules.json#L103
Still doesn't work with latest SDK
Any news ?
In my case addNotificationResponseReceivedListener
is not working on background and killed app. I am using Expo SDK 42
@MrIceman @Guilhemfuel Just use the useLastNotificationResponse
hook
@MrIceman @Guilhemfuel Just use the
useLastNotificationResponse
hook
It doesn't work either on background and killed. The response will be null...
π Bug Report
Summary of Issue
If you call
Notifications.addResponseReceivedListener
inuseEffect
for example, the listener will not be triggered when opening an app from a completely killed state via a notification. This can also be demonstrated by adding a timeout tocomponentDidMount
as shown here. Without 1 second timeout- events come through; with 1 second timeout- event's do not come through.I should note that the emit method is getting called in this case.
Environment - output of
expo diagnostics
& the platform(s) you're targetingReproducible Demo
https://snack.expo.io/@charliecruzan/push-notifications
Steps to Reproduce
Need to run the app as a published experience or standalone app (or bare debug build) to see the behavior. Press "show notification" and kill the app, tap the notification, observe that response listener isn't triggered.
Workaround
The workaround (and possibly long-term solution) is to add the listener outside of any component, then it works as expected (presumably bc of how much sooner it's getting called?). I changed the docs to suggest this so fewer people run into this issue