I have a voip app, but it won't wake up from standby mode when a call comes in. The docs say the following:
There are several requirements for implementing a VoIP app:
1. Enable the Voice over IP background mode for your app. (Because VoIP
apps involve audio content, it is recommended that you also enable
the Audio and AirPlay background mode.) You enable background modes
in the Capabilities tab of your Xcode project.
// I did this using the "capabilities" tab in the project's settings.
// I have "audio and airplay", "voice over ip",
// "background fetch" and "remote notifications" checked.
2. Configure one of the app’s sockets for VoIP usage.
// I have 2 sockets, one for sending stuff to the server that closes after sending.
// One socket that stays alive all the time, which is used to
// receive stuff from the server.
// The one that stays alive is configured as voip*.
3. Before moving to the background, call the
setKeepAliveTimeout:handler: method to install a handler to be
executed periodically. Your app can use this handler to maintain its
service connection.
// I did this and in the handler I send a login message to the server,
// On the server side it's detected that the account is already logged in so
// it refreshes the connection instead.
4. Configure your audio session to handle transitions to and from active use.
// I did not do this yet, I might in the future.
5. To ensure a better user experience on iPhone, use the Core Telephony
framework to adjust your behavior in relation to cell-based phone
calls; see Core Telephony Framework Reference.
// I did not do this and probably never will (company's decision, not mine).
6. To ensure good performance for your VoIP app, use the System
Configuration framework to detect network changes and allow your app
to sleep as much as possible.
// I don't do this yet, but will implement it once all the basics run fine.
When a call comes in I create a local notification to let the user know about the call. When the app is minimized this works fine, but when the device is in standby (sleep) there is no notification. When I wake the device from standby, the notification pops up after a few seconds (so it's not already there, it really appears after waking up the device).
I created more voip apps in the past, and I can't remember ever having trouble with this. I'm running ios 8 now, perhaps I have to do some more to make it work while in standby? Are there more requirements for voip now? Or am I missing something stupid?
Note: I know about push notifications. They are an option (in fact, I already tested and they make it work), but I'd rather not be dependent on the apns.
I just spent two full days troubleshooting a similar problem. An iPhone 6+ worked properly but neither of two iPhone 6's did. To make a long story short, SIP packets were not being transmitted reliably. I pinged the VOIP servers offered me and found that I was using one with a latency of 30 milliseconds but one with 15 milliseconds' latency was available, so I tried switching servers. That did the trick.
Be aware that if the user closes the App manually (double click home button, swipe up) your application will not be able to run in the background until the user manually opens it up.
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.
Check it here.
Related
We are building an iOS iPhone app that needs to check-in with a server on a 12 hour basis. This is needed to let the server know that the app is still using it's service on the server. To our understanding this is possible when the app is in background state (not showing on the foreground) via backgound fetch or remote notifications.
But this is not possbile when the app is not running or terminated, when the app is in these states then there is no way to initiate communication with a server. Is this statement corret? Is it possible initiate the communication after a device bootup, is it then possible to send a small keep alive message to te sever?
The background fetch and responding to remote notifcations is not possible in the not running and termenating states(?), so we cannot use these mecahnisms for this purpose. If that is the case are there any other solutions that we can try? Or is it just not possible?
We looked at many sources on the internet but some say that it is possible and others say it is not.
You might want to take a look at the Silent Push Notifications. Here is the thing, if the app is in background mode or suspended state, you will be fine. If the app was killed by the user, you have a problem.
You can always send a silent push notification, and wait for a service call made from the device to your service. If there is a response, it means the app was in background or suspended, and then you can go ahead and do whatever you need to do. If no request is made, it means that app was killed. Then you might want a sent a non silent push letting the user of that device know that he needs to launch the app or something like that. I don't know how you are going to work around it, but that could be a possibility.
I would tell you to take a look at NSURLSession and Background NSURLSessionConfiguration as well, but you will run into the same issue. If the user manually terminates the app, you need to find a work around to set up that connection to the server, and that will imply the user to somehow launch your application.
Now for those who don't know, can go to https://web.whatsapp.com/ and sync your Whatsapp chats by exchanging a QR code and chat via the web extension of the app.
I am not interested in how they have an initial handshake( might be communicating with whatsapp servers) nor how they sync data so fast for chatting (might be using Open sockets directly from device to client).
I am curious as to how the app works in Background on iOS . AFAIK running a background Intent Service is pretty simple. But not for iOS. iOS allows only up to 30 seconds after the app is shut down normally.
1) I tried crashing the App(swipe up) (Still the web version was running normally)
2) I disabled Background App refresh the web version didn't stop.
3) Even disable Notifications still the web version worked normally.
4) As well they do not have a Blue bar the likes when Google Maps is giving you directions that indicates the app is running in BG
5) Are they using Dummy Geo Fencing to keep them alive? (but that d require BG App Refresh too)
Is it some new feature on iOS 8 that was introduced and I am not aware of
Just as a side note, Apple introduced the Notification Service extension point in iOS 10, which can be used to achieve this. The following applies only to iOS 9.x or earlier.
No app in iOS can be long alive in background with a keep-alive socket, or
guaranteed to wake by remote notifications except those using VoIP background mode (OT: and IIRC Bluetooth background modes).
An app has only ~5 seconds of runtime on applicationDidEnterBackground: after being put in background, unless it is registered for any background modes or tasks. The app would be terminated if it runs out of time in this delegate method.
The background task model mentioned by #xoail has a app-specific, system-imposed time limit (up to 30 seconds...?) and cannot be extended. It is for an app to complete its current work, e.g. uploading a media, before being suspended. Background Transfer Service, since iOS 7.0, is an alternative for long running file transfer.
Silent Remote Notificaiton is observed to be triggered consistently only on charger and Wi-Fi, but always throttled by iOS otherwise. So it is sort of indeterministic - let alone the fact that this can be switched off by flipping the app's Background App Refresh switch.
VoIP background mode (in iOS 8 and later) guarantees to call the app's handler when a VoIP notification is received from APNs. But App Review Guidelines states clearly that background modes should only be used for their intended purpose.
So either Apple waives WhatsApp the use of VoIP background mode for purpose other than WhatsApp Call, or WhatsApp happens to get away from the "use your phone to sync" architecture and does something new for the iPhones.
As per the docs the app can remain in the background performing finite updates to the App. You can continue extending the background process one after the other. Look into Perform finite-length tasks. I think killing the app from background still executes registered actions by the system.
Whatsapp does some clever web session token + background app token generation to keep session valid.
As mentioned in #32112433 by Steven Darbey this is most likely implemented using the new iOS 8 PushKit Service which includes a VoIP service notification type, allowing applications to resume from background. A misuse of the API for non-VoIP purposes, but Apple apparently putting a blind eye on it.
https://developer.apple.com/library/prerelease/ios/documentation/Performance/Conceptual/EnergyGuide-iOS/OptimizeVoIP.html
I have always coded for Android, and now I'm looking to expand my knowledge to iOS development; so I'm really new at this, please be patient.
I understand that only a small group of apps are allowed to run indefinitely in the background. Those are VoIP, Music players and location tracking apps.
I want to write a chat app using the XMPP framework. Everything is fine until the user puts the app in the background, in which case, the app will stay connected for about ten minutes to then be killed by the system and therefore the user won't be able to receive new messages.
I am aware of hacks to keep the app alive. Hacks such as defining it as a music playing app in the info.plist file and then just play some empty sound indefinitely. But I'm also aware that Apple will reject the app when it's time to publish to the App Store.
So, normally, how do other apps do it? How can other chat apps stay alive in the background to receive new messages from the servers? Apps like Google Hangouts, IM+ and such?
Ideally, they aren't really running in the background, but use push notifications, as others have mentioned.
But some chat clients seem to do something else: I've verified (by sniffing the traffic of an idle iOS device) that at least Google Hangouts, Facebook and Skype all keep a persistent socket opened in the background, and regularly send traffic to keep it alive.
I'm suspecting that they are using the VoIP exceptions to Apple's otherwise strict background execution policies. iOS allows "VoIP apps" to run in the background and keep one socket open to be notified about incoming calls and messages.
Maybe they are also using the new "background fetch" feature of iOS 7, but as far as I know, that doesn't allow persistent socket connections.
The iOS operating system allows for the existence of something called a PUSH NOTIFICATION
There exists hundreds of tutorials online which teach you how to implement the notification code and how to respond accordingly when you receive such a message!
http://www.raywenderlich.com/32960/apple-push-notification-services-in-ios-6-tutorial-part-1
Check this link out for an in-depth tutorial on push notifications!
http://maniacdev.com/2011/05/tutorial-ios-push-notification-services-for-beginners
I think most of these apps use push notifications and just load the last messages from the server as soon as the app is being opened.
While there are some hacks, and your app can ask for more time when it goes in background (up to a point, and with no guarantees), this is a perfect application for push notifications.
The server tells the phone there's a message, and iOS wakes your app up to process it.
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Introduction.html
As of iOS 7 there is a new background-execution mode - 'fetch' for apps that need to periodically fetch new data. It sounds like your case would meet that definition.
You can find the information in the iOS App Programming Guide -
Fetching Small Amounts of Content Regularly
In iOS 7 and later, an app that retrieves content regularly from the
network can ask the system for background execution time to check for
new content. You enable support for background fetches from the
Background modes section of the Capabilities tab in your Xcode
project. (You can also enable this support by including the
UIBackgroundModes key with the fetch value in your app’s Info.plist
file.) At appropriate times, the system gives background execution
time to the apps that support this background mode, launching the app
directly into the background if needed. The app object calls the
application:performFetchWithCompletionHandler: method of its app
delegate to let you know when execution time is available.
You can also use push notifications, but that requires some server infrastructure
An app running in the background has limited capability. Read App States and Multitasking thoroughly to decide how best to design your app. Chat is not listed as one of the specific exceptions that can operate with a more relaxed policy. You will never be able to "keep [your] app live in background forever." You might be able to leverage an iOS 7 feature also described in this guide, Fetching Small Amounts of Content Regularly.
iOS App Programming Guide: App States and Multitasking
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOS ProgrammingGuide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html
1) My plist configuration to provide backgroundmode:
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
</array>
2) In didFinishLaunchingWithOptions I have:
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:1.0];
3) I declared the protocol UIApplicationDelegate in the delegate.
4) I implemented the following method, but it never gets fired. (It only works if I simulate the fetch with "XCode->Debug->Simulate Background Fetch".)
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
Why? Is this a DP5 beta error? Should I radar this?
Running your app in the iOS Simulator, in Xcode Debug mode, you can force a background fetch from the Xcode menu:
Debug > Simulate Background Fetch
May work for a tethered device, I haven't tried it recently.
I'm afraid this is hard to debug on a device because you're not guaranteed it is called in the amount of time you specify.
setMinimumBackgroundFetchInterval means that it is not called in an interval which is smaller than the value you specified. But there's no setMaximumBackgroundFetchInterval.
So if iOS decides to call your app just once a day or even just once a week than it won't be called more often regardless your minimumBackgroundFetchInterval. AFAIK iOS decides when to call performFetchWithCompletionHandler measured by the pattern when and how often the users start the app.
There are many considerations:
Make sure the background fetch capability was set in the plist.
Make sure the background fetch capability hasn't been disabled for this particular app, or in general, in the device's Settings app.
Make sure to set the minimum fetch interval.
Make sure you gracefully leave the app (e.g. just hit the home button and fire up another app and/or just lock the device). But if you kill the app (by “force quitting” by double tapping on the home button and swiping up or, for those devices without home button, swiping up from the bottom to pull up the task manager and then swiping up on the app in question) that will prevent the OS from offering your app a chance to fire off subsequent background fetch requests (at least until the user runs the app again).
Make sure you are testing this on physical device and not running the app via the Xcode debugger. Being attached to the debugger changes the behavior of background operations.
Make sure the app is actually doing some network requests. If you have app that performs no network requests at all, it won't participate in background fetch. If you do, for example, a little test app with "background fetch" and don't issue any network requests, you won't participate in background fetch.
Likewise, if the OS starts up your app in background mode so it can perform a background fetch, if you don't actually perform a network request, the OS may stop offering your app the ability to perform background fetches in the future.
Make sure to call the completion handler, and do so within the allotted time, or your app may not participate in background fetch in the future.
The timing of when the OS performs background fetch is dictated by poorly documented rules that may change in the future. But the relevant factors include:
Whether the device is connected to power and/or is sufficiently charged;
Whether connected to WiFi or not;
How often the user actually fires up the app;
Whether the device is doing other network related tasks (e.g. whether background fetch can be coalesced with other network operations);
How frequently past background fetch requests resulted in there being data available.
In my experience, after the app is run the first time, if connected to wifi and power, if you wake the device about 5 minutes later, the app will perform background fetch. This isn't a hard and fast rule, but just what we've experienced in the past.
But many new developers post on Stack Overflow with questions like “how can I have app request data ever x minutes (or hours)”, “how can I request data every day at 2 am time”, etc. The short answer is that you can't. The OS decides the timing of background at its own discretion. You cannot control this (other than the minimum request interval; but you cannot control the maximum interval, as the OS controls that).
This may seem obvious to many, but make sure you've got a reliable way of knowing whether background fetch process is running correctly or not. User Notifications framework can be used to present some alert so you know if the background request resulted in something. Alternatively, os_log or Logger “Unified Logging” (see WWDC 2016 Unified Logging and Activity Tracing or 2020’s Explore logging in Swift) can be used to post messages on device that can be monitored on macOS Console app. But more than once, I've seen users do something like waiting for message to show up in Xcode or waiting for UIAlertController. You need some mechanism that works when not connected to Xcode and when the app never enters foreground.
Using your device you can fire application:performFetchWithCompletionHandler with the following steps:
Put your app in the Background state
Lock your device and wait 5 minutes.
Unlock your device, this will fire the method
(It only works if I simulate the fetch with "Xcode->Debug->Simulate
Background Fetch".)
It's because you're in Debug mode. Please try launch app without Xcode.
Another thing to check is your plist file. Make sure the UIApplicationExitsOnSuspend key is not present.
Many people here on Stack Overflow have recommended using that setting as a way to force your app to start fresh each time it's launched. That does work, but the side effect is that it prevents the new iOS 7 background fetch feature from being triggered.
If application: performFetchWithCompletionHandler: never gets fired (unless you simulate it using Xcode), check also if "Background App Refresh" preference is "On" for your app. (Settings app -> General -> Background App Refresh)
Also, background fetch is disabled if the iPhone is in Low Power Mode.
Apple provides an algorithm which defines how often the background fetch should trigger, based on your own usage of the app. If you use it a lot, then it will fetch as often as possible, but if you use like at 4pm every day, the background fetch should trigger just before, so your data is updated when you launch it.
I'm spec-ing an iOS app (which will be built outside of our company) which will upload a user's data entry to a server. If the device is not connected to the Internet, we'd like to save data on the device and upload it when the network is re-connected. (The app will primarily run on iPod Touch devices that will be disconnected most of the time).
If the user unlocks the device and re-opens our app after the network is reconnected, then uploading to the server should be easy because the app is running.
But what if the app is not running, where "not running" can mean one or more of:
device was power cycled
user has locked the device and it's sitting in his pocket
app crashed
user exited the app
user started using other apps so our app isn't running in the foreground anymore
are there other cases?
In the cases above, is there a way (ideally a battery-efficient way) to ensure that local data is uploaded soon after Internet connectivity is restored? Is the answer different depending on which of the cases above caused the app not to be running?
And is there a minimum iOS version the device will need in order to enable some (or all) of the above not-running cases to still upload when the app is not running?
My apologies if these are obvious newbie questions-- I'm not an iOS expert.
There is an interesting technique that is used by among others Instapaper and News.me(the pioneers of this technique) where you use region monitoring to initiate background downloads or uploads. Marco (Instapaper) blogged and talked (in episode 80 of the Build and Analyze podcast) about his communication with Apple so it should be a allowed in the App Store.
In brief the technique is that you set up certain regions (geofences) like "home" or "work" and respond to the locationManager:didEnterRegion: (and similar) callback(s). Your app will wake up from the background once you enter the pre-specified region and you can check to see if there is any data to upload.
This technique won't guarantee that the data is uploaded when the network reconnects but it will allow your app to automatically upload the information when the iPod Touch users gets home to their WiFi network.
That should most likely be at least once a day which may or may not be frequent enough for you. You could add a timestamp to when the initial upload was attempted and send that along the upload once it succeeds to get the correct order of events (data entries) on your server.
There is no way to ensure this. If your application is "not running" (by the definition described in your question), it will not be capable of responding to a change in the device's network status. It should be setup to resume upload operations the next time the application runs again.
EDIT:
Some of the cases you've described may indeed provide different opportunities for your application. Specifically, if the user "exits" the app by pressing the home button or launches another app in the foreground, your application may continue to run the in the background and could potentially respond to a change in network reachability.
The nature of what may be done in the background and for how-long is well documented, and supported by any version of iOS that supports multi-tasking. I recommend you review the documentation pertaining to App States and Background Services.
device was power cycled --> really NO WAY of resuming, unless you open the App!!!
user has locked the device and it's sitting in his pocket --> apps applicationStatus is UIApplicationStateInactive but it is running in the background. You still are able to react to notifications and i.e. accelerometer events. Try the Reachability Class and Log the changes!
app crashed --> NO WAY, unless opening the App
user exited the app --> App is sitting in the background. There you have a maximum of 10 Minutes Restriction of fully using your App (like the App "Pastebot" does)
user started using other apps so our app isn't running in the
foreground anymore --> Same as user exited the app
On multitasking Apple says the following:
Real multitasking only for certain kinds of usage, as there is Audio Background playing, VOIP (like Skype), navigation applications
All the other apps can request a specific amount of time after the app is closed/in the background, to finish certain tasks (as sending an email, sms or uploading/downloading important data)
Important Quote from dev docs:
Your app delegate’s applicationDidEnterBackground: method has approximately 5 seconds to finish any tasks and return. In practice, this method should return as quickly as possible. If the method does not return before time runs out, your app is killed and purged from memory. If you still need more time to perform tasks, call the beginBackgroundTaskWithExpirationHandler: method to request background execution time and then start any long-running tasks in a secondary thread. Regardless of whether you start any background tasks, the applicationDidEnterBackground: method must still exit within 5 seconds.
If you're building a restful API then I would recommend using RestKit, it has a request queue that checks the network status on the device and starts uploading once network access has been assured. You can read more about this here: http://mobile.tutsplus.com/tutorials/iphone/advanced-restkit-development_iphone-sdk/. Read the sections about Request Queue and background download/upload. It should be noted that RestKit is a big library which has it's advantages and disadvantages. I'm not completely sure how this que works with the app lifecycle, if it saves the request que even if the app is terminated. You would have to investigate that. RestKit does support background uploading/downloading, but as already noted, I think it's impossible to do any uploading if the app is terminated and not in background state.
I wouldn't recommend using RestKit if the API isn't Rest though.
You can download and experiment with RestKit here: https://github.com/RestKit/RestKit.