在iOS进入后台时如何保持Socket心跳
解读
国内 iOS 游戏/应用上架审核对后台行为极其敏感,“保活 Socket”≈“后台长连接”,直接关联到电量、流量与隐私合规。面试官想确认三点:
- 是否理解 iOS 后台生命周期与系统限制;
- 能否给出合规且可落地的技术组合,而不是“强行保活”;
- 是否具备 Unity 侧与原生侧联调、灰度验证与线上监控的完整闭环思路。
答得太“简单”会被追问“审核被拒怎么办”;答得太“hack”会被直接判负。必须给出官方允许范围内最稳方案,并说明“做不到 100% 实时”也是业务必须接受的事实。
知识点
- iOS 后台模式(UIBackgroundModes):VOIP、Audio、Location、External-Accessory、Bluetooth-Central、Processing、Push 等,只有 VOIP 持续 Socket 保活但已被苹果废弃,新包一律禁止使用。
- Background Task(beginBackgroundTaskWithExpirationHandler):进入后台后最多30s(实测 iOS17 高频场景 8~15s),Unity 的 OnApplicationPause(false) 触发后必须在此窗口内把未发完的数据发完,无法周期性心跳。
- PushKit & CallKit:原生 VOIP 推送通道,苹果仍允许,但游戏类 App 若无真实通话功能会被 4.3 条款拒审;国内版号游戏基本无法使用。
- NSURLSession/URLSessionWebSocketTask:后台会话由系统托管,可配置 discretionary 与 timeout,但只能“短连接”,不能维持长心跳。
- Unity 层生命周期:OnApplicationPause(bool) 与 OnApplicationFocus(bool) 在 iOS 与 Android 表现不同,必须区分平台宏 UNITY_IOS。
- 国内合规:工信部 337 号文、App Store 审核指南 2.5.4、5.1.1,后台偷跑网络属于“违规收集”,可被下架并通报。
- 热更新框架(Lua/ILRuntime):心跳逻辑若跑在脚本层,后台任务被挂起后解释器不再调度,必须下沉到原生代码。
- 电量与流量监控:Xcode Energy Log、sysdiagnose、Unity Profiler 的 Network Messages 模块,面试时要提到“上线前跑 24h 电量测试”。
答案
分三步给出国内可过审的完整方案:
-
Unity 入口快速标记后台任务
在OnApplicationPause(true)内通过UnitySendMessage调用原生静态库:#if UNITY_IOS && !UNITY_EDITOR UnitySendMessage("GameManager", "OnPauseIOS", ""); #endif原生层立即
beginBackgroundTaskWithExpirationHandler,把未发出的业务包发完即主动endBackgroundTask,不尝试周期性心跳。 -
真正的心跳交由 APNs/厂商推送
- 客户端进入后台前把
uid+lastSeq写入NSUserDefaults; - 服务端 90s 内无业务包则走离线推送(APNs 或华为/小米通道),payload 带 1 字节静默标志;
- 客户端收到推送后,若进程已被系统唤醒,则在
application:didReceiveRemoteNotification:fetchCompletionHandler里拉起 30s Background Fetch,把未读数据通过短连接拉取,仍不维持长连接。 - 该方案在王者荣耀、和平精英等腾讯系产品已大规模验证,审核无阻力。
- 客户端进入后台前把
-
Unity 层重连优化
回到前台后,不立即重连,先判断NetworkReachability与Time.unscaledTime - lastHeartbeat > 5s,再使用指数退避(1-2-4-8s)发起新 TCP/TLS 握手;
同时把原生层收到的离线消息一次性合并到 Lua 层队列,保证玩家无感知。
结论:iOS 进入后台后无法也不允许保持周期性 Socket 心跳;合规做法是用系统推送代替心跳,前后台切换时把未发数据在 30s 窗口内发完即可。
拓展思考
- 如果产品强依赖实时对战,可让策划在后台 30s 窗口内把玩家置为“托管”状态,服务端 AI 接管,回到前台再插值同步,既省电又过审。
- 对于企业内签或 TestFlight 的工业仿真类 App,可申请 External-Accessory 后台模式,用 MFi 蓝牙心跳维持私有协议,但上架 App Store 仍需剥离该代码。
- 面试时可以反问面试官:“我们业务场景是 MMORPG 还是休闲卡牌?不同场景对‘实时’定义不同”,体现需求分析能力。