1.坑從何處來?
? ? ? ?很多APP都有截屏分享的功能,在某個詳情頁按下截屏鍵,將當前頁面繪制成UIImage,再貼上一個二維碼。通過微信/微博/QQ之類的渠道分享出去。很常見,對吧?
? ? ? ?但是有用戶反映二維碼尺寸太小,URL太長以至于生成的二維碼太密集,導致識別率不高。于是產品狗提出了解決方案:1.二維碼尺寸放大。2.將原本的URL壓縮成短鏈接。
? ? ? ?放大二維碼so easy,這里就略過了。而第二步壓縮長鏈接需要走后臺的接口。于是乎新的截屏分享流程如下:
? ? ? ?1.出發(fā)截屏操作
? ? ? ?2.將現有的長鏈接通過后臺接口變換成短鏈接
? ? ? ?3.成功返回短鏈接則用短鏈接生成二維碼
? ? ? ?4.返回短鏈接失敗則繼續(xù)用原來的長鏈接生成二維碼(此處有坑?。?/p>
? ? ? ?這個流程看起來沒什么毛病,但是沒過多久就有人反饋了bug。。。
2.問題重現
昨天下午被叫過去,看到了如下一張圖,

看到此圖,我一臉懵逼,這特么是個啥,為了方便說明,正常情況應該是類似于這樣

? ? ? ?這種截圖分享的方式相信大家實現的方法大同小異,截取當前屏幕的內容生成UIImage,然后放到一個UIImageView里,然后根據URL生成二維碼,再add到這個UIImageView上,最后繪制為一個有二維碼的UIImage。新建一個UIWindow來展示這個彈出的浮層?;揪秃蜕厦嬉粯恿恕?/p>
? ? ? ?我最無法理解的是,明明截屏的內容和二維碼是在一張圖上,為啥后面截屏的內容沒了,就剩個碼,而且下面分享button也不見了。。。詢問發(fā)現bug的人,只說了截屏發(fā)微信亂點點再切回來就成這樣了,而且還卡死了,只能殺掉APP。終于在昨天深夜,有大佬找到了穩(wěn)定復現的方法:打開飛行模式,進入詳情頁,在內容沒有加載好的時候立刻截屏退到后臺,過一會再回到前臺就這樣了。
? ? ? ?有了穩(wěn)定復現的方法,就可以開始debug了!
3.定位原因
? ? ? ?我按照步驟開始重現問題,關鍵點就在于網絡請求超時后,依然繼續(xù)走了后續(xù)的流程,導致APP還在后臺的時候,彈出了新的window。我就重點跟蹤了這個window的創(chuàng)建過程!
+ (UIWindow *)sharedWindow{ ? ?
????????static UIWindow *sharedWindow = nil; ? ?
????????static dispatch_once_t onceToken; ? ?
????????dispatch_once(&onceToken, ^{ ? ? ? ?
????????????????sharedWindow = [[UIWindow alloc] initWithFrame:[[[UIApplication sharedApplication] keyWindow] bounds]]; ? ?
????????}); ? ?
????????return sharedWindow;
}

? ? ? ?重點在于keywindow上,因為此時APP在后臺,po出來可以看到keywindow是nil,所以[[[UIApplication sharedApplication] keyWindow] bounds]取出來的frame是{0,0,0,0}。所以新彈出的window才不能響應任何手勢,顯得APP像是卡死了一樣。
? ? ? ?于是我就想,那我換一種取frame的方式:[UIScreen mainScreen].bounds,這會怎么樣呢?這次得到了下面的樣子:

? ? ? ?因為獲取到了正常的frame,彈出的window看起來稍微有點正常了,黑屏不是就是因為APP在后臺,所以獲取不到任何屏幕上的信息,繪制出來自然就是一團黑,這是在預料之內的。而且此時新彈出的window也能正常響應手勢了。點擊空白了新彈出的window消失了,但此時有了另一個問題,APP的主window不見了,所以又卡死了。。當然主window消失就是另一個問題了,這里就不展開說了。
4.總結
? ? ? ?發(fā)現了問題所在,解決起來也就有很多方法了。
? ? ? ?回想一下造成這個bug的根本原因就是[[UIApplication sharedApplication] keyWindow]是nil,所以截屏獲取不到內容,彈出的window的frame為0。
? ?????APP在后臺獲取不到keyWindow!
? ?????APP在后臺獲取不到keyWindow!
? ?????APP在后臺獲取不到keyWindow!