Unity中如何获取SystemClock.elapsedRealtime()实现防篡改离线游戏计时
获取系统重启后运行时长,实现离线防篡改游戏计时器
核心思路
系统自重启后的运行时长(Uptime)是独立于系统时间的指标,修改系统时间不会改变它。我们可以通过各平台原生API获取该值,再结合PlayerPrefs记录游戏每次退出时的Uptime,重启后计算差值即可得到游戏累计运行时间——这就是你看到的Elapsed_stamp变量的作用逻辑。
各平台Uptime获取实现
Windows平台
调用kernel32.dll的GetTickCount64()获取系统启动以来的毫秒数:
using System.Runtime.InteropServices; public static class SystemUptime { [DllImport("kernel32.dll")] private static extern ulong GetTickCount64(); public static ulong GetUptimeMilliseconds() { return GetTickCount64(); } }
macOS/Linux平台
用Mono的SystemInformation直接获取,或通过系统原生接口实现:
using System.Windows.Forms; public static ulong GetUptimeMilliseconds() { return (ulong)SystemInformation.TickCount; }
macOS原生调用版本:
using System.Runtime.InteropServices; public static class SystemUptime { [DllImport("libc.dylib")] private static extern int sysctlbyname(string name, IntPtr oldp, ref uint oldlen, IntPtr newp, uint newlen); public static ulong GetUptimeMilliseconds() { uint len = sizeof(long); IntPtr ptr = Marshal.AllocHGlobal((int)len); sysctlbyname("kern.boottime", ptr, ref len, IntPtr.Zero, 0); long bootTime = Marshal.ReadInt64(ptr); Marshal.FreeHGlobal(ptr); long now = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); return (ulong)(now - bootTime) * 1000; } }
Android平台
调用Android系统的SystemClock.elapsedRealtime():
using UnityEngine; public static ulong GetUptimeMilliseconds() { AndroidJavaClass systemClock = new AndroidJavaClass("android.os.SystemClock"); return (ulong)systemClock.CallStatic<long>("elapsedRealtime"); }
iOS平台
通过mach_absolute_time()转换为实际运行毫秒数:
using System.Runtime.InteropServices; using UnityEngine; public static class SystemUptime { [DllImport("libSystem.dylib")] private static extern uint mach_absolute_time(); [DllImport("libSystem.dylib")] private static extern void mach_timebase_info(ref TimebaseInfo info); private struct TimebaseInfo { public uint numer; public uint denom; } public static ulong GetUptimeMilliseconds() { TimebaseInfo info = new TimebaseInfo(); mach_timebase_info(ref info); ulong absoluteTime = mach_absolute_time(); ulong nanoseconds = absoluteTime * (ulong)info.numer / (ulong)info.denom; return nanoseconds / 1000000; } }
结合PlayerPrefs实现计时器逻辑
每次游戏退出时记录当前Uptime和累计时间,启动时计算差值更新总时长:
using UnityEngine; public class GameTimer : MonoBehaviour { private const string Prefs_UptimeStamp = "Elapsed_stamp"; private const string Prefs_TotalGameTime = "Total_Game_Time"; private ulong _lastUptime; private double _totalGameTime; void Start() { if (PlayerPrefs.HasKey(Prefs_UptimeStamp) && PlayerPrefs.HasKey(Prefs_TotalGameTime)) { _lastUptime = (ulong)PlayerPrefs.GetInt(Prefs_UptimeStamp); _totalGameTime = PlayerPrefs.GetFloat(Prefs_TotalGameTime); } else { _lastUptime = SystemUptime.GetUptimeMilliseconds(); _totalGameTime = 0; } } void Update() { ulong currentUptime = SystemUptime.GetUptimeMilliseconds(); if (currentUptime > _lastUptime) { double delta = (currentUptime - _lastUptime) / 1000.0; _totalGameTime += delta; _lastUptime = currentUptime; } } void OnApplicationQuit() { PlayerPrefs.SetInt(Prefs_UptimeStamp, (int)_lastUptime); PlayerPrefs.SetFloat(Prefs_TotalGameTime, (float)_totalGameTime); PlayerPrefs.Save(); } public double GetTotalGameTime() { return _totalGameTime; } }
关键注意事项
- 用
Application.platform做平台分支判断,确保各平台调用对应Uptime获取方法。 PlayerPrefs存储为明文,可通过简单异或加密存储值,防止玩家直接修改文件篡改时间。- 优先使用64位返回值,避免32位Uptime变量溢出问题。
内容的提问来源于stack exchange,提问作者Xordaraxus
相关产品推荐
相关产品推荐

