iOS Development - Check Internet Time - ios

I am developing an app that has refills lives every 5 minutes. What is the best way to check the time since the last refill so that the user cannot trick the system by changing the time on their device?
For an example, look at Candy Crush. Changing the system time on there gives you extra lives, and this is what I need preventing.

How about running an [NSTimer scheduledTimerWithTimeInterval:300.0
target:self
selector:#selector(giveLife:)
userInfo:nil
repeats:YES];
That should execute giveLife every 5 minutes and there you can give the extra life.
As far as I can tell, NSTimer will not be affected by changing the clock time once it has started.

I would suggest You do something similar as it is in Clumsy ninja.
SHORT
Every time application becomes active [applicationDidBecomeActive:] - You try to get internet time.
If device time timestamp is smaller than stored timestamp - don't allow to continue. (Ask to connect to internet).
Implement a feature to save timestamp of the last regeneration cycle. Thus - even if user succeeds getting faster live refills, Once he reverts back to original time and continues game - it will show that next live refill will be way in the future at the time user was last using application, not 5 minutes. (To punish cheaters) (But maybe set a max limit, if last regenerate time is bigger than 5 minutes from current time, then set it to 1 hour? still a punish, but not so big to lose a player.
LONG
(Based on what I could distinguish)
Every time application becomes active - You try to get internet time. At that point - You don't need to check the time anymore while the app is opened, until the next time application becomes active again.
In clumsy ninja, they allow to use app even if internet is not available. So - if I activate airplane mode (for example), adjust time to be few hours forward, and open application - it sees that internet is not available, and thus cannot compare time. And - the things (punch bag, balls, etc) I had to wait to be repaired - are now repaired. Yay.
But If I do the same thing again many many times and finally I want to set back to original date and time - and open application, it will know that there is something not right. It probably stores some last opened timestamps, and if that time is bigger than actual device time - then user probably is doing something bad. And - alert appears - App must connect to server in order to continue.
Another downfall of moving time forward (for user, but great for developer) is - that there are some things, which will auto-regenerate after a while, but needs to be "picked" in order to initiate regenerating again. In clumsy ninja, chicken generates an egg once in a while. If Egg is not picked up, it still holds a timestamp, when it should be / was generated. So - imagine, user successfully forwards time many times (until it is already 1 day ahead of original time) - and now he wants to set the time back to original time, so that clock would actually show correct time. After user does that - when app is opened, time is synced but the generating egg will now show, that it will be ready after 1 day - last saved timestamp. But this could also be used for all items, which require time to be available. Why the clumsy ninja has not used this thing to all items? Maybe they are afraid, that if user sees, that nothing is available for a long time - user will stop playing. Thus - better have a cheater user, than no user at all.

NSURL *url = [NSURL URLWithString:#"http://www.timeapi.org/utc/now"];
NSString *str = [[NSString alloc] initWithContentsOfURL:url usedEncoding:Nil error:Nil];
str = [str stringByReplacingOccurrencesOfString:#"T" withString:#" "];
str = [str stringByReplacingOccurrencesOfString:#"+01:00" withString:#""];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyy-MM-dd hh:mm:ss"];
NSDate *date = [dateFormat dateFromString:str];

Related

Run code every 24 hours, but only after a specific time

In my apps settings page, users can select to have their data cleared every day, either at 3am, or 3pm, depending on their schedule. Im looking for a way to reliably do this.
So far I have tried storing the seconds since Jan 1, 1970 on install, and then every time time app is opened, I get the current seconds since 1970, and compare them to determine if the number meets or exceeds 86400, which is 24 hours. If it does, I clear the data and replace the stored seconds with the time of the clear, and if it doesn't I do nothing. This would work great if I only wanted to clear the data if its been 24 hours or more since the last clear, but what I really want to do is clear the data if its past the users set time, and a clear hasn't already been completed that day.
For example:
if the app is installed on May 21st at 6pm, and the user begins to input data, it should clear as long as the current data & time meets or is past May 22nd, at 3am. The 24 hour logic will not not clear it until the date and time meets or exceeds May 22nd, at 6pm.
Any thoughts on how this could be accomplished?
Well i'm not sure how you are planning on handling it(with push notifications/Local notifications/ or a simple check if the user has the app in the foreground)
However, I would create a local notification:
let notification = UILocalNotification()
notification.fireDate = Date().addingTimeInterval(86400)
UIApplication.sharedApplication().scheduleLocalNotification(notification)
Handle your clearing, and reset the notifications for 24-hours later once again.
Silent push notifications would be nice, as you would be able to clear the data every 24 hours, without your user needing to think about or even open the app. However, you would then need backend logic to handle sending out those notifications to the devices; you are limiting your reset times to 3am or 3pm so I suppose that wouldn't be terrible to implement.
Just keep in mind that you are limited to a 30s runtime. Also the silent notifications only complete if the app is suspended, if the app has been terminated by the user, the delegate method is not called.
--Edit--
Push notifications would be a little much for this, I must have missed the part saying you wanted this to happen on app start(sorry about that)....
You could write a extension to the Date class:
func dateByAddingDays(_ daysToAdd: Int) -> Date {
let calendar = Calendar.current
var days = DateComponents()
days.day = daysToAdd
return (calendar as NSCalendar).date(byAdding: days, to: self, options: [])
}
Save this date however you would like, then on app load compare the saved date to the current date, if it passes your check remove the data. You don't have to use days here, you can can replace days with hours/minutes etc... var hours = DateComponents() -> hours.hour = hoursToAdd

ios: find real time since previous app launch

SO basically all is in the title. I've searched quite a lot, but didn't find any right solution which doesn't require internet connection.
If the user changes time in settings - i can't find real time since last launch.
I need that for my game, in it for every hour, even when you don't play the game, you get some coins.
If the user changes time in settings - that affect the time in NSDate() and user can cheat with coins.
So save the NSDate() to user defaults on app launch. The next time the app comes to the foreground, or gets launched again, get the current NSDate and subtract the saved date from it. That will give you the number of seconds between the two dates. Calculating hours from seconds is a simple matter of dividing by 3600. – Duncan C just now edit
EDIT:
Note that in newer versions of Swift (starting with Swift 2?) Most Foundation classes were defined as native Swift classes without the NS prefix. For newer versions of swift, replace all occurrences of NSDate with Date in the above.
Also note that in iOS ≥ 7.0, the Calendar has some methods that make this sort of calculation neater and easier. There's a new method dateComponents(_:from:to:) that lets you calculate the difference between 2 dates in whatever units you want. You could use that to calculate the seconds between the 2 dates more cleanly than calculating seconds, as outlined in my original answer. Calendar methods also tend to handle boundary conditions like spanning daylight savings time, leap seconds, etc.
Consider the following Swift 4/5 playground code:
import UIKit
let now = Date()
let randomSeconds = Double.random(in: 100000...3000000)
let later = now + randomSeconds
if let difference = Calendar.current.dateComponents([.second],
from: now,
to: later)
.second {
print(difference)
Try this.
Step 1. When user exits game. Set a NSUserDefault with current time.
Step 2. When app launches, in your appDelagate file, get this value.
Step 3. Calculate diff between and award coins accordingly.

Is current time persisted across all iPhones?

I just have a quick question about how date and time works in iOS and Objective-C. If I make a call like NSDate *today = [NSDate date] on two separate devices, will they both return the exact same time? I am trying to have multiple phones sync up using the current time and I just want to make sure that they will have the same current time (if it's a matter of milliseconds I'm not worried but more than a second off will probably not work).
Thanks in advance!
Since NSDate stores a time internally as an NSTimeInterval, which is a typedef for double. It has in the sub-microsecond resolution for times within a decade or more of the date of this question.
This means that even if your two devices have closely synchronized clocks, you are unlikely to get exactly the same NSDate by calling [NSDate date] on both devices.
You can check whether two dates are within a second of each other like this:
NSTimeInterval diff = date0.timeIntervalSinceReferenceDate - date1.timeIntervalSinceReferenceDate;
if (fabs(diff) < 1) {
// dates less than one second apart
}

Is there a way to get the current Date in IOS (time not needed, accurate enough regardless of system date) using method that is not overkill?

I use the current date (YYYY-MM-DD) in a critical part of my app, and I need the correct date independant of the set system date. So far, the only option that I found that WOULD work is using an NTP server like this one here.
Problem: This is complete overkill for my purposes as I can deal with a +- several hour inaccuracy of the date. I simply need a somewhat accurate datestamp at various points throughout the app. All of the devices using my app will be connected to the internet as well as GPS, etc. I would even be happy to find a simpler method of finding the current date that would only work on some select devices, just something. I am wondering if anybody knows of any other ways now that actual time accuracy is not so important.
EDIT: I need this date to be independent of device date because the user could easily change the device date rendering it inaccurate.
Thank you.
You should probably use NTP, or at least a subset of NTP since you don't need that much accuracy, perhaps simply accepting the first value returned from the NTP server.
As an alternative, if you run your own web server, you could create a very simple server-side application that simply returns the date via HTTP/HTTPS. To prevent users from spoofing the server, you'd probably want to use HTTPS rather than HTTP although really clever users could still get around that issue by installing private certificates on the device or a network proxy.
Note that depending on a server means that your application won't run if there's no network available.
An alternative would be to use the system date routines as others have described, but write the date to either NSUserDefaults or, better yet, the device keychain. That way, your application can tell if the user turned the date backwards. There may be some edge cases you'd have to watch out for, though, like time zone changes.
NSDateFormatter *dateFormat = [NSDateFormatter new];
[dateFormat setDateFormat:#"YYYY-MM-DD"];
NSString *dateAsString = [dateFormat stringFromDate:[NSDate date]];
I have this method in my Utilities class.
+ (NSString *)formattedDate {
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd"];
NSString *todaysDate = [dateFormatter stringFromDate:[NSDate date]];
return todaysDate;
}
I put it in the header for results like this:
NSString *gameNameHeader = [NSString stringWithFormat:#"<p>&nbsp</p><h1>%# Results</h1><h2>%#%#</h2>",GAME_NAME_TITLE,[Utilities formattedClientName], [Utilities formattedDate]];

iOS prevent date/time update?

a relatively simple question that I've not been able to find a clear answer to. My app is more complex, but answering this question will suffice.
Suppose you're writing a stopwatch app. When the user taps "start", the app stores the current date and time in startTime:
startTime = [NSDate date];
When the user tapes "stop", the app stores the current date and time in stopTime:
stopTime = [NSDate date];
The duration is calculated by:
duration = [stopTime timeIntervalSinceDate:startTime];
and is displayed with something like:
[durationLabel setText:[NSString stringWithFormat:#"%1.2f", duration]];
The typical durations that my app is timing range from 2 to 50 seconds. I need accuracy to 1/100th of a second (e.g. 2.86 seconds).
I'm assuming that there is some protocol that iOS devices use to keep their clocks accurate (cellular or NTP sources?). My concern is that between starting and stopping the stopwatch, the clock on the iOS device is updated which can result in a shift of the current date/time either ahead or back. If this were to happen, the duration calculated would be inaccurate.
I've seen a few posts relating to timing methods for purposes of improving code efficiency. Some suggest using mach_time.h functions, which I'm not familiar with. It's not obvious to me which is the best approach to use.
Is it possible to disable iOS from updating the date & time? Is mach_absolute_time() unaffected by iOS clock updates?
Many thanks!
Tim
You are correct in thinking that CFAbsoluteTime and its derivatives (NSDate dateand so on) are potentially skewed by network updates on 'real' time. Add that to the fact that NSTimer has an accuracy of 50-100ms and you have a timer that is not suited to the most critical of time-sensitive operations.
The answer to this problem seems to be CACurrentMediaTime.
It is a member of the Core Animation group, but there shouldn't be any problem integrating it into non-animation based applications.
CACurrentMediaTime is a wrapper of mach_absolute_time() and makes sense of the "mach absolute time unit," which from my understanding is no fun to tinker with. mach_absolute_time() is calculated by running a non-network synced timer since the device was last booted.
There is relatively little information on CACurrentMediaTime but here are some sources and further reading:
Apple's sparse documentation of CACurrentMediaTime
Stack Overflow - NSTimer vs CACurrentMediaTime()
http://bendodsonapps.com/weblog/2013/01/29/ca-current-media-time/
http://blog.spacemanlabs.com/2011/09/all-in-the-timing-keeping-track-of-time-passed-on-ios/
http://forum.sparrow-framework.org/topic/accurate-timer
Note: If you do use CACurrentMediaTime, make sure you include and link the QuartzCore.framework
Check out this here. I would say forget about the current time check and use a precision timer since it won't rely on the current time but instead uses an interval.

Resources