iOS Time change notification and previous time - ios

I have an application that works with timeout (let's say -> ring in 3 days). My problem occurs if a user change the device local time while being offline because I am comparing two NSDate (the final date and today) to check that timeout.
So I am trying to get notified when a user made a significant time change (several hours or days) in order to update my timers depending on the difference between before and after the update.
I found the UIApplicationSignificantTimeChangeNotification, which does :
Posted when there is a significant change in time, for example, change to a new day (midnight), carrier time update, and change to or from daylight savings time.
That nearly fits but I can't figure out how to get the "old" time in order to get the difference. I can't rely on a webserver neither because the app should be running in offline mode.
Any idea or suggest is welcome ;)

I finally find a way to solve my problem by using the CPU time (which is always constantly increasing except on reboot).
First time the app is launched, I get the Real time and the CPU time.
Then, when I need to check if time has been changed, I just take
the Real time at first, I add to it ( the current CPU time - the CPU time at first).
This give me the correct time.
Note: take care to use the real CPU time, not the one used by timer because it's stop when device go to sleep.

You should store the current time of your device, when your application goes into background. When the application comes into foreground, you should take the current time of your device. Now measure the difference between these 2 dates. If it is less than zero, it means, the user has set the device with previous date and you should throw the error of time out. If the difference is greater than 0, then you should compare current time with actual finish date.
One more indirect way is to start the location tracking of your device. Keep it on even when the app goes into background. When your didUpdateLocation delegate will hit by system, you will receive CLLocation object in argument. This location object is having currentTime details. Compare the time of last location and current location. If it is negative, user has bluffed with time. Its time to take the action.

Related

iOS do scheduled operation in background or when app active

I have CoreData model which I want to update at 12 AM. So it's kind of an even when the app can recognize that a new day is coming and at 12 AM change some things in data models.
Initially, the idea was:
Prepare a single function that returns updated data. So before the function returns smth I every time check for the time (NSDate interval between two dates) and then update data model (if it's a new day). But the architecture not so simple for this purpose and it will take some time to prepare for a single point where I can get updated data, also it takes some time in background to update CoreData model which also adds some expenses to this task.
Is this ok solution to use some timer which will update data at 12 AM, I don't care about consistency in this case, but I don't like a timer which is checking every single second is 12 AM already or not. Is there some push notification update or some scheduler manager in iOS which can update data for me. One more time I just want to update the data layer and I don't care about consistency in UI. If consistency matter for sure then I would like to follow initial ide with a single point of retrieving data.
So I probably need some scheduler manager for this purpose or rewrite code of how I get the data.
There is no way to execute a function at regular intervals, even when the app is backgrounded/killed by the user.
The most reliable solution for executing a function at regular intervals even when the app is backgrounded is to use push notifications scheduled for the specific time intervals (midnight each day in your case), which would wake up the app and let it update its data. However, this solution has its downsides, since you need a server to send the push notification from and the users device needs to be connected to the internet. Also, push notifications don't wake up the app in case the user manually killed it.
For your particular problem, the best solution would be to refactor your code in a way that you have a single function that can be used to retrieve data and hence this function could ensure the data is updated in case a certain time interval has passed since the last update.
You might want to look into BGProcessingTask. You won't have granular control over when you're granted CPU time but you can set the interval you'd prefer that the task execute. Ultimately, when you run and how often is up to the system.
I would recommend checking out the new BackgroundTasks Framework Apple releases for iOS 13.
https://developer.apple.com/documentation/backgroundtasks
While you are not guaranteed at specific time if you have a window (12 am - 3 am) scheduling background tasks may be sufficient for you.

Check if system time is auto or user set

I need to set up user proof time keeping in my current project. I have found a lot of different question around this, but none that seem to have the answer I am looking for. These are the questions i have looked at so far:
XCODE: How to get/verify ACCURATE timestamp from device
Is it possible to get the atomic clock timestamp from the iphone GPS?
How can I get the real time in iPhone, not the time set by user in Settings?
I have several options for getting a time from a server connection but I need to have an offline solution too.
1.
It seems that using CLLocation gets the same time as as the device clock. Is there away to get the actual GPS time?
2.
I know the system time settings are not a public API thus can't be changed. Is it possible to find out if the device has the auto time setting turned on? If the auto time is on then I can rely on the system time for my purposes and if it's off then record that so I know that the time recorded is not to be trusted?
Just wanted to post my solution, incase some one else has the same issue.
After much research i found that getting GPS time of time setting info was not possible.
This solution isn't perfect nor real time but works for my purpose.
I have implemented a time check using cloud time each time the app comes on line. When the device re-establishes a server connection to sync events created off line i have put a verification that takes the last object device time and the new object device time and calculates the elapsed time between the two. (using NSdates so that daylight savings is covered) then do the same with the last available server time and the most recent server time. I then compare the results and if they are not within my margin of error the events are marked as invalid.
Hope that makes sense and is helpful for others.

Can I prevent an iOS user from changing the date and time?

I want to deploy managed iOS devices to employees of the company, and the app they will use will timestamp data that will be recorded locally, then forwarded. I need those timestamps to be correct, so I must prevent the user from adjusting the time on the device, recording a value, then resetting the date and time. Date and time will be configured to come from the network automatically, but the device may not have network connectivity at all times (otherwise I would just read network time every time a data value is recorded). I haven't seen an option in Apple Configurator to prevent changing the date and time, so is there some other way to do this?
You won't be able to prevent a user either changing their clock or just hitting your API directly as other commentators have posted. These are two separate issues and can be solved by having a local time that you control on the device and by generating a hashed key of what you send to the server.
Local Time on Device:
To start, make an API call when you start the app which sends back a timestamp from the server; this is your 'actual time'. Now store this on the device and run a timer which uses a phone uptime function (not mach_absolute_time() or CACurrentMediaTime() - these get weird when your phone is in standby mode) and a bit of math to increase that actual time every second. I've written an article on how I did this for one of my apps at (be sure to read the follow up as the original article used CACurrentMediaTime() but that has some bugs). You can periodically make that initial API call (i.e. if the phone goes into the background and comes back again) to make sure that everything is staying accurate but the time should always be correct so long as you don't restart the phone (which should prompt an API call when you next open the app to update the time).
Securing the API:
You now have a guaranteed* accurate time on your device but you still have an issue in that somebody could send the wrong time to your API directly (i.e. not from your device). To counteract this, I would use some form of salt/hash with the data you are sending similar to OAuth. For example, take all of the parameters you are sending, join them together and hash them with a salt only you know and send that generated key as an extra parameter. On your server, you know the hash you are using and the salt so you can rebuild that key and check it with the one that was sent; if they don't match, somebody is trying to play with your timestamp.
*Caveat: A skilled attacked could hi-jack the connection so that any calls to example.com/api/timestamp come from a different machine they have set up which returns the time they want so that the phone is given the wrong time as the starting base. There are ways to prevent this (obfuscation, pairing it with other data, encryption) but that becomes a very open-ended question very quickly so best asked elsewhere. A combination of the above plus a monitor to notice weird times might be the best thing.
There doesn't appear to be any way to accomplish what you're asking for. There doesn't seem to be a way to stop the user from being able to change the time. But beyond that, even if you could prevent them from changing the time, they could let their device battery die, then plug it in and turn it on where they don't have a net connection, and their clock will be wrong until it has a chance to set itself over a network. So even preventing them from changing the time won't guarantee accuracy.
What you could do is require a network connection to record values, so that you can verify the time on a server. If you must allow it to work without a net connection, you could at least always log the current time when the app is brought up and note if the time ever seems to go backwards. You'll know something is up if the timestamp suddenly is earlier than the previous timestamp. You could also do this check perhaps only when they try to record a value. If they record a value that has a timestamp earlier than any previous recorded value, you could reject it, or log the event so that the person can be questioned about it at a later time.
This is also one of those cases where maybe you just have to trust the user not to do this, because there doesn't seem to be a perfect solution to this.
The first thing to note is that the user will always be able to forge messages to your server in order to create incorrect records.
But there are some useful things you can use to at least notice problems. Most of the time the best way to secure this kind of system is to focus on detection, and then publicly discipline anyone who has gone out of their way to circumvent policy. Strong locks are meaningless unless there's a cop who's eventually going to show up and stop you.
Of course you should first assume that any time mistakes are accidental. But just publicly "noticing" that someone's device seems to be "misbehaving" is often enough to make bad behaviors go away.
So what can you do? The first thing is to note the timestamps of things when they show up at the server. Timestamps should always move forward in time. So if you've already seen records from a device for Monday, you should not later receive records for the previous Sunday. The same should be true for your app. You can keep track of when you are terminated in NSUserDefaults (as well as posting this information to the server). You should not generally wake up in the past. If you do, complain to your server.
Watch for UIApplicationSignificantTimeChangeNotification. I believe you'll receive it if the time is manually changed (you'll receive it in several other cases as well, most of them benign). Watch for time moving significantly backwards. Complain to your server.
Pay attention to mach_absolute_time(). This is the time since the device was booted and is not otherwise modifiable by the user without jailbreaking. It's useful for distinguishing between reboots and other events. It's in a weird time unit, but it can be converted to human time as described in QA1398. If the mach time difference is more than an hour greater than the wall clock time, something is weird (DST changes can cause 1 hour). Complain to your sever.
All of these things could be benign. A human will need to investigate and make a decision.
None of these things will ensure that your records are correct if there is a dedicated and skilled attacker involved. As I said, a dedicated and skilled attacker could just send you fake messages. But these things, coupled with monitoring and disciplinary action, make it dangerous for insiders to even experiment with how to beat the system.
You cannot prevent the user from changing time.
Even the time of an Location is adjusted by Apple, and not a real GPS time.
You could look at mach kernel time, which is a relative time.
Compare that to the time when having last network connection.
But this all sounds not reliable.

Getting updated server time every second

I have a requirement where I need to know what is the server time at a given point of time in the app. As soon as the app connects to server, the server sends back the time and I am not sure how to update this time.
I thought of using the timers where the method is called every second and and a second is added to server time, so that whenever I ask for server time it is always updated one. But problem with this if we schedule this on main runloop, the run loop may or may not process the timer request if there it is busy.
So how to track the server time?
Thanks
Your server is in a specific time zone correct? Just get the time zone of the server using a request and show the time in that time zone in your app. You can then use a timer to continue updating the time every second.
I suggest getting just the time zone because if you get the server's time, there would be a lag between when the server sends back the response and when you get it - which defeats the whole purpose of getting the time as on the server.
You can't update the iOS system time from your app; there is no API
for that.
iPhone's time is usually very accurate. On iPads, it varies but has improved with iOS 5 to +/- 5 seconds if some form of internet connectivity is available.
If you want to manually connect to a server to synchronize time, you
should do it in a background task.
To compensate for latency, you should make multiple requests and add
the average half of the roundtrip time to the time sent by the server.
However, the question remains: Why do you want to do that anyway?

Auto-detect time of day

I'm writing a daily to do list app, and want the app to update certain elements with each new day. This isn't a problem if the user closes the app one day and then reopens it the next -- I just compare days in the startup methods.
However, this is a problem if the user happens to be using the app exactly at midnight. At midnight, daily task elements need to reset themselves automatically for the new day.
Here's my issue -- I could have a constant thread running in the background, always accessing [NSDate date] and checking for a new day. But I feel like there must be a better way, especially because this only has to happen once per day (and then, only if the user is using the app at midnight).
Thank you in advance!
In applicationDidFinishLaunching: and applicationWillEnterForeground:, setup an NSTimer scheduled to trigger at midnight. Also, register for UIApplicationSignificantTimeChangeNotification to reschedule the timer for time zone changes etc.

Resources