I am creating an Apple Watch application which has a chat feature. I would like to update the chat conversation whenever the watch app is running and an APNS message is received. I know in the AppDelegate, the function
application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject])
can be used, but that's only when the device application is running in the foreground, not background. In the WKUserNotificationInterfaceController, there is the function didReceiveRemoteNotification, but that is only used when using a Dynamic Notification. Is it possible to have the watch application process a remote notification that is received when not using Dynamic Notifications and is running in the foreground?
When creating a WatchKit app, and using APNS, there's few things you need to know about how a push notification actually work on the Watch side.
1) It's the iOS system which choose wether or not the notification is handled by Watch, based on user activity (iPhone locked/unlocked; Watch is used/not used...).
When one of your app’s local or remote notifications arrives on the user’s iPhone, iOS decides whether to display that notification on the iPhone or on the Apple Watch. See Doc Apple
2) For the iOS side you can handle all your notifications in didReceiveRemoteNotificationapplication(_:didReceiveRemoteNotification:fetchCompletionHandler:) ==> you can check wether or not your app is in foreground + handle silent notifications.
3) There is two distinct entry points for notifications on the Watch side:
As you said, there's theWKUserNotificationInterfaceController which is called when your WatchKit app is not used.
And there's didReceiveRemoteNotification(_:) in your ExtensionDelegate class, which is called when your WatchKit app is running. See here for complete documentation.
If you need to update your app while it's running, through APNS, you should handle it in this last method ;)
Hope it'll help you!
Related
Language: Swift 3
I'm using APNS in order to run MFMessageComposeViewController.
I don't know how to run my application when I get push notice.
The most important reason for this is that show text message view.
func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {
// Print notification payload data
print("My Push: \(data)");
// Run my application with MFMessageComposeViewController.
}
My application have a MFMessageComposeViewController so I'd like to call ViewController.swift some of methods.
How can I implement for this?
[Edit]
I mean I want to run my application automatically both screen on and off.
I usually do this job in android with no problem however iOS have a little bit trouble.
In iOS, there is no way to launch your app and display its window without explicit interaction from the user.
If your app is in the background, or is terminated when a push notification is received from APNS, iOS will display an alert to the user if one is defined in the push notification payload. The payload is not delivered to terminated or suspended apps unless the user taps on it, indicating that they want to engage with the alert.
An exception is made for VOIP, Apple Watch Complications, or FileProvider apps. These apps can use the PushKit framework to interface with APNS. This framework will launch the app if it is terminated, and deliver the notification payload to the app, even if it is in the background. This however will not display your app's window, only deliver the payload for processing. The user will either need to tap the app's icon on the home screen, or engage with a notification alert presented to make your app visible.
I am working with a messaging app and the app needs to receive the notification from the server (chat message). I am facing the problem when receiving the silent notification, most of the notification can’t received by the device, the scenario as below:
iOS 10 – Bring the app into background and push the silent notification, all notification can receive by the device.
iOS 11 – Bring the app into background and push the silent notification, device only can receive first 10 notifications and the rest of the notification disappear, I try to reboot the device and put the app into the background, able to receive another few notification and after that all not receive again.
Both iOS 10 and 11 – Kill the app and push the silent notification, all the notifications not receive.
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
logging(cls: self, mod: "APP", msg: "Did receive remote notification")
}
I try the Whatsapp push notification, even I kill the app and turn off the background app refresh in setting, all the notification still come in, I’m curious how Whatsapp handle the push notification?
How do I solve this notification issue?
Ideally you should use XMPP server base for live chat.
XMPP server has RTC ( Real time communication ) protocol, where 2 or more parties can connect, exchange document, live chat, video call, audio call etc.
You can also integrate websocket, for knowing user is online / office and other activities.
Integrating apple push, is not a 100% solution for live chat app like whatsapp, facebook messager, skype etc.
Get more information about Pushkit
From iOS 8, Apple introduced a new kind of push notification service called VoIP push. VoIP push is provided by the Apple's PushKit framework.
Normal push notification service has the following drawbacks,
Delivery: Apple doesn't promise a delivery time or priority.
Need permission to send push: Not all users understand that they need to allow it to receive calls.
The app doesn't know about a push until the user decides to act on the push.
Apple might throttle your push messages if you send too many.
Now coming to PushKit framework,
The benefits of PushKit framework are,
You don't need to allow push; it works without the user knowing about it.
Apple promises to deliver these push notifications high priority.
Your push notifications won't get lost.
You have total control over push notifications.
So, for messaging apps like yours, the usage of PushKit framework is recommended. Here is a tutorial on Github which explains how to implement PushKit in your apps.
when sending a background push with "content-available": "1", to an app that is killed by the user, the application is not launched into the background mode and the application:didReceiveRemoteNotification:fetchCompletionHandler: is not called as the Apple doc say:
Use this method to process incoming remote notifications for your app. [...]In addition, if you enabled the remote notifications background mode, the system launches your app (or wakes it from the suspended state) and puts it in the background state when a remote notification arrives.
However, the system does not automatically launch your app if the user has force-quit it.
My question is: Is there is any way to access this silent push payload the next time the user starts the application?
I tried using the launchOptions of the didFinishLaunchingWithOptions method but they do not contain the push payload.
NSDictionary *userInfo = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
My use case is that I rely only on the push channel to receive data to the app but the app cannot pull them.
Short answer is: no, you cannot.
You also won't be able to use VoIP pushes, the only option would be to use regular pushes with a push notification service extension. Share a keychain between your app and this extension, save the push payload in the keychain when receiving a notification and retrieve it with your app when it enters foreground.
Downside is you will need to present a visual notification to the user, but it can be silent, and you can choose to present whatever text you want (the best option will depend on what your app does and what's the purpose of this notification).
You may use a VoIP Push message, see here:
Voice Over IP (VoIP) Best Practices
There are many advantages to using PushKit to receive VoIP pushes:
[...]
Your app is automatically relaunched if it’s not running when a VoIP push is received.
[...]
Be aware, that your app must have background mode with VoIP capability enabled, which may be an issue for app store approval if misused.
Looking at the documentation, it seems like you should implement this method:
optional func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable : Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void)
Within that method, write your code to store the payload (userInfo). Maybe store it in the userDefaults temporarily. Then when the application launches, check to see if the payload is available.
I'm using a combination of Firebase and Batch for a chat like application.
When a push notification is received the app should be able to perform some tasks based on the data received in the notification.
From my understanding this can only be done in app states suspended -> active and not terminated.
I have it working when the app is in the foreground and also when closing the app via home button.
Should the device be locked however, didReceiveRemoteNotification:fetchCompletionHandler: is never called. At least not until the user interacts with the notification from notification center.
Is this correct? Can no work be done on a remote notification if the device is locked?
I have all the appropriate entitlements and "content-available":1 set correctly.
Is there another way that I can wake the app up from a notification and do a few background tasks? I also tried using Notification Service Extension but had the same issue with nothing happening while the device was locked.
I've been looking at this for a few days now and making no progress. I've developed a small test iOS (9.2.1) app that receives push notifications from the Azure Notification Hub. Everything appears to work fine, including the background notification push so long as the app is launched via xcode and is in debug mode.
Every notification I receive via the following callback just writes a file to the documents folder on the device. If I use xcode device explorer, I can see these files appearing
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
makefile(random file name based on timestamp);
completionHandler(UIBackgroundFetchResult.NewData);
}
I have also enabled the following modes in the UIBackgroundModes section of the plist file
fetch
remote-notification
The paypload that I send to the ANS server is:
"aps":{ "sound":"default", "content-available":1 }
Like I have mentioned above, so long as the app is running via xcode, I can press the home button, but it into the background and it will receive the push data fine. However, if I disconnect the USB cable it will stop receiving the background push events.
It's worth noting that the in-built OS notification does appear. Does anyone know what could be the problem here?
EDIT
If I launch the app via xcode, unplug the USB, send the notification - nothing happens. As soon as i reconnect to xcode it comes in and the code is run! Is this something to do with certifications (development / production)
The content-available key indicates iOS should treat this as a silent notification. Silent notifications are silent - they do not show an alert, badge, or play a sound.
A notification payload that contains both the content-available key and user-facing features like a sound or alert may be treated as either. The behavior is undefined - a notification should be silent or not, not both.
Silent notifications are handled by application(didReceiveRemoteNotification:fetchCompletionHandler), not application(_:didReceiveRemoteNotification:). It's possible that when your app does not seem to be getting the notification that iOS is calling this method.
In your case, you may also be getting throttled by iOS. If silent notifications are received too frequently, if you app uses too many resources handling them, etc. iOS will delay delivery of the notification. It will not delay them when launched from Xcode.
Your silent notification should not include a sound. Make that a separate notification, or try playing a sound in the background from inside your app.
Check the rate you are sending silent notifications to your app. At most send 2 an hour.
Verify that your silent notification handling code does not use excessive CPU, memory, or energy. Target using 15mb or less when handling the silent notification. Also make sure the fetchCompletionHandler block is called with 30 seconds of iOS calling application:didReceiveRemoteNotification:fetchCompletionHandler