urbanairship / airship-flutter

Flutter integration
Other
17 stars 17 forks source link

onPushReceived not called on iOS when App is in Background #143

Closed jschmitz1 closed 1 year ago

jschmitz1 commented 1 year ago

❗For how-to inquiries involving Airship functionality or use cases, please contact (support)[https://support.airship.com/].

Preliminary Info

What Airship dependencies are you using?

airship_flutter: ^6.1.0

What are the versions of any relevant development tools you are using?

Flutter 3.3.6, I am using the development airship keys and running the app on a usb-connected iphone which is running ios 15.6

Report

What unexpected behavior are you seeing?

On iOS, neither listeners registered using Airship.onPushReceived, nor listeners registered using Airship.setBackgroundMessageHandler are called when the App is in the background. On Android however, my onPushReceived listener will be executed when a Push Notification is received while the App is in the background.

When the App is in the foreground, my listeners are called and execute in the way i expect them to. Also, interestingly, when i open the app by tapping the notification inside the ios pull-down notification centre instead of tapping on the app icon on the homescreen, my listener is also executed (But only in the moment i tap the notification).

What is the expected behavior?

iOS and Android should behave in the same way, since there does not seem to be platform specific ways to register these listeners

What are the steps to reproduce the unexpected behavior?

This is the code i use to initialize Airship in my flutter App: `Airship.takeOff(<-- airshipAppKeyDev -->, <-- airshipAppSecretDev -->); Airship.setUserNotificationsEnabled(true); Airship.addTags(<-- tag -->); Airship.setAutoBadgeEnabled(false);

Airship.onPushReceived.listen((event) async { debugPrint('Push Received $event');

Map data = json.decode(event.payload!["type"]);

debugPrint(data.toString());

data.forEach((key, value) {
  if (value) {
    store.dispatch(ToggleNavigationBadgeAction(navigationEntryID: key, value: true));
    store.dispatch(TriggerReduxPersistAction());
  }
});

Airship.setBadge(1);

}); `

Do you have logging for the issue?

These are the logs from the moment i put the App into the background:

[Airship] [D] AirshipKit/Analytics.swift applicationDidEnterBackground() [Line 278] Application did enter background. [Airship] [D] -[UAAutomationEngine updateTriggersWithScheduleID:type:argument:incrementAmount:] [Line 662] Updating triggers with type: 1 [Airship] [D] AirshipKit/Analytics.swift addEvent(_:) [Line 404] Adding app_background event 3BD09434-4BA2-4A02-AD7B-3085B6E6B444 [Airship] [D] AirshipKit/EventStore.swift storeEvent(withID:eventType:eventTime:eventBody:sessionID:context:) [Line 207] Event saved: 3BD09434-4BA2-4A02-AD7B-3085B6E6B444 [Airship] [D] AirshipKit/ExpirableTask.swift expire() [Line 92] Expiration handler not set, marking task as failed. [Airship] [D] AirshipKit/ExpirableTask.swift expire() [Line 92] Expiration handler not set, marking task as failed.

This is what is logged afterwards, when i open the app by clicking on the app icon:

[Airship] [D] AirshipKit/Analytics.swift applicationWillEnterForeground() [Line 270] Application will enter foreground. [connection] nw_read_request_report [C3] Receive failed with error "Software caused connection abort" [connection] nw_read_request_report [C2] Receive failed with error "Software caused connection abort" [connection] nw_read_requestreport [C1] Receive failed with error "Software caused connection abort" [Airship] [D] AirshipKit/Analytics.swift applicationDidTransitionToForeground() [Line 252] Application transitioned to foreground. [Airship] [D] -[UAAutomationEngine updateTriggersWithScheduleID:type:argument:incrementAmount:] [Line 662] Updating triggers with type: 0 [Airship] [D] -[UAAutomationEngine updateTriggersWithScheduleID:type:argument:incrementAmount:] [Line 662] Updating triggers with type: 8 [Airship] [D] AirshipKit/Analytics.swift addEvent(:) [Line 404] Adding appforeground event 33F348C5-E3C0-4045-917C-9BF0503E0C50 flutter: Notifications in storage: [Notification(notificationId=null, alert=null, title=null, subtitle=null, extras=null)] [Client] Updating selectors after delegate addition failed with: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service with pid 90 named com.apple.commcenter.coretelephony.xpc was invalidated from this process." UserInfo={NSDebugDescription=The connection to service with pid 90 named com.apple.commcenter.coretelephony.xpc was invalidated from this process.} [Airship] [D] AirshipKit/ContactAPIClient.swift resolve(channelID:completionHandler:) [Line 97] Resolving contact with channel ID 96dcd93e-2dba-4e55-b4e7-0fe94116aba0 [Airship] [D] AirshipKit/Push.swift badgeNumber [Line 653] Change Badge from 4, to 0 [Airship] [D] AirshipKit/EventStore.swift storeEvent(withID:eventType:eventTime:eventBody:sessionID:context:) [Line 207] Event saved: 33F348C5-E3C0-4045-917C-9BF0503E0C50 [Airship] [D] AirshipKit/RemoteDataAPIClient.swift fetchRemoteData(locale:randomValue:lastModified:completionHandler:) [Line 53] Request to update remote data: <UARequest: 0x28398ac80> [Client] Updating selectors after delegate addition failed with: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service with pid 90 named com.apple.commcenter.coretelephony.xpc was invalidated from this process." UserInfo={NSDebugDescription=The connection to service with pid 90 named com.apple.commcenter.coretelephony.xpc was invalidated from this process.} [Airship] [D] AirshipKit/ChannelRegistrar.swift handleRegistrationTask(:) [Line 218] Ignoring registration request, registration is up to date. [Airship] [D] AirshipKit/Contact.swift logOperationResult(operation:response:error:) [Line 1063] Contact update for operation: ContactOperation(type: AirshipKit.OperationType.resolve, payload: nil) failed with response: HTTPResponse(status=403) [Airship] [D] AirshipKit/RemoteDataManager.swift handleRefreshTask(_:) [Line 232] Remote data refresh finished with response: HTTPResponse(status=304) [Airship] [D] -[UAInboxMessageList updateMessages:]_block_invoke [Line 496] Inbox messages updated.

jschmitz1 commented 1 year ago

It would also be of great help to me, if you could give me some example code how i could instead process the Push Notification and its Payload on app launch. I don't necessarily need to process it in the background as soon as it arrives on the device, i just need to be sure i process it at all. I have looked through the documentation but couldn’t really find an example on this and had no luck trying to implement it myself. Thank you in advance

jyaganeh commented 1 year ago

Hi @jschmitz1, we're looking into this. I've been able to reproduce the behavior you're seeing, but haven't gotten to the bottom of it yet. I'll get back to you once we've identified the problem, and will check with the team to see if there's a way to delay handling of pushes received in the background like you describe. I'm not sure that's possible, currently, but we might be able to come up with something.

Thanks for the detailed report! 👍

rlepinski commented 1 year ago

@jschmitz1 On iOS, the app does not process the notification, instead the OS does that. Because of that, standard push notifications never actually wake up the app. To wake the app up with the push you need to send content-available: 1 (push api) or background processing (composer). Also, your app needs to be set up with background remote-notification capability. You can find that in the Xcode settings for the target.

jschmitz1 commented 1 year ago

Hey @rlepinski, thanks for your support. We tried setting content-available to true, and it did not change the behavior for us sadly. The required capabilities are already set in the Xcode target

rlepinski commented 1 year ago

I am still trying to figure this one out. I am unable to get any of the normal iOS callbacks to be called on a flutter app, with or without Airship. I verified things work on a native ap. I see this issue - https://github.com/flutter/flutter/issues/52895 not sure if its related but seems like its the same problem.

rlepinski commented 1 year ago

IMO its a flutter issue - https://github.com/flutter/flutter/issues/52895#issuecomment-1320749791

If they don't agree, then I might have to make some changes in the plugin.

As a workaround, you can use this branch for now - https://github.com/urbanairship/airship-flutter/tree/workaround-bg-push

Once I hear back from the Flutter devs I'll update you with a proper solution.

jschmitz1 commented 1 year ago

Thank you for the effort so far. I am looking forward to a reply from the flutter team.

I tried your workaround branch and sadly it does not seem to alter the behavior for me. Possibly i am missing something here. I register my listener via the onPushReceived.listen() method and i have the Background fetch and Remote notifications capabilities activated. Am i missing something?

jschmitz1 commented 1 year ago

Nevermind, i figured it out. Forgot to sent the content-available field again. Thank you for the workaround branch, it's working as expected now!

rlepinski commented 1 year ago

🎉

I will probably merge the workaround in the next release. The only issue it will cause is if our plugin is using it, then other plugins wont be able to use it since it calls through to the first plugin that returns true. I cant return false since flutter wont call the completion handler with nodata if it doesn't have a plugin that returns true https://github.com/flutter/engine/blob/main/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate.mm#L263