Reading time: 1 min

This recipe shows two ways of detecting when your app goes to foreground or background.

NotificationCenter solution

The first solution works on iOS 13+ and any device, iPhone or iPad, and is generally the one you should use. First, add these two extensions to your app:

extension View {
  func onAppCameToForeground(perform action: @escaping () -> Void) -> some View {
    self.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
       action()
    }
  }

  func onAppWentToBackground(perform action: @escaping () -> Void) -> some View {
    self.onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) { _ in
      action()
    }
  }
}

Then, you can use it on any View you'd like:

var body: some View {
  VStack {
    Text("Some content")
  }
  .onAppCameToForeground {
    print("App came to foreground")
  }
  .onAppWentToBackground {
    print("App went to background")
  }
}
ScenePhase solution

The second solution relies on observing the scenePhase environment variable, which changes its value as the app state changes. The thing is, this only works only on iOS 14+, and only on iPhone: since an iPhone app only has a single screen, a change in the scenePhase equals a change in the entire app, which isn't true for iPad apps.

@Environment(\.scenePhase) var scenePhase

var body: some View {
  VStack {
    Text("Some content")
  }
  .onChange(of: scenePhase) { newPhase in
    switch newPhase {
    case .background:
      print("App went to background")
    case .active:
      print("App became active (or came to foreground)")
    case .inactive:
      print("App became inactive")
    @unknown default:
      print("Well, something certainly happened...")
    }
  }
}

Tip: You can track app (in)activity via the NotificationCenter solution by subscribing to didBecomeActiveNotification and willResignActiveNotification, respectively.

Next Post Previous Post