Not Receiving scenePhase Changes
I acknowledge this question is specifically about schenePhase
changes, however, on macOS I am not able to receive any .background
notifications when a user switches to a different app. The older NotificationCenter
strategy works as I expected, on both platforms. I'll add this to the mix for anyone who is just trying to execute some code, onForeground
/ onBackground
on iOS
and macOS
.
On any view, you can attach:
.onReceive(NotificationCenter.default.publisher(for: .willResignActiveNotification)) { _ in
doBackgroundThing()
}
The events you may care about are:
- iOS:
willResignActiveNotification
&willEnterForegroundNotification
- macOS:
willResignActiveNotification
&willBecomeActiveNotification
You can find all NotificationCenter
Name
s here.
I use will*
variants for background because I assume they'll be called early in the process, and I use did*
variants for foreground, because they are called regardless of whether the app is launched for the first time, or it's coming out of background.
I use this extension so I don't have to think about the platform differences:
extension View {
#if os(iOS)
func onBackground(_ f: @escaping () -> Void) -> some View {
self.onReceive(
NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification),
perform: { _ in f() }
)
}
func onForeground(_ f: @escaping () -> Void) -> some View {
self.onReceive(
NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification),
perform: { _ in f() }
)
}
#else
func onBackground(_ f: @escaping () -> Void) -> some View {
self.onReceive(
NotificationCenter.default.publisher(for: NSApplication.willResignActiveNotification),
perform: { _ in f() }
)
}
func onForeground(_ f: @escaping () -> Void) -> some View {
self.onReceive(
NotificationCenter.default.publisher(for: NSApplication.didBecomeActiveNotification),
perform: { _ in f() }
)
}
#endif
}
As expected, I use it as such:
AppView()
.onBackground {
print("my background")
}
.onForeground {
print("my foreground")
}
Use inside scene root view (usually ContentView
)
Tested with Xcode 12 / iOS 14 as worked.
struct ContentView: View {
@Environment(\.scenePhase) private var scenePhase
var body: some View {
TestView()
.onChange(of: scenePhase) { phase in
switch phase {
case .active:
print(">> your code is here on scene become active")
case .inactive:
print(">> your code is here on scene become inactive")
case .background:
print(">> your code is here on scene go background")
default:
print(">> do something else in future")
}
}
}
}