Silent notifications in iOS Simulator - ios

I've been studying background execution in iOS. One of the methods is silent notifications.
Silent notifications (aka background push) can be used to wake the app from suspended state and update content. From Xcode 11.4, it is possible to simulate regular user notifications, as described here. Then, from Xcode 14 onwards, those with Apple silicon Mac laptops will be able to send notifications to simulator from APNS itself... wonderful.
But this post is about silent notifications.
.apns file used is,
{
"Simulator Target Bundle": "com.example.IOSBackgroundExec",
"aps": {
"content-available": 1
}
}
In project settings, 'remote notification' is enabled under 'Signing and Capabilities' tab and Push notification is added. User permission is not required for silent notifications.
The following delegate method is supposed to be invoked when app is woken up.
// Handling silent remote notification
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
NSLog(AppDelegate.TAG + "application(_:didReceiveRemoteNotification:fetchCompletionHandler:)")
// Some work
completionHandler(.newData)
}
Question(s):
When I drag and drop the .apns file, the delegate method is not invoked. I'm aware that Background Fetch and Background Processing cannot be tested in simulator because, their scheduling is dependent on system conditions, which is beyond the simulator. So silent notifications are also not possible to test in simulator?
According to documentation, by user force-quit, user swiping app from app switcher is referred? Even after swiping WhatsApp, you still get notified of incoming messages as long as there's an internet connection, right?
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.
Environment: Xcode 14.2, iOS Simulator 16.x

Related

Even if I get a remote notification, not wake up my app that isn't running when other apps are in the foreground. Swift for iOS

MyApp: Terminate or Suspended ( Not exist in App Swithcer)
OtherApp: Foreground
this situation.
Notification is received. However, this didReceiveRemoteNotification method is not invoked. (The app didn't wake up)
But, method in UNNotificationServiceExtension is called.
In other words, the appdelegate of my app is not executed.
If there are no other apps in Foreground, it runs well. (didReceiveRemoteNotification method)
Why is it like this?
It's difficult to follow your question. Are you saying that your app has been force-quit? In that case you will not receive didReceiveRemoteNotification. This is documented behavior:
However, the system does not automatically launch your app if the user has force-quit it. In that situation, the user must relaunch your app or restart the device before the system attempts to launch your app automatically again.

FCM Notification for flutter app does not show in iOS system tray

I have a flutter app where I use Firebase Cloud Messaging for notifications.
I am sending test notifications via firebase console.
Notifications function as expected on android.
On ios the notifications arrive as expected when the app is in the foreground. When the app is minimized in the background, notifications do not show in the system tray. Also no badge shows either even though a badge is set in firebase notification when I send by console.
Essentially there is no sign a notification has arrived at all until the app is opened again.
I have followed the instructions found on this page and confirmed I followed the ios integration steps to a T.
I am testing on a simulator.
As per the documentation found on Firebase website regarding apple integration:
For iOS; you must have a physical iOS device to receive messages.
Firebase Cloud Messaging integrates with the Apple Push Notification service (APNs), however APNs only works with real devices.
I have had some issues when I didn't ask for the permissions of the notifications in my App. So you should check that you have asked for the permissions of the notifications when executing the App and that it has been acepted because if you don't accept the permissions you could have problems receiving the notifications.
You can add this code in the appDelegate in the iOS project to ask for the permissions when the app executes:
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
// Enable or disable features based on the authorization.
}
Or you can also use a package in the pub.dev that can check and request the permissions in your App.
You can also check on the phone if the notifications are enabled for your App.
Follow these steps:
Generate the certificates required by Apple for receiving push
notifications following this guide in the Firebase docs. You can
skip the section titled "Create the Provisioning Profile".
Using the Firebase Console add an iOS app to your project: Follow
the assistant, download the generated GoogleService-Info.plist file,
open ios/Runner.xcworkspace with Xcode, and within Xcode place the
file inside ios/Runner. Don't follow the steps named "Add Firebase
SDK" and "Add initialization code" in the Firebase assistant.
In Xcode, select Runner in the Project Navigator. In the
Capabilities Tab turn on Push Notifications and Background Modes,
and enable Background fetch and Remote notifications under
Background Modes.
Follow the steps in the "Upload your APNs certificate" section of
the Firebase docs.
5.If you need to disable the method swizzling done by the FCM iOS SDK
(e.g. so that you can use this plugin with other notification
plugins) then add the following to your application's Info.plist
file.
<key>FirebaseAppDelegateProxyEnabled</key>
<false/>
Secondly, Apple doesn't support FCM push notifications in the simulator, you have to set up a physical iOS device to run your app.
I had this problem recently... tried many things like this guys wrote, but the ONLY thing worked for me was change the firebase_message version to firebase_messaging: ^8.0.0-dev.14. You should try it.. there are some things that has changes from the last stable version, but the transition is not hard. You could check the tutorial here. https://firebase.flutter.dev/docs/messaging/usage/.
I saw now that they released a newest version (9.0.0).. but for me the 8.0.0 worked
*Only works in a real device
import UIKit
import Flutter
import UserNotifications
//import FacebookCore
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
override func application(_ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
GeneratedPluginRegistrant.register(with: self)
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self
} else {
// Fallback on earlier versions
}
//SDKApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
// This method will be called when app received push notifications in foreground
#available(iOS 10.0, *)
override func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
{
completionHandler([.alert, .badge, .sound])
}
}
Make this replacement in your info.plist file .
Replace <false/> by <string>0</string>
Before :
Now :
Info : If you don't have this code in your info.plist and you don't
receive the notification as well, make sure you add it.
Don't forget , here is the new code :
<key>FirebaseAppDelegateProxyEnabled</key>
<string>0</string>
Info: IOS does not support FCM push notifications in the simulator,
even if you use the simulator in XCode . The best solution will be
to use a physical device.

CloudKit subscription Error: apsd[81] <Warning>: Silent Push: Deny app not available

I'm trying to get silent push from CloudKit. But it only works when my app in foreground (OR when its launched from Xcode, in that case notifications are delivered in background too).
I've enabled all corresponding Background Modes.
Registered for remoteNotifications and specified background fetchInterval in didFinishLaunchingWithOptions
UIApplication.sharedApplication().setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalMinimum)
application.registerForRemoteNotifications()
I'm getting didRegisterForRemoteNotificationsWithDeviceToken no problems here.
I've implemented method for handling remoteNotifications:
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
NSLog(__FUNCTION__)
let identifier : UIBackgroundTaskIdentifier = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler(){
}
CoreDataStack.sharedInstance.ensemblesSynchronizeWithCompletion(){
UIApplication.sharedApplication().endBackgroundTask(identifier)
completionHandler(UIBackgroundFetchResult.NewData)
}
}
I've tried switching CloudKit container to Production and testing with TestFlight.
There results are always the same : In the foreground I'm getting CKNotifications,but for background in console I see this:
Error: apsd[81] : Silent Push: Deny app not available
Additionally I've tried:
Changing container completely - no luck.
I've also edited my AppID accordingly, but I don't think its necessary for CloudKit notifications (or is it?) :
in Settings everything is enabled :
Console output when started from device (not from Xcode)
App running foreground :
App running background :
When started from Xcode I get notification in background & foreground.
If you force quit your application then iOS stops delivering push notifications to your app in the background. When you are running your app from Xcode and want to quit make sure you "Stop" the process from Xcode instead of swiping up from the app switcher on the device.
You may just have to restart your phone to get the silent push notifications to start working again.

iOS 8: App processing silent notification upon launch

I've read about the woes of silent push notifications in iOS, so this will likely be fruitless ... but I figure I'll ask if only to just maybe have an Apple rep see it.
I'm sending a simple APNS message to an iOS 8.1 app:
aps: {
content-available: 1,
priority: 5
}
The app is in the background (read: I have not force-closed it).
Sometimes my app delegate's didReceiveRemoteNotification with fetchCompletionHandler fires, sometimes it doesn't. I can tell because I am monitoring my server and can see if/when a GET request arrives.
I'm currently exploring if there's a correlation with passing weather systems and/or bird migration patterns.
But what's really frustrating is that when I build/launch my app via xCode, here's the console output:
- appDelegate: received notification
- appDelegate: fetching stories
- appDelegate: application launched
- appDelegate: remote notifications approved
**** modal view controller: viewDidLoad
Notice the notification is "received" just as xCode is firing up the app, but before the application launches (?).
It's as though the device is receiving silent notifications but is sitting on them until xCode starts the app. Additionally, I've noticed that when the device is running the app & connected to xCode, silent push notifications arrive very reliably ... which would also suggest some sort of irregularity involving xCode.
Am I doing something wrong? Is anyone else seeing this phenomenon? Or is this just a bug with iOS / APNS?
I'm happy to try out any code snippets or suggestions anyone has! Thank you.

Will iOS launch my app into the background if it was force-quit by the user?

I am triggering a background fetch by using the content-available flag on a push notification. I have the fetch and remote-notification UIBackgroundModes enabled.
Here is the implementation I am using in my AppDelegate.m:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
NSLog(#"Remote Notification Recieved");
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = #"Looks like i got a notification - fetch thingy";
[application presentLocalNotificationNow:notification];
completionHandler(UIBackgroundFetchResultNewData);
}
When the app is running in the background, it works fine. (The notification is received and the app triggered the "looks like i got a notification" local notification, as the code above should do).
However, when the app is not running and a push notification is received with the content-available flag, the app is not launched and the didRecieveRemoteNotification delegate method is never called.
The WWDC Video Whats New With Multitasking (#204 from WWDC 2013) shows this:
It says that the application is "launched into background" when a push notification is received with the content-available flag.
Why is my app not launching into the background?
So the real question is:
Will iOS perform background tasks after the user has force-quit the app?
UPDATE2:
You can achieve this using the new PushKit framework, introduced in iOS 8. Though PushKit is used for VoIP. So your usage should be for VoIP related otherwise there is risk of app rejection. (See this answer).
UDPDATE1:
The documentation has been clarified for iOS8. The documentation can be read here. Here is a relevant excerpt:
Use this method to process incoming remote notifications for your app.
Unlike the application:didReceiveRemoteNotification: method, which is
called only when your app is running in the foreground, the system
calls this method when your app is running in the foreground or
background. 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 push
notification arrives. However, the system does not automatically
launch your app if the user has force-quit it. In that situation, the
user must relaunch your app or restart the device before the system
attempts to launch your app automatically again.
Although this was not made clear by the WWDC video, a quick search on the developer forums turned this up:
https://devforums.apple.com/message/873265#873265 (login required)
Also keep in mind that if you kill your app from the app switcher
(i.e. swiping up to kill the app) then the OS will never relaunch the
app regardless of push notification or background fetch. In this case
the user has to manually relaunch the app once and then from that
point forward the background activities will be invoked. -pmarcos
That post was by an Apple employee so I think i can trust that this information is correct.
So it looks like when the app is killed from the app switcher (by swiping up), the app will never be launched, even for scheduled background fetches.
You can change your target's launch settings in "Manage Scheme" to Wait for <app>.app to be launched manually, which allows you debug by setting a breakpoint in application: didReceiveRemoteNotification: fetchCompletionHandler: and sending the push notification to trigger the background launch.
I'm not sure it'll solve the issue, but it may assist you with debugging for now.
The answer is YES, but shouldn't use 'Background Fetch' or 'Remote notification'. PushKit is the answer you desire.
In summary, PushKit, the new framework in ios 8, is the new push notification mechanism which can silently launch your app into the background with no visual alert prompt even your app was killed by swiping out from app switcher, amazingly you even cannot see it from app switcher.
PushKit reference from Apple:
The PushKit framework provides the classes for your iOS apps to
receive pushes from remote servers. Pushes can be of one of two types:
standard and VoIP. Standard pushes can deliver notifications just as
in previous versions of iOS. VoIP pushes provide additional
functionality on top of the standard push that is needed to VoIP apps
to perform on-demand processing of the push before displaying a
notification to the user.
To deploy this new feature, please refer to this tutorial: https://zeropush.com/guide/guide-to-pushkit-and-voip - I've tested it on my device and it works as expected.
Actually if you need to test background fetch you need to enable one option in scheme:
Another way how you can test it:
Here is full information about this new feature:
http://www.objc.io/issue-5/multitasking.html
I've been trying different variants of this for days, and I thought for a day I had it re-launching the app in the background, even when the user swiped to kill, but no I can't replicate that behavior.
It's unfortunate that the behavior is quite different than before. On iOS 6, if you killed the app from the jiggling icons, it would still get re-awoken on SLC triggers. Now, if you kill by swiping, that doesn't happen.
It's a different behavior, and the user, who would continue to get useful information from our app if they had killed it on iOS 6, now will not.
We need to nudge our users to re-open the app now if they have swiped to kill it and are still expecting some of the notification behavior that we used to give them. I'm worried this won't be obvious to users when they swipe an app away. They may, after all, be basically cleaning up or wanting to rearrange the apps that are shown minimized.
This might help you
In most cases, the system does not relaunch apps after they are force
quit by the user. One exception is location apps, which in iOS 8 and
later are relaunched after being force quit by the user. In other
cases, though, the user must launch the app explicitly or reboot the
device before the app can be launched automatically into the
background by the system. When password protection is enabled on the
device, the system does not launch an app in the background before the
user first unlocks the device.
Source:
https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
For iOS13
For background pushes in iOS13, you must set below parameters:
apns-priority = 5
apns-push-type = background
//Required for WatchOS
//Highly recommended for Other platforms
The video link: https://developer.apple.com/videos/play/wwdc2019/707/

Resources