Unity开发:移动端应用最小化时内置计时器逻辑在Android失效
我之前在做Unity手游的时候也踩过这个坑——把应用最小化后,内置的计时器直接停了,查了一堆资料才搞定,下面是亲测有效的解决方案,分步骤来:
1. 先调整Unity的基础设置
这是最基础的一步,先让Unity允许应用在后台运行:
- 打开Unity的Player Settings(Edit > Project Settings > Player),切换到Android标签页
- 在Resolution and Presentation里,勾选Run In Background,这个选项会告诉Unity:即使应用不在前台,也继续运行逻辑
- 再到Other Settings里,找到Background Behavior,设置为Resume(不要选Suspend,否则后台会直接挂起进程)
2. 处理Android系统的后台限制
现在Android(尤其是8.0以上版本)对后台进程的限制非常严格,光靠Unity的设置不够,还得做这些:
- 添加必要权限:在Player Settings > Android > Other Settings > Configuration > Required Permissions里,添加
android.permission.FOREGROUND_SERVICE和android.permission.WAKE_LOCK(WAKE_LOCK用来保持CPU唤醒,避免系统休眠) - 引导用户添加后台白名单:不同品牌手机的路径不一样,比如小米是「设置 > 应用设置 > 应用管理 > 你的应用 > 省电策略 > 无限制」,华为是「设置 > 电池 > 应用启动管理 > 你的应用 > 允许自启动、允许后台活动」。这一步很关键,因为系统层面的杀进程操作,代码很难绕过,必须让用户手动设置。
3. 代码层面优化计时器逻辑
Unity自带的Time.time、Time.deltaTime会在应用挂起时暂停,所以必须改用系统时间来计算计时:
- 用
System.DateTime.UtcNow来记录起始时间,每次计算流逝时间时直接取当前系统时间和起始时间的差值,这样即使应用被挂起,系统时间还是在走的。示例代码:
private DateTime _timerStartTime; private float _totalElapsedSeconds; void Start() { // 记录计时器启动的UTC时间(避免时区问题) _timerStartTime = DateTime.UtcNow; } void Update() { // 计算从启动到现在的流逝时间,不受Unity挂起影响 _totalElapsedSeconds = (float)(DateTime.UtcNow - _timerStartTime).TotalSeconds; Debug.Log("已运行时长:" + _totalElapsedSeconds + "秒"); }
- 如果需要在后台持续执行逻辑(比如计时器到点触发事件),可以用Android的前台服务(Foreground Service)——前台服务的优先级比普通后台服务高,不容易被系统杀死。你可以通过Unity的AndroidJavaClass调用Android原生API实现,示例代码(需要配合自己写的Android服务类):
#if UNITY_ANDROID && !UNITY_EDITOR private AndroidJavaObject _foregroundService; void Start() { StartAndroidForegroundService(); } void StartAndroidForegroundService() { // 获取当前Unity Activity AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"); // 调用自定义的前台服务 AndroidJavaClass serviceClass = new AndroidJavaClass("com.yourgame.package.YourForegroundService"); _foregroundService = serviceClass.CallStatic<AndroidJavaObject>("getInstance", currentActivity); _foregroundService.Call("startForegroundService"); } void OnDestroy() { // 退出时停止前台服务 _foregroundService?.Call("stopForegroundService"); } #endif
注:自定义的Android前台服务需要打包成AAR放到Unity的Plugins/Android文件夹里,核心逻辑是创建服务后调用startForeground()方法,同时显示一个通知(Android要求前台服务必须显示通知)。
4. 测试注意事项
- 不要用Unity的Remote Debug测试后台行为,Remote模式下的后台逻辑和真机打包后的行为不一致,一定要打包APK安装到真机测试
- 重点测试Android 10+版本,这些版本的后台限制更严格,要确保计时器在后台能正常走
内容的提问来源于stack exchange,提问作者s.m.m




