在iOS进入后台时如何保持Socket心跳

解读

国内 iOS 游戏/应用上架审核对后台行为极其敏感,“保活 Socket”≈“后台长连接”,直接关联到电量、流量与隐私合规。面试官想确认三点:

  1. 是否理解 iOS 后台生命周期与系统限制;
  2. 能否给出合规且可落地的技术组合,而不是“强行保活”;
  3. 是否具备 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 电量测试”。

答案

分三步给出国内可过审的完整方案:

  1. Unity 入口快速标记后台任务
    OnApplicationPause(true) 内通过 UnitySendMessage 调用原生静态库:

    #if UNITY_IOS && !UNITY_EDITOR
        UnitySendMessage("GameManager", "OnPauseIOS", "");
    #endif
    

    原生层立即 beginBackgroundTaskWithExpirationHandler把未发出的业务包发完即主动 endBackgroundTask不尝试周期性心跳

  2. 真正的心跳交由 APNs/厂商推送

    • 客户端进入后台前把 uid+lastSeq 写入 NSUserDefaults
    • 服务端 90s 内无业务包则走离线推送(APNs 或华为/小米通道),payload 带 1 字节静默标志
    • 客户端收到推送后,若进程已被系统唤醒,则在 application:didReceiveRemoteNotification:fetchCompletionHandler拉起 30s Background Fetch,把未读数据通过短连接拉取,仍不维持长连接
    • 该方案在王者荣耀、和平精英等腾讯系产品已大规模验证,审核无阻力。
  3. Unity 层重连优化
    回到前台后,不立即重连,先判断 NetworkReachabilityTime.unscaledTime - lastHeartbeat > 5s,再使用指数退避(1-2-4-8s)发起新 TCP/TLS 握手;
    同时把原生层收到的离线消息一次性合并到 Lua 层队列,保证玩家无感知。

结论:iOS 进入后台后无法也不允许保持周期性 Socket 心跳;合规做法是用系统推送代替心跳,前后台切换时把未发数据在 30s 窗口内发完即可。

拓展思考

  • 如果产品强依赖实时对战,可让策划在后台 30s 窗口内把玩家置为“托管”状态,服务端 AI 接管,回到前台再插值同步,既省电又过审。
  • 对于企业内签或 TestFlight 的工业仿真类 App,可申请 External-Accessory 后台模式,用 MFi 蓝牙心跳维持私有协议,但上架 App Store 仍需剥离该代码。
  • 面试时可以反问面试官:“我们业务场景是 MMORPG 还是休闲卡牌?不同场景对‘实时’定义不同”,体现需求分析能力。