I am developing an iOS application for iPod Touch in which my application displays the server time always. I always sync the application time with server time whenever the application comes to foreground by making a web service call to the server. If there is a connectivity loss between my server and client for few hours I wont be able to sync the application time. I read iOS does not support running a timer when the application is in background other than few limited cases mentioned below:
Apps that play audible content to the user while in the background, such as a music player app
Apps that keep users informed of their location at all times, such as a navigation app
Apps that support Voice over Internet Protocol (VoIP)
Newsstand apps that need to download and process new content
Apps that receive regular updates from external accessories
So how can I keep track of application time? Whenever the user switches to my application he needs to look at the server time so I need to run a timer to update the last synced server time.
A combination of other answers, create a class in charge of obtaining the server time and maintaining the last time the application was synced to the server using a combination of NSDate* lastSync and applicationDidBecomeActive. For example:
-(void)applicationDidBecomeActive:(UIApplication*)application {
[ServerTimeSync sharedInstance] resync];
}
ServerTimeSync will maintain an NSDate* property with the last sync time (you'll want to convert what the server gives you to an NSDate*).
You can store the NSDate when the app goes into the background. When it resumes, get the current NSDate again, and add the difference to your stored server time.
You don't need a timer for this at all.
I would suggest that when you sync time with your server, you have it return its current UNIX timestamp. You can then do:
[[NSDate date] timeIntervalSince1970];
...to get the device's current UNIX timestamp. Then what you can do is store the difference between these two timestamps. This is the clock skew between the server time and the device time.
You can now compute the server's approximate time by taking the device's current UNIX timestamp and adding the clock skew to it. Adjust for time-zone when displaying it (if you want), and you're done. Whenever you sync time with the server, you can just refresh the stored clock skew value.
If you want to get fancy, you can also attempt to measure and take network latency into account when determining the clock skew.
This approach should work much better than trying to store the server's absolute timestamp and then track how much time has elapsed using a timer (or any other mechanism).
Related
I need to make an application that will start playing same media on two (or more) iPhones simultaneously, the problem is that it has to be perfect, no second delays and such. Is it possible that iPhone has some universal time stamp that is perfectly (or near-perfect) on every device. Or maybe I have some other options?
2 rules:
Find a way to have the same time on each devices
Use a "startAtTime" function using this shared uniform time. No "startNow" function.
the iPhones are supposed to be able to sync their date and time using a remote server, if this is not accurate enough (who knows), a way to achieve this (assuming you iPhone are able to communicate between them already):
The master send its time to a slave 10 (or more) times.
Each time the slave compare it's time with the one received and make a delta
After 10 tries, make a mean of the deltas and use this mean to adjust the slave time accordingly
There's no internal clock that is different to the system clock - so this means that each of the devices could have completely different time settings (in fact, it's highly likely that they will have different time settings even if only by a second or two).
Using a network/internet connection to synchronise against a central time server may be an approach that could be taken, but that would then require the network/internet connection and you would have to set the clocks taking into account lags on the connection to/from the time server.
You could have to have some kind of local synchronising system. If they are in close proximity, one approach may be to create an ad-hoc bluetooth connection between the devices in your app and then use some synchronisation code in you app to get the internal timers the same. You could, for example, have the first app to launch be the "controller" and then all the other apps would seek this controller and synchronise against it. The synchronisation could just be the controller sending out timestamp messages which the other devices can get and set an internal counter to match.
Without knowing much more about the requirements, it's hard to say how best to approach this as there may be limitations regarding time between running the app and it making the sound, or if you have to have a triggering signal, or if it is just at time x they need to make the sound.
If they are in same time zone and same time set ,you can schedule it to start your function in the paticular point of time using NSTimer's
- (id)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(id)ui repeats:(BOOL)rep;.
One option you have is to access the time from a common server and then start a timer on both devices accordingly (calculating depending on the time you got from the service)so you have exact time on both the devices and then play it ...
Even this has a catch as internet speed may vary and there might be a slight in delay on one of the two devices in getting the response from the server as compared to the other device and looking at your requirement they might go out of sync by a milisecond or so which will be visible.. :/ any other ideas anyone.. ?
In my application i want to run an internal clock in background mode [while application is not running in foreground].
The whole functionality will be like this:
The objective is to get the server time to use in the application, because using device time may sometimes cause issues. The issues may be in situations like somebody has changed the user's iPhone time etc. So i am following the below method.
-Running an internal clock in my application background even if the application is not running.
-Communicate with server every 15 minutes to get the real time and run a timer.
-If net is disconnected in between,timer will continue and take the timer time.
My application is heavily depended on this time factor as this is a ticket booking system.Kindly help me to implement this or please confirm whether this is possible or not?
I am developing an iPhone application which involves Ticket Booking System. I registered my application as location based beacuse it is using user's location taken in background for a purpose.
My problem is that i need to run an internal clock in my application in background mode. I need to write the codes for internal clock in core location delegate methods, so that internal clock will also run along with the location bsed services. Will my app get rejected? Is anything wrong in doing like this?
I need to get the correct time to use in my app, so that i am running this internal clock. I can use NSDate, but that will return the device time. Anyone can change the device time. So once somebody chaged, wrong time will affect the smooth functioning of the app. Kindly some body suggest to get the correct time with out running the internal clock ?
Update: Sorry to say my original answer isn't correct. When the device goes to sleep (can happen sometime after it's locked) the internal CPU clock stops ticking, and mach_absolute_time won't update either. Theoretically it will return the exact same value if you call it right before the device went to sleep, and after it awakes.
The best available way I know of to check for date changes is kern.boottime, it holds the boot time, and is modified whenever the system time changes. Among other things, kern.boottime will be updated if the user changes the time, or if the OS changes the time itself according to info from cell towers.
So, in your case, you can take the original time you calculated and modify it according to the modifications in kern.boottime. If you see kern.boottime changed significantly, it may mean that the device was turned off, and in this case you will need to contact the server to ask it for the time until the flight.
Relevant code:
time_t getBootTimeSecs(void)
{
struct timeval boottime;
size_t size = sizeof(boottime);
int ret = sysctlbyname("kern.boottime", &boottime, &size, NULL, 0);
assert(ret == 0);
return boottime.tv_sec;
}
Original (incorrect) answer: You can use mach_absolute_time which isn't affected by date changes made by the user.
When you book the ticket, get the correct date from the server and record mach_absolute_time. Now you will always be able to call mach_absolute_time whenever you want, calculate the difference from the one you recorded initially, and display the correct date.
This will only work as long as the device wasn't shut down, in that case it makes sense for the app to re-connect to the server to get the correct date.
You can also either Local or Push Notifications to alert the user when the target date is getting closer, even if the app isn't running.
apple is support small task for background mode which will work for approximate 10 sec only.
so you can do one thing when app is active then get time form server and update your local time according that.
I think that you can only detect that the date of the iOs device has been changed (using NSSystemClockDidChangeNotification).
I guess you to use this notification and force reload the real date of your application from your server (With a WebService).
EDIT: You can use the systemUptime in NSProcessInfo:
NSLog(#"ProcessInfo System uptime: %f",[NSProcessInfo processInfo].systemUptime);
but it will not solve your problem if the Device is restarted.
I think there are 2 ways you can go about solving your problem.
Never use system time. In other words, never call [NSDate date] in your code. When you need the current time, call an NTP server. This will of course cause latency in your app, but will guarantee accuracy.
When the app launches, or enters foreground, verify that the system time is reasonably accurate against an NTP server. If the system time is off by more than your tolerance level, then do not let them continue running the app until they address it. If the system time is okay, then start monitoring to ensure they don't change the system time while running the app (NSSystemClockDidChangeNotification). If they pass the initial check, but the move the clock forward, you can catch that and disable the app til they change it back to being accurate.
Here is an iOS NTP implementation which could be helpful in implementing either solution above. http://code.google.com/p/ios-ntp/
EDIT: The Ticketmaster app uses technique #2, so this seems like a reasonable solution for a ticketing app that requires your system time to be correct.
timezone settings should not affect time as in UTC
your app cannot run in the background. Abusing the location requirement for this will cause your app to be rejected by Apple
so my suggestion: do the logic server side with push notification
we are creating a location-enabled app where users use this app to record certain events in the field.
The important part of the event data is when an event happened. This is no issue when user is online, but we also support situations when user is offline (by remembering & later syncing events).
There could be situations when users are offline and they change the time on the phone, so that event times are wrongly recorded.
So, what would be the best way to ensure we get a correct time, independent of user actions, given that device could be offline. Some ideas:
GPS time. Is it possible to acquire it?
Tracking system time changes made by user?
Any other idea?
Note: time does need second accuracy, approximately minute accuracy would be ok.
Note2: we are creating mobile apps for Android and iPhone, so I'm interested for generic solutions and also solutions that are specific to any of those two platforms.
I, personally, wouldn't worry so much about this scenario. The liklihood of someone intentionally changing the time on their Android (which periodically throughout the day syncs to a time server automatically) while offline seems low to me. That being said, the only way I could see compensating for this is to keep a service running in the background that keeps a running tally of the seconds passed since recording the location data offline. Once uploaded to your servers you could use the elapsed seconds to calculate a time offset from current UTC time. It's an awful lot to go through, but it would work.
GPS time is an interesting idea, but Android allows users of the SDK to send mock locations to their devices. I'm not sure you could reliably track changes to system time either, and even if you could you'd be capturing them after the fact without the current real time as context.
We use GPS times in our app for very similar reasons. Since our users are in different time zones and we want local times, we define from our server what time zone they are in at installation time (they don't move very far). Hadn't thought of the mock GPS locations, but you would need to be a fairly advanced user to do that.
I have an app that requires me to take an action after some period of time. For example, if an user hasn't been inside the app in few weeks, when the user eventually starts the app, I have to ask them to put in a special code that was given to them when they installed this app. (this is an in-house app and i am being required to do this due to security concerns)
I am using the [NSDate date] method to retrieve the date when the user logs in and save it into a database. I compare this saved date next time they open up the app and see how long its been since their last login. The problem is that [NSDate date] gives the time that is effected by the time settings that can be changed manually by the user in the native settings app. As you can probably tell, this causes lots of problems to my situation. If the user is suppose to be put the special code after 3 weeks of inactivity, he can cause the app to show this screen by modifying the time in the native settings app or worse, get away from it by setting the time to a previous date that will be within 3 weeks of his activity.
Is there a way to get the "system time" instead of the "user time"? I have looked into mach_absolute_time() but this gets reset after restart of the device. Since the time of inactivity I will be comparing against is pretty large, chances are device would have been restarted by then. I also thought of using network connection to get the time from servers outside the app, but lots of users won't have access to wifi where they use their iPads. That will be my last resort solution if i can't find anything else. Because of their location during usage, I am trying to use everything on the device itself.
Am I overlooking something simple here? this seems too simple of a problem to not have an answer. Please guide me toward the right direction. Thank you in advance.
Why not query a remote server for the time - lots of NTP servers about or just make a simple HTTP request to a php script on your own server. Of course if your app is likely never to be connected to the internet that could be a problem, but once you have a 3rd party time its quite easy to guess if the user has been playing with the clock.
If this is an inhouse app (so you aren't constrained by Apples approval process), you could mark your app as doing some background stuff (voip or receiving location updates), so that the app will always be active and you'd be able to update some sort of an "unused" counter. Voip app will even be restarted by the OS after device reboot.
But of course it'll drain the battery somewhat.
Either: make having the actual time an essential feature of your app. This way the users will have a need to keep the time of the device current and can't go back three weeks
Or: mark the code as expired and save this information before the app informs the user. This will stop most user from setting the time back. Most will try once or twice, see that the app stays disabled and will give up.
You can also save the timestamp of the last successful execution and if that is more than a reasonable time frame in the future (remember summer/winter time) then consider it a "hack attempt". Put a CRC check (or whatever obscure idea you come up with) on that timestamp and save it too and you will stop a large number of script kiddies.
You can never stop the diehard hacker who search actively for every trick you might have put into the app. Just focus on the "average" user.
I am interested in building a Timer Based game such as mafia wars or soemthing like that. I'm stuck on one question.
What would be the best way to retain a timer, even if the app is closed?
Should I do this based on the Device Clock? or should I set a time to a server, and get the time when the device starts up?
If any one knows a better way for this,
let me know.
Thanks.
#lessfame
I'll interpret your question as "What's the best way to measure elapsed time between app launches?" instead of "How do I make a timer fire when my app is closed?".
There's no reliable and accurate way to measure time when the device is powered off (remote servers might not be reachable, astronomical measurements might not be possible if it's cloudy, ...). Don't bother.
That said, most CF/NS APIs use CFAbsoluteTime/NSDate (namely, CFRunLoopTimerGetNextFireDate() and -[NSTimer fireDate]). I'm not sure what they do if the system clock changes.
You can use mach_absolute_time() (and it's used internally by some things), but that's just system uptime, so it fails if the phone reboots. I'm not sure if you can get the boot UUID in order to find out if the phone has rebooted.
At the end of the day, CFAbsoluteTimeGetCurrent() or (equivalently) [NSDate date] is probably enough; just make sure that your app behaves sensibly if the time suddenly changes by a day or two in either direction.
Yes, the user can game the system by setting the system clock. You can mitigate this to some extent by occasionally syncing with the server, and keeping track of game time elapsed between syncs. If the difference between elapsed game time and server time is small, then just speed up or slow down the game appropriately to bring elapsed "game time" to real time. If the change is large, you can restore from the last save point on the server, or make the user wait until the elapsed game time has elapsed in server time, or a bunch of other things. This means you can't start playing until the initial sync, but the user has to be online to download the app anyway, so it's not a major problem.
If you only need to retain the time and show how much time elapsed since the game was closed (i.e. you don't need to notify the user when the time is up), you can use the [NSDate timeIntervalSinceNow] method to determine the amount of milliseconds that passed between two times.
If you are saying you want to just know time elapsed since some event, all you do is log the initial time, and then log the final time and compare the difference.
If you need a countdown timer to some event then what you do is set up a local push notification set to go off at the end time.