在不调用私有 api 的情况下，如何禁止一个一个 window 变成 keyWindow，以下是一种方案

ripperhe
2018-09-13T12:13:49Z

ZYSuspensionContainer.h

| #import <UIKit/UIKit.h>
|
| @interface ZYSuspensionContainer : UIWindow
|
| @property (nonatomic, weak) UIWindow *oldOldKeyWindow;
| @property (nonatomic, weak) UIWindow *oldKeyWindow;
|
| @end

ZYSuspensionContainer.m

| #import "ZYSuspensionContainer.h"
|
| @implementation ZYSuspensionContainer
| - (void)makeKeyWindow
| {
| // 记录当前的 keyWindow
| if (self.oldKeyWindow) {
| self.oldOldKeyWindow = self.oldKeyWindow;
| }else{
| self.oldOldKeyWindow = nil;
| }
|
| self.oldKeyWindow = [UIApplication sharedApplication].keyWindow;
|
| [super makeKeyWindow];
| }
|
| - (void)becomeKeyWindow
| {
| [super becomeKeyWindow];
|
| /**
| 1. makeKeyAndVisible 方法会调用 makeKeyWindow
| 2. keyWindow hidden=YES 的时候，会找 windows 最后一个 window，设置为 keyWindow，所以也会调用 makeKeyWindow
|
| makeKeyWindow 内部会调用 becomeKeyWindow；调用父类 makeKeyWindow 之前，self 还没有变成 keyWindow
| becomeKeyWindow 调用的时候，self 已经变成了 keyWindow
| */
|
|
| if (!self.oldKeyWindow) {
| // oldKeyWindow 都没有，那我是第一个 window，也是唯一一个 window，直接返回
| return;
| }
|
| if ([self.oldKeyWindow isKindOfClass:[self class]]) {
| // 从 self 这种类型过来，那不处理了，应该所有 window 都是这种类型
| return;
| }
|
| if (self.oldOldKeyWindow == self.oldKeyWindow) {
| // 这家伙反复设置 keyWindow 给 self，以免循环设置，直接将 keyWindow 设置给 appdelegate window
| [[UIApplication sharedApplication].delegate.window makeKeyWindow];
| return;
| }
|
| if (self.oldKeyWindow.isHidden == NO) {
| // 原来的 keyWindow 没有隐藏，并且不是 self 这种类型，直接将 keyWindow 设置回它
| [self.oldKeyWindow makeKeyWindow];
| return;
| }
|
| // self.oldKeyWindow.isHidden == YES 这家伙隐藏了，那看来我得找一个除开它之外的合适的 window
| UIWindow *targetWindow = nil;
| NSArray <UIWindow *>*windows = [UIApplication sharedApplication].windows;
| for (UIWindow *window in windows.reverseObjectEnumerator) {
| if ([window isKindOfClass:[self class]]) {
| // 本类型 跳过
| continue;
| }
| if (window.hidden == YES || window.opaque == NO) {
| // 隐藏的 或者 透明的 跳过
| continue;
| }
| if (CGRectEqualToRect(window.bounds, [UIScreen mainScreen].bounds) == NO) {
| // 不是全屏的 跳过
| continue;
| }
| targetWindow = window;
| break;
| }
|
| if (targetWindow) {
| [targetWindow makeKeyWindow];
| }
| }
|
| @end