問題描述:
現(xiàn)在的App里一共有2個UIWindow,一個是加載Tabbar的Window,一個是懸浮播放器的Window咽瓷。 像Loading這種視圖默認是加載在 UIApplication.shared.keyWindow
上的。
但在升級到iOS14.x后出現(xiàn)了一個問題绑蔫。
當點擊懸浮播放器的Window時柄驻,App的KeyWindow會自動變成懸浮播放器的Window胁出。
這個時候再去添加Loading到KeyWindow上就會出現(xiàn)視圖錯亂的Bug。
明明在iOS14以前都是好的忆家,為什么在iOS14.5的系統(tǒng)就會出現(xiàn)這個問題犹菇。
探究過程:
方案一:
首先想到的就是通過runtime Hook
的方式去監(jiān)聽 UIApplication.shared.keyWindow
的Set方法,來確定改變時機芽卿。
但KeyWindow屬性在UIKit中標記為{ get }
. 故方案不可取揭芍。?
方案二:
通過Symbolic BreakPoint [符號斷點]
來查看其方法調(diào)用堆棧。
那就讓我們開始吧~
首先通過斷點工具查看 UIApplication.shared.keyWindow
的具體實現(xiàn)卸例。
其實是調(diào)用了UIWindow 的 KeyWindow 方法称杨。
然后 通過反編譯來獲取 UIWindow的KeyWindow方法具體實現(xiàn)流酬,發(fā)現(xiàn)無法獲取方法的具體實現(xiàn)。
這個時候就通過classdump獲取UIWindow類的所有方法列另,逐個查閱, 找出可能有關系的方法芽腾。
再通過斷點找出對應堆棧。
具體UIKit的class dump網(wǎng)上已經(jīng)有很多人做了页衙,這里提供一個現(xiàn)成的UIWindow.h的頭文件內(nèi)容摊滔。
在全局搜索了所有關于Keywindow的方法后,
- (void)_makeKeyWindowIgnoringOldKeyWindow:(BOOL)arg1;
這個方法的可能性最強店乐。
在Xcode中繼續(xù)打一個symbolic 斷點艰躺。用來監(jiān)聽[UIWindow _makeKeyWindowIgnoringOldKeyWindow:]
的調(diào)用。
在iOS14.5的手機上當點擊新的窗口時,會觸發(fā)斷點眨八。
而在iOS13.6的系統(tǒng)上腺兴。斷點不會觸發(fā)。
這也證實了筆者的猜測廉侧。
那么是為什么在點擊新的Window上時會觸發(fā)Window改變呢页响?
通過查看方法調(diào)用順序,發(fā)現(xiàn)是[_UIRemoteKeyboards peekApplicationEvent:]
觸發(fā)了KeyWindow的改變段誊。
我們再看看[_UIRemoteKeyboards peekApplicationEvent:]
做了些什么闰蚕, 原來在其方法內(nèi)部調(diào)用了更新KeyWindow的方法。
結論:
在iOS14.x后點擊新創(chuàng)建的Window KeyWindow會切換连舍,主要是蘋果在iOS14.x后修改了UIKit的底層實現(xiàn)没陡。
在iOS14.x版本后點擊Window觸發(fā)的[_UIRemoteKeyboards peekApplicationEvent:]
會調(diào)用[UIWindow _makeKeyWindowIgnoringOldKeyWindow:]
來更新KeyWindow.
而在iOS14.x之前也會觸發(fā)[_UIRemoteKeyboards peekApplicationEvent:]
方法,但不會調(diào)用[UIWindow _makeKeyWindowIgnoringOldKeyWindow:]
來更新KeyWindow索赏。