Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: make getTopWindow more robust #621

Conversation

thespacemanatee
Copy link
Contributor

@thespacemanatee thespacemanatee commented Oct 8, 2024

📜 Description

This PR updates the top window retrieval method:

Old: UIApplication.shared.windows.last (deprecated in iOS 15+)
New: UIWindowScene-based approach

Differences:

  • UIApplication.shared.windows.last:
    • It accesses all windows associated with the application.
    • The last window in this array isn't always the topmost or key window, especially in more complex app setups.
    • This approach is deprecated as of iOS 15, though it still works in many cases.
  • UIWindowScene:
    • Iterates through all connected scenes to find the active foreground scene
    • Ensures selection of the correct key window in multi-window environments (e.g., Split View in iPadOS)
    • Provides more reliable behaviour in complex app configurations that utilize multiple UIWindowScenes

💡 Motivation and Context

Closes #618

In our case, this change was required to get the children of the OverKeyboardView to show. Without it, they were still rendered, but invisible. This change should enhance the reliability across different iOS versions and device types.

📢 Changelog

iOS

  • Get the last key window in the current UIWindowScene as opposed to the last window of all windows associated with the app

🤔 How Has This Been Tested?

It works on my company project. Did not manage to get the example app to compile on my machine. Could be due to the (lack of) provisioning profiles.

📝 Checklist

  • CI successfully passed
  • I added new mocks and corresponding unit-tests if library API was changed

@thespacemanatee thespacemanatee force-pushed the thespacemanatee/robust-get-top-window branch from d141c25 to 7b919e7 Compare October 8, 2024 17:07
@kirillzyusko kirillzyusko self-assigned this Oct 8, 2024
@kirillzyusko kirillzyusko added 🍎 iOS iOS specific OverKeyboardView Anything related to OverKeyboardView labels Oct 8, 2024
Comment on lines 45 to 56
if #available(iOS 13.0, *) {
for scene in UIApplication.shared.connectedScenes {
if scene.activationState == .foregroundActive,
let windowScene = scene as? UIWindowScene,
let keyWindow = windowScene.windows.first(where: { $0.isKeyWindow }) {
return keyWindow
}
}
return nil
} else {
return UIApplication.shared.windows.last { $0.isKeyWindow }
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes looks good to me, but may I ask you to slightly re-work this part?

I would like to have this code somewhere isolated, because potentially we may want to get an access to main window in future, so I would move this code to an extension:

extension UIApplication {
    var activeWindow: UIWindow? {
        if #available(iOS 13.0, *) {
            for scene in connectedScenes {
                if scene.activationState == .foregroundActive,
                   let windowScene = scene as? UIWindowScene,
                   let keyWindow = windowScene.windows.first(where: { $0.isKeyWindow }) {
                    return keyWindow
                }
            }
            return nil
        } else {
            return windows.last { $0.isKeyWindow }
        }
    }
}

And then use it like:

return keyboardWindow ?? UIApplication.shared.activeWindow

Not sure if this code works - just wanted to show the idea. Hope you can test these modifications in your project 👀

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will try and let you know!

Copy link
Contributor Author

@thespacemanatee thespacemanatee Oct 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kirillzyusko Looks like it functionally works the same, but I found a new issue that I'm not sure if is the result of this PR, or also present in the existing code.

In my app, I have routes guarded behind an auth check, and the Screens rendered in the Navigator change based on the auth state. When I open the OverKeyboardView for the first time, it works, and navigation events such as push can be done and OverKeyboardView still works. But if the user logs out, the Screens are remounted and the next time I try to open this OverKeyboardView, the children become invisible again.

Do you think this PR should be put on hold until I figure out the fix for that as well?

EDIT: I would like to know if you can reproduce this as well, by adding more complicated routes to the example if you have the time 🙏

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, sad to hear that it still has issues 😔

Would you mind to submit a new issues and describe hte problem? Just want to track it somewhere so that I know that I'll not forget about the problem and will return to it :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kirillzyusko let me create an issue when I get some time this week! Thanks man

@kirillzyusko
Copy link
Owner

And yeah, if possible, please fix swiftlint and swiftformat jobs 👀

I think running swiftformat should be enough and swiftlint should be fixed automatically

@thespacemanatee thespacemanatee force-pushed the thespacemanatee/robust-get-top-window branch from 7b919e7 to e2f7733 Compare October 8, 2024 18:19
return windows.last { $0.isKeyWindow }
}
}

static func topViewController(
base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kirillzyusko Xcode also complains about using UIApplication.shared.keyWindow, I haven't tested it yet but replacing this with the activeWindow extension removes the warning and should achieve the same thing.

Screenshot 2024-10-09 at 2 19 47 AM

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes @thespacemanatee I'm also constantly getting these warnings 🙈

I would split changes in two parts anyway 🙃 Like merge these changes and then open a second PR that will repace a single line.

In this case it'll be easier to manage 😊

@kirillzyusko kirillzyusko merged commit a259792 into kirillzyusko:main Oct 8, 2024
15 of 16 checks passed
@kirillzyusko
Copy link
Owner

Merged @thespacemanatee 🙌

Would you mind to submit a PR that we discussed here?

@kirillzyusko kirillzyusko mentioned this pull request Oct 14, 2024
2 tasks
kirillzyusko added a commit that referenced this pull request Oct 14, 2024
## 📜 Description

Replaced the usage of deprecated `keyWindow` with our `activeWindow`
extension (which is not depecated).

## 💡 Motivation and Context

We shouldn't rely on deprecated syntax.

In
#621
we added `.activeWindow` extension which represents a better alternative
to `.keyWindow`.

So I thought it would be better to not use deprecated syntax anymore and
use new extension.

## 📢 Changelog

<!-- High level overview of important changes -->
<!-- For example: fixed status bar manipulation; added new types
declarations; -->
<!-- If your changes don't affect one of platform/language below - then
remove this platform/language -->

### iOS

- replace `.keyWindow` with `.activeWindow`;

## 🤔 How Has This Been Tested?

Tested manually on CI (e2e tests).

## 📸 Screenshots (if appropriate):

|Before|After|
|------|------|
|<img width="1709" alt="image"
src="https://github.com/user-attachments/assets/5e7bfe97-ad64-4871-8d0e-3405034f1eb6">|<img
width="1741" alt="image"
src="https://github.com/user-attachments/assets/298c1e4e-d499-48a3-990d-2c1c0e21b699">|

## 📝 Checklist

- [x] CI successfully passed
- [x] I added new mocks and corresponding unit-tests if library API was
changed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🍎 iOS iOS specific OverKeyboardView Anything related to OverKeyboardView
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[iOS] OverKeyboardView does not work when the keyboard is not active
2 participants