使用 ScenePhase 监听 App 活跃状态

了解如何使用 SwiftUI 中的 ScenePhase 环境变量来获取 App 状态,简化 UIKit 中复杂的通知代码。

使用 ScenePhase 监听 App 活跃状态

在 iOS 开发中,应用会经历多种状态转换,比如从前台进入后台、从后台恢复到前台等。有时候,开发者需要监听这些状态变化,并在特定的时候执行一些特定的逻辑,比如:

  • 在应用进入后台时保存用户数据: 例如保存用户填写但未提交的表单内容。
  • 刷新界面内容: 当应用从后台切换到前台时,更新视图以确保数据最新。
  • 读取剪切板:在恢复到前台时刷新界面或读取粘贴板数据(例如淘宝、拼多多)。
  • 释放资源: 在应用即将进入后台时暂停耗时任务或释放内存。

使用 ScenePhase 可以轻松实现以上需求。

什么是 ScenePhase

ScenePhase 是 SwiftUI 中的一个环境值(Environment),在 iOS14 中引入。用于表示当前场景(Scene) 的生命周期状态。

它的状态主要包括以下三个:

  • active:场景处于活跃状态,用户正在与其交互。
  • inactive:场景不可交互,但还没有完全进入后台(例如收到来电时)。
  • background:场景已经完全进入后台。

ScenePhase 使用方法

iOS14 之前,需要通过监听通知(如UIApplication.didBecomeActiveNotification )来手动处理这些事件。

例如,下面这个代码,用过 onReceive 监听 NotificationCenter 通知,来获取 App 何时从后台转为前台:

.onReceive(
    NotificationCenter.default.publisher(
        for: UIApplication.didBecomeActiveNotification)
) { _ in    
    checkClipboardForImage()
}

使用ScenePhase ,可以让这个实现更加简单、直观:

import SwiftUI

struct ContentView: View {
    @Environment(\.scenePhase) private var scenePhase

    var body: some View {
        Text("Hello, SwiftUI!")
            .onChange(of: scenePhase) { newPhase in
                switch newPhase {
                case .active:
                    print("App is active: 恢复更新 UI")
                    // 在应用变为活跃状态时刷新界面
                    refreshUI()
                case .inactive:
                    print("App is inactive: 暂停当前操作")
                    // 暂停动画或任务
                    pauseTasks()
                case .background:
                    print("App is in background: 保存用户数据")
                    // 保存数据或释放资源
                    saveUserData()
                default:
                    break
                }
            }
    }
    
    private func refreshUI() {
        // 刷新界面逻辑
    }
    
    private func pauseTasks() {
        // 暂停任务逻辑
    }
    
    private func saveUserData() {
        // 保存数据逻辑
    }
}

在上面的代码中,通过监听 scenePhase 的变化,可以明确应用处于哪个生命周期状态,并根据需要执行逻辑。