I'd like my app to be able to - say, every 12 hours - even if the app isn't curently running or is in the background, send an HTTP request to a server, get a small file with a version number and if the version on the server is higher than the version on the client, then download some more files to disk so that next time the app starts it will find new content on disk.
What design patterns are best suited for such task in ios?
A few come to my mind but I'm not as experienced.
- Perhaps push notifications, the server needs to push a message to all clients when there's a new version available.
- Or, Is there something similar to Android's Service that can help?
- Or, maybe every time the app starts (or goes to the foreground) just ping the server and see if there's anything new.
- Or, every time the app starts ping the server plus add a timer for the next 12h in case this app will still be in the foreground.
- Or, every time the app starts, check a preference value and if the last time the server was pinged was more than 12h ago, then ping it now. And then save this ping time.
Option 1 may be more heavy on the server and could be more complicated to implement (consider an ios newbe) but may be the only option for real background update. But even so, I still don't want the user to have to react to some low-level data update b/w a client and a server (and that's what it is), so unless push notifications can go directly to the app and execute something without the user's intervention then this option doesn't fly.
Options 3-5 are all possible and don't sound too hard but they would only work while the app is in the foreground.
From what I know, background apps can only either play music, get location updates or voip updates. There's even this hack with the silent sound that was trying to escape this limitation. (and was not approved to the store).
Perhaps the limitations in place are of good cause, so how do I play by the rules and be able to achieve a periodic server ping (or more generally, solve the problem of periodic sync b/w clients and servers even when apps are in bg)?
Thanks
I don't have a definite answer for your question, just a rambling set of comments that may help you decide what will work best for your situation. Sorry, this is the best I can offer.
One thing to keep in mind is that an app shouldn't use any of the phone's data-plan quota without letting the user know it's downloading something. Some apps are all about downloading stuff such as Twitter clients, so the nature of the app tells the user the app is using the data plan. Other apps, like a drawing program, have little explicit need for downloading, so should notify the user of a need for a download.
Because Apple doesn't allow developers the option of downloading in the background, people using iOS are trained to wait for their apps to download updated data. The typical way to improve the user experience while waiting for a download is to at a minimum show a spinner, letting the user know the app is working. To improve the interface even more, send the download to another thread, and allow the people to continue to use the rest of the app. They can interact with the old data, or use the parts of the app that are not in need of an update.
Apple doesn't give programmers a mechanism to download new content in the background for most app types. According to Apple's announcements, iOS 5's Newsstand feature will allow subscriptions to be updated in the background. Maybe in the future we developers will have more options for background downloading.
I have one app on the app store that uses method 5, and another in the works that uses method 3.
I'd use push notifications (method 1) if the people would want to know as soon as possible that new data is available. It would depend upon the topic.
iOS doesn't have anything like Android's service (method 2)
I have an app that checks an RSS feed for news each time the app is launched (method 3). This app mostly does other things, but shows the feed on the starting view. Since the app is a simple utility that helps people find a specific solution, the RSS feed is ancillary.
I like the timer idea in method 4. If you want to give the person a chance to approve the download, the timer could pop up an alert view, and then wait. That way the app doesn't actually download something if the device was just left sitting with your app in the foreground.
My implementation of method 5 in my currently available app has a little variation. It downloads the data for just one of many views. Each time this view is visited it checks against the stored time to see if it should download fresh data. Then it asks for permission.
Perhaps the limitations in place are of good cause, so how do I play
by the rules and be able to achieve a periodic server ping (or more
generally, solve the problem of periodic sync b/w clients and servers
even when apps are in bg)?
Any of options 3, 4, or 5 are the right way to go.
iOS applications typically don't even create their views until they're needed in order to conserve resources, so it definitely doesn't make sense to turn on the radio and download data that the user might never see.
If it's critical that the user have the most up-to-date data in order to use your app (seems unlikely if you're only updating twice a day) you should design your app in such a way that the user either won't see old data, or knows that the data is being updated. So, say your app is a mortgage calculator that needs to know what the currently available interest rates are. You could:
Take the user's input, but not display a result until you've confirmed that the data is up to date (or downloaded new data).
Take the users input and display the result using the data you have, but show the result in such a way that it's clear that the result may change. That might mean displaying a spinner near the numbers that might change or maybe showing the questionable numbers in a different color.
Display a 'data last updated at:...` message somewhere nearby.
Users typically don't mind waiting a few seconds for a mobile app to do its thing, especially if: a) they understand why the delay is happening, and b) their device works very well in other respects, such as having an appreciably longer battery life than other devices. For example, I'm constantly amazed at how long my iPad will run before needing a recharge; if the tradeoff is that I have to wait a few moments for apps to hit the network, I'm okay with that.
Most convenient message would be to notify the user of an update with push notifications and when your app starts it could show some "updating.." screen.
One of the main design concepts within iOs is that the app does what the user asks it to do. so if you have data-intensive updates you need to install, push notifications & update-dialog is the way you should go.
If your updates are very frequent (you wrote about 12h-checks -> assuming 24-48h update cycle), you might want to load new data every time the app starts. Friendly for iPad is a good example of this - they load tons of html/javascript/css to use as a framework for displaying facebook content in WebViews because facebook's structures change rapidly.
I would add the voip background mode string in your Info.plist file. Then you can call setKeepAliveTimeout:handler:
which allows you to periodically run a scheduled task. Keep in mind it will use more battery.
More info: http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH5-SW15