iOS14.2中當(dāng)點(diǎn)擊新創(chuàng)建的Window時(shí)KeyWindow改變問(wèn)題探究

問(wèn)題描述:

現(xiàn)在的App里一共有2個(gè)UIWindow,一個(gè)是加載Tabbar的Window,一個(gè)是懸浮播放器的Window。 像Loading這種視圖默認(rèn)是加載在 UIApplication.shared.keyWindow上的。

但在升級(jí)到iOS14.x后出現(xiàn)了一個(gè)問(wèn)題。
當(dāng)點(diǎn)擊懸浮播放器的Window時(shí),App的KeyWindow會(huì)自動(dòng)變成懸浮播放器的Window。
這個(gè)時(shí)候再去添加Loading到KeyWindow上就會(huì)出現(xiàn)視圖錯(cuò)亂的Bug。

明明在iOS14以前都是好的,為什么在iOS14.5的系統(tǒng)就會(huì)出現(xiàn)這個(gè)問(wèn)題。

探究過(guò)程:

方案一:

首先想到的就是通過(guò)runtime Hook的方式去監(jiān)聽(tīng) UIApplication.shared.keyWindow的Set方法,來(lái)確定改變時(shí)機(jī)。
但KeyWindow屬性在UIKit中標(biāo)記為{ get }. 故方案不可取。?

image.png

方案二:

通過(guò)Symbolic BreakPoint [符號(hào)斷點(diǎn)]來(lái)查看其方法調(diào)用堆棧。

image.png

那就讓我們開(kāi)始吧~

首先通過(guò)斷點(diǎn)工具查看 UIApplication.shared.keyWindow的具體實(shí)現(xiàn)。

image.png

其實(shí)是調(diào)用了UIWindow 的 KeyWindow 方法。
然后 通過(guò)反編譯來(lái)獲取 UIWindow的KeyWindow方法具體實(shí)現(xiàn),發(fā)現(xiàn)無(wú)法獲取方法的具體實(shí)現(xiàn)。

這個(gè)時(shí)候就通過(guò)classdump獲取UIWindow類(lèi)的所有方法,逐個(gè)查閱, 找出可能有關(guān)系的方法。
再通過(guò)斷點(diǎn)找出對(duì)應(yīng)堆棧。

具體UIKit的class dump網(wǎng)上已經(jīng)有很多人做了,這里提供一個(gè)現(xiàn)成的UIWindow.h的頭文件內(nèi)容。

在全局搜索了所有關(guān)于Keywindow的方法后,


image.png
- (void)_makeKeyWindowIgnoringOldKeyWindow:(BOOL)arg1;

這個(gè)方法的可能性最強(qiáng)。

在Xcode中繼續(xù)打一個(gè)symbolic 斷點(diǎn)。用來(lái)監(jiān)聽(tīng)[UIWindow _makeKeyWindowIgnoringOldKeyWindow:]的調(diào)用。

image.png

在iOS14.5的手機(jī)上當(dāng)點(diǎn)擊新的窗口時(shí),會(huì)觸發(fā)斷點(diǎn)。
而在iOS13.6的系統(tǒng)上。斷點(diǎn)不會(huì)觸發(fā)。

這也證實(shí)了筆者的猜測(cè)。

image.png

那么是為什么在點(diǎn)擊新的Window上時(shí)會(huì)觸發(fā)Window改變呢?
通過(guò)查看方法調(diào)用順序,發(fā)現(xiàn)是[_UIRemoteKeyboards peekApplicationEvent:]觸發(fā)了KeyWindow的改變。

image.png

我們?cè)倏纯?code>[_UIRemoteKeyboards peekApplicationEvent:] 做了些什么, 原來(lái)在其方法內(nèi)部調(diào)用了更新KeyWindow的方法。

image.png

結(jié)論:

在iOS14.x后點(diǎn)擊新創(chuàng)建的Window KeyWindow會(huì)切換,主要是蘋(píng)果在iOS14.x后修改了UIKit的底層實(shí)現(xiàn)。 在iOS14.x版本后點(diǎn)擊Window觸發(fā)的[_UIRemoteKeyboards peekApplicationEvent:]會(huì)調(diào)用[UIWindow _makeKeyWindowIgnoringOldKeyWindow:]來(lái)更新KeyWindow.

而在iOS14.x之前也會(huì)觸發(fā)[_UIRemoteKeyboards peekApplicationEvent:]方法,但不會(huì)調(diào)用[UIWindow _makeKeyWindowIgnoringOldKeyWindow:]來(lái)更新KeyWindow。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容