My app want to update server about users location after every 5 seconds even if app is in background. I implemented Background fetch for it.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil))
application.setMinimumBackgroundFetchInterval(5.0)
return true
}
func application(application: UIApplication, performFetchWithCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
completionHandler(UIBackgroundFetchResult.NewData)
UpdateData()
}
func UpdateData(){
print("UpdateData executes")
// function to update data when ever this method triggers
}
but the problem is
I am unable to enter performFetchWithCompletionHandler method unless I click Debug>simulate background fetch
How can I achieve to invoke performFetchWithCompletionHandler after every 5 seconds.
You have a misunderstanding about what background fetch is. Developers have no power over when a background fetch will be performed exactly. iOS itself decides when to allow an app to perform a background fetch.
The setMinimumBackgroundFetchInterval function only allows you to specify a minimum time interval that has to pass between background fetches to minimize the energy and data usage of your app. However, the interval you set here does not guarantee at all that your app will be able to perform a background fetch this frequently. The key sentence in the documentation regarding this is "Fetch content opportunistically in the background...".
At the moment, the only way to ensure that your app can execute certain functions (including fetching data from a server) in the background is by sending silent push notifications from your own server at regular intervals. However, even then, the system might decide not to wake up your app in response to a silent push notification if your app takes to long to finish execution in response to the push or if your app receives too many notifications.
Related
Is there any way to grab the information that comes from the firebase notification when the app is closed in the background?
I managed to capture it and save it in the following function
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void)
when it is in the background and in execution, but I cannot do it when it is closed
I managed to capture it and save it in the following function
It depends on what you are trying to do.
When the app is sent to the background there are certain life cycle changes that happen and the AppDelegate is notified about this, which gives you a chance to do some small tasks like cleanup, or make a last minute save. But you will only get a limited time to do so (I think its usually around 1 minute, you can ask for more time I believe but that only extends it to about 3 mins).
An example of these life cycle events is applicationWillTerminate, this method is called just before the app terminates and gives you a small window to make a last minute save.
Once your app is suspended you can only do limited things, like background fetch, receive location information, receive push notifications etc.
Background Modes is a good guide on what you can do in the background
When your app is terminated, there is pretty much nothing you can do.
I am trying to implement background fetch in my iOS app (it's a simple http call that downloads some data for later processing).
I enabled background fetch in my project capabilities:
Also in AppDelegate I set minimum fetch interval:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplication.backgroundFetchIntervalMinimum)
return true
}
And implemented fetch handler:
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
do {
try api.downloadInBackground()
} catch {
Debug(self).error(error)
}
completionHandler(.newData)
}
Testing with Debug -> Simulate Background Fetch or custom scheme with enabled background fetch mode work fine and data gets downloaded:
However, when the app is not being debugged background fetch is never invoked. I've read that there's no strict rule when it happens and some time and networking has to be done. However, I've tried leaving device over a weekend (connected to wifi) after I've tried reading some emails browsing, and still nothing happened. What could be wrong?
(At first, I thought it might something to do with a provisioning profile because I did not update it in the apple developer portal, but there's no option to do that, so I suspect that enabling this capability only in the project locally is enough?
I have 4 scenario
When the app is not Launched
Given the app was not Launched or Killed
When the push notification receive
And opened the app without tapping the notification
Then the app should capture the notification.
When the app is running in foreground
Given the app running in foreground
When the push notification receive
Then the app should capture the notification.
When the app is running in background
Given the app is running in background
When the push notification receive
And opened the app without tapping the notification
Then the app should capture the notification.
When the app is not Launched and cleared the notification
Given the app is not Launched or Killed
When the push notification receive
And user cleared the notification
And opened the app
Then the app should capture the notification.
The first 3 scenario works fine with the following code
The last scenario is not worked When the app is not Launched and cleared the notification
AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().getDeliveredNotifications(completionHandler: { requests in
for request in requests {
self.setNotification(userInfo: request.request.content.userInfo as NSDictionary)
}
})
}
return true
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
setNotification(userInfo: userInfo as NSDictionary)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
setNotification(userInfo: userInfo as NSDictionary)
}
According to your query
When the app is not Launched and cleared the notification
Given the app is not Launched or Killed When the post notification
receive And user cleared the notification And opened the app Then the
app should capture the notification.
This is not possible for a Normal Push notification unless the user interacts with that notification. You may want to try Silent notifications, these are not shown in the UI but the control reaches the app and you can use the data/payload from there in your code.
When user clears the notification from bar, there is no way to fetch that information.
You could also try to add the same information that is being sent in the push within an API and call it once the user opens the app.
This link deals with all the detail involved. According to your implementation, you can try a combination of both.
I've read a lot of answers here and I can't find answers of this questions
How to stop badge, alert and sound from notifications when the application is not running ?
How to stop badge, alert and sound from notifications when the application is in Background?
in this function:
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
I've put completionHandler([]) without [.badge, .alert, .sound] and I still receive notifications in background when the app is runned.
Also I have function in my code that sends notification when somebody is typing to you and you see that he is typing to you when you are in-app, but when the application is not runned you are receiving notification with badge alert sound? How to prevent that?
PHP Code:
$body['aps'] = array(
'content-available' => 0,
'typingNewMessage' => 'true',
'senderId' => $your_id
);
Two things first: Are you using websocket/socket.io for the chat in your app? And as for notifications, have you set up remote notifications in background modes?
Background modes.
Read up on the docs for push notifications, it sounds like you're adding steps here, or missing some. Basically as kathayatnk mentioned, his method should give you what you want. So if you haven't activated remote background notifications:
To configure your app to process silent notifications in the
background
In the Project Navigator, select your project.
In the editor, select your iOS app target.
Select the Capabilities tab.
Enable the Background Modes capability.
Enable the Remote notifications background mode.
If this is done, you should receieve them in the background..
Also, you are using the wrong method for recieving background notifications in the background.. As stated in the same link above:
In iOS, the system delivers silent notifications by calling the
application:didReceiveRemoteNotification:fetchCompletionHandler:
method of your app delegate. Use that method to initiate any download
operations needed to fetch new data.
how i usually use it :
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
guard let aps = userInfo["aps"] as? [String:Any] else {
//handle something here..
return
}
//handle the content here...
}
You can also perform background tasks from inactive states here by playing with the return value of completionHandler. I suggest you read up on it too.
For your chat issue...
Clarify how you're performing this...
If you're using a websocket/socket.io architecture:
I would strongly recommend not using notifications to notify a user of anything with APNS when using a websocket. Websockets are very efficient and much quicker. Handling both can greatly complicate things. Stick to the socket approach, and use a method server side that checks if a user is still within the app. Something like a ping-pong method like here. Have that method switch to APNS delivery when the socket client ping method shows that the user has left the app or has closed it. This means, if the user is still in the app, but not in the conversation, stay with the ping approach but program the UI response differently (take FB Messenger or Snapchat's notification tabs for example).
If you are not using websockets/socket.io:
...Switch to websockets technologies or packages (depending on your server platform type) or socket.io or use firebase realtime chat services.
Let me know your setup like i asked earlier, but if youre doing all of this already and still getting the issues, then post your code.
Personnaly, i've used RawWenderlicht for APNS guides for over a year, good stuff if you ask me.
To silent push notification the payload should contain content-available key as:
{
"aps": {
"content-available": 1
}
}
Also, you need to enable Remote Notifications in Background Modes under Capabilities setting of your Xcode project.
Now your app will wake up in the background when it receives one of these push notifications.
didReceiveRemoteNotification will be called in AppDelegate whenever the push notification is received.
func application(
_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable : Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void)
{
let aps = userInfo["aps"] as! [String: AnyObject]
if aps["content-available"] as? Int == 1
{
//Your code
}
}
For more on how to handle push notifications in foreground/background refer to: https://www.raywenderlich.com/156966/push-notifications-tutorial-getting-started
you can add silent push notifications (set content-available key appropriately) when sending pushes, like below.
//when you want the badge and sound
aps {
content-available: 1
}
//When you want silent notifications
aps {
content-available: 0
}
This will call the appropriate delegate method but wont display badge and sound
I want to make a request every 15 minutes. Then I want to make a push notification to the user.
I use this code.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
// push
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: [UIUserNotificationType.Sound, UIUserNotificationType.Alert, UIUserNotificationType.Badge],categories:nil))
// background fetch
let settings = UIUserNotificationSettings(forTypes: [UIUserNotificationType.Sound, UIUserNotificationType.Alert, UIUserNotificationType.Badge], categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.sharedApplication().setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalMinimum)
return true
}
func application(application: UIApplication, performFetchWithCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
print("Complete");
completionHandler(UIBackgroundFetchResult.NewData)
getData();
}
func getData() -> Void {
let p = PushService()
p.Push("Changed")
}
It works fine but only one time.
And when I close this app via task manager there is no push.
So how I can send push notifications every 15 minutes even when the user closed my app. (like WhatsApp or another messenger)
I use a local push.
As mentioned by myself and others, I wouldn't recommend going about it in the app. Instead, you should use Parse.com Cloud Code for managing and setting Push Notifications:
https://parse.com/apps/quickstart#cloud_code/window
This links shows how to set up Cloud Code using your terminal. You can automate Push Notifications using Parse as well. Parse has relatively good documentation which can help you get started.
Here's the push notification homepage on Parse: https://parse.com/products/push
Here are the parse docs for Push Notifications which will take you through registering your app for Push Notifications as well: https://parse.com/docs/ios/guide#push-notifications
Go down to "Sending Pushes" in the docs. This is where Parse will help you set up Push notifications with Cloud Code on Parse.
Once you set it up, go to your project, then "Core" and click jobs, and you'll get this screen (note, this is my project and I'm deleting posts. You can name this whatever you want):
Use this link for your push notification javascript code as a tutorial: How to send Push Notifications with Parse.com Cloudcode it's a good example. On Parse, as the image I posted above shows, you can get specific on when you want the push notification to push to the user.
Hope that helps