开发每24小时累加+5的应用,需规避设备时间对定时器的影响
Hey there! I’ve dealt with exactly this kind of problem before—users messing with system clocks to cheat timers is way more common than you’d think, so ditching the system clock entirely is the right move. Here’s how to build this reliably:
Core Idea: Use a Monotonic Clock
The key is to rely on a monotonic timestamp—this is a clock that counts time since the device booted up (or app launched, depending on the platform) and never goes backwards, even if the user changes the system date/time. It’s immune to manual adjustments, which is exactly what we need.
Step-by-Step Implementation
1. Persist Critical State Locally
First, you need to save two pieces of data every time an update happens (or when the app is backgrounded):
last_monotonic_time: The monotonic timestamp when the last +5 increment happened (or when we last checked the state)current_total: The current accumulated value (starts at 0, adds 5 every 24h)
Store these in a secure local storage (like SharedPreferences on Android, UserDefaults on iOS, or Hive/SharedPreferences in Flutter)—avoid plain text files so users can’t easily tamper with the values.
2. Calculate Elapsed Cycles & Update Values
Every time the app starts, comes back to the foreground, or you need to refresh the timer:
- Grab the current monotonic timestamp using your platform’s API:
- Android:
SystemClock.elapsedRealtime()(returns milliseconds since boot, including sleep) - iOS:
CACurrentMediaTime()(returns seconds since boot, use*1000for ms) - Flutter:
SystemClock.elapsedRealtime()(cross-platform wrapper for the above)
- Android:
- Calculate the time difference between now and the last saved timestamp:
time_diff = current_monotonic_time - last_monotonic_time - Figure out how many full 24-hour cycles have passed:
full_cycles = Math.floor(time_diff / 86400000) // 86400000ms = 24 hours - If any full cycles have passed, update your total and reset the last timestamp:
if (full_cycles > 0) { current_total += full_cycles * 5; // Shift the last timestamp forward by the exact number of full cycles last_monotonic_time += full_cycles * 86400000; // Save the updated state back to local storage saveToStorage("last_monotonic_time", last_monotonic_time); saveToStorage("current_total", current_total); }
3. Calculate & Display Remaining Time
Once you’ve updated the total, compute the remaining time until the next increment:
remaining_ms = 86400000 - (current_monotonic_time - last_monotonic_time); // Convert to minutes/hours for display remaining_minutes = Math.floor(remaining_ms / 60000); remaining_hours = Math.floor(remaining_minutes / 60);
To keep the UI updated, refresh this calculation every second while the app is in the foreground—don’t rely on a fixed interval timer that might drift or pause when the app is backgrounded.
4. Handle Device Reboots
Monotonic clocks reset when the device reboots, so we need a fallback here:
- If your app has internet access, sync with a server timestamp on first launch after reboot. Use the server’s current time to calculate how many full 24-hour cycles have passed since the last known increment, then update
current_totalandlast_monotonic_timeaccordingly. - For offline-only apps, you can store a backup of the system timestamp alongside the monotonic timestamp before reboot. When the app restarts, compare the current system time to the backup (note: this isn’t 100% foolproof if the user changed the time after reboot, but it’s better than nothing).
Pro Tips
- Test Edge Cases: Simulate changing the system time forward/backward while the timer is running to make sure the remaining time stays accurate.
- Avoid Tampering: Encrypt the stored state if possible—users might try to edit the local storage to cheat the accumulated value.
- Background Updates: On mobile, use platform-specific background tasks to trigger updates even if the app isn’t open (but keep in mind battery restrictions—you don’t want to drain the user’s battery).
内容的提问来源于stack exchange,提问作者Sarmer

