本地本机-iOS时间破解背景倒数计时器

我想创build一个本地的本机iOS的时间黑客certificate背景倒计时计时器 ,例如为倒计时下次在游戏中的奖励。

对象的解释:

本地
– 没有互联网连接

原生的iOS
– 我想find一个解决scheme(最好)Objective-C或Swift

时间黑客certificate
– 用户向前/向后更改设备时间时,剩余时间保持不变

背景
– 关机/重新开放友好

倒计时器
– 一个计时器,开始后,将提供一个方法来检查剩余时间

我想在我的iOS游戏中有一个基于时间的奖励系统,只要将设备时间向前移动,这个系统就不容易被破解。

最初,我认为这是不可能的,并保持使用[NSDate date]savedDate ,比较它们在一起,以查找经过的时间。 不过最近我遇到了一个使用这个function的游戏: Crossy Road 。 据我所知,这是一个Unity游戏,但我怀疑在Unity项目中可用的一些常见function(这些function被编译到iOS应用程序中)不能通过Objective-C或Swift在iOS上访问。

他们提供了一个定时的奖励系统,每6小时一次,而据我testing,这是不是通过改变设备时间hackable。 它也没有互联网连接。 (如果不连接,我不确定它是否能正常工作,但是当我连接,断开连接并试图使用黑客时,它不起作用。)

您可以使用当前的系统正常运行时间( mach_absolute_time() )。 使用CACurrentMediaTime()可以方便地访问这个函数, CACurrentMediaTime()可以在几秒钟内轻松返回。 那么你可能需要设置一些时间间隔来检查这个值。 这当然可以使用NSDate来完成,因为它不是由用户设置时钟向前触发的问题。 重新启动时,只需保存起始值并在重新启动后将其用作偏移量即可。

唯一的缺点是,它不计算设备closures的时间,但是现在当没有人打开手机时,这通常不是什么大问题。

要获得实际的计时器function,只需在开始时保存该值,然后定期对照计划的最终值对其进行检查,或许随着结束时间的增加而增加分辨率。

对于我正在构build的应用程序,我有这些完全相同的要求。 我尝试使用CACurrentMediaTime(),但是当你closures设备它重置为0这不是你想要的。 甚至在closures设备时也能使用这个时间参考:

 currentUser.timeLastUpdated = [[NSDate date] timeIntervalSince1970]; 

这里是帮助你实现定时器的代码。 这是从另一个stackoverflow线程修改的。

在MainViewController.m中

 @interface MainViewController () @property (strong, nonatomic) IBOutlet UILabel *countdownLabel; @end @implementation MainViewController { UserData *_currentUser; int hours; int minutes; int seconds; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. _currentUser = [UserData currentUser]; [self updateTimerText]; [self startTimer]; } - (void)startTimer { [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTimer:) userInfo:nil repeats:YES]; } - (void)updateTimer:(NSTimer *)timer { if (_currentUser.secondsLeft > 0) { _currentUser.secondsLeft--; [self updateTimerText]; } } - (void)updateTimerText { int secondsLeft = _currentUser.secondsLeft; hours = secondsLeft / 3600; minutes = (secondsLeft%3600) / 60; seconds = (secondsLeft%3600) % 60; self.countdownLabel.text = [NSString stringWithFormat:@"%02d:%02d:%02d",hours,minutes,seconds]; } } 

现在为了让它无懈可击,所以当你停止应用程序时,它不会停止计数,你需要修改AppDelegate.m。

在AppDelegate.m中

 @implementation AppDelegate { UserData *currentUser; } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. // Intialize currentUser currentUser = [UserData currentUser]; // Reset secondsLeft based on lastTimeUpdated if (currentUser.secondsLeft > 0 && currentUser.lastTimeUpdated != 0) { currentUser.secondsLeft -= ((int)[[NSDate date] timeIntervalSince1970]) - currentUser.lastTimeUpdated; } return YES; } - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. // Set the last time updated (only need to call it here because this is coupled with applicationWillTerminate currentUser.lastTimeUpdated = (int)[[NSDate date] timeIntervalSince1970]; } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. // Reset secondsLeft based on lastTimeUpdated if (currentUser.secondsLeft > 0 && currentUser.lastTimeUpdated != 0) { currentUser.secondsLeft -= ((int)[[NSDate date] timeIntervalSince1970]) - currentUser.lastTimeUpdated; } } 

你只需要修改AppDelegate中的三个方法,因为ApplicationWillTerminate总是用ApplicationDidEnterBackground触发(据我所知)。

打扰currentUser.secondsLeft和currentUser.lastTimeUpdated是整数。 我铸造[[NSDatedate] timeIntervalSince1970]作为一个整数,因为它返回一个CFTimeInterval是一个双重的types。

最后,您必须确保将其保存到数据库中。 我懒洋洋地将这两个variables保存到NSUserDefaults,只要通过在我的UserData.m文件中包含以下代码进行更新:

在UserData.m中

 -(void)setSecondsLeft:(int)secondsLeft { _secondsLeft = secondsLeft; [[NSUserDefaults standardUserDefaults] setObject:@(secondsLeft) forKey:@"secondsLeft"]; } -(void)setLastTimeUpdated:(int)lastTimeUpdated { _lastTimeUpdated = lastTimeUpdated; [[NSUserDefaults standardUserDefaults] setObject:@(lastTimeUpdated) forKey:@"lastTimeUpdated"]; 

这样当应用程序退出时,数据被保存起来供以后使用。