The first thing I installed after the WWDC25 Keynote was the beta for iPadOS. There was only one reason: it had the windows we have all wanted for so long.
And generally, windows on iPad work exactly how we want them to.
But there’s a problem, and I suspect that the root cause is that Apple engineers are thinking more about how the iPhone has worked for the past 18 years rather than how the Mac has worked for the past 41 years.
From the very beginning, iOS has had a notion of an app being in the foreground or background. When you saw an app on screen it was active and when it was gone it was inactive. The operating system let you know when that state changed and developers used it for all kinds of things:
- Saving the state of the app. For example, if you are in the middle of editing some text that is only in memory, the data gets written to local storage because there is no guarantee that your app stays in memory. No one likes losing several paragraphs of typing because they switched to Safari and loaded a heavyweight page.
- Syncing state between devices. Apps like Tapestry and Ivory do this with the reading position so you can switch between devices seamlessly.
- Exchanging data with a server. To make apps more responsive, developers often queue up work to be performed after you leave the app. This work can be done at a lower priority in the background.
It was simple system that let you do what you needed to do, when you needed to do it. Now with windows on iPadOS, that’s gotten a lot harder.
That’s because apps stay active even when their windows do not.
If you’re using iPadOS 26 and noticing that the saving/syncing/exchange of data is not happening, there’s a stupid trick you need to do to get things working:
Tap on the home screen to hide the windows (they slide off to the sides of the display). That makes all the apps on screen inactive and triggers the work that they need to do.
Of course, that’s a completely unintuitive action, hard to remember, and generally a pain in the butt. Especially when you’re on an iPad Pro with a lot of screen real estate and have several apps working together nicely.
(Note that this “hide to sync” issue is also a problem when you’re running iOS/iPadOS apps on your Mac: you have to hide a window to make it inactive. It breaks Tapestry.)
There is an API in iPadOS to track the state of each window: it has an “active appearance” that tells you when the window has focus. Unfortunately, on older versions of the OS, nothing is reported for this state, so backward compatibility is a problem. Also, on iOS 26, the active/inactive window state changes unpredictably while an app is off screen: my suspicion there is that the OS is taking screenshots to use in the App Switcher.
It’s taken several years for folks at Apple to arrive at a solution that the Mac had long ago, and I think it’s time for them to re-evaluate the notion of what makes an app “active”.
On macOS, there two things that can be active: the application itself or one of its windows. An app is active if it’s been launched and has at least one active window. A window is active if it’s frontmost on screen.
There is a clear distinction between the overall activity and the content-specific activity. If there is some global data that needs attention, you work with it when the app becomes active. If a window has some document data, you know to update it when the active state changes.
iOS and iPadOS need that same clear distinction.
For any Apple folks reading, take a look at FB18443571. It shows how I worked my way through this problem and came to the conclusion above. I’m happy to talk more about this problem and any potential solutions.