Overview
crash stack
#0 at 0x1d910a3a4
Thread 0 Crashed
0 libsystem_kernel.dylib nil
1 libsystem_kernel.dylib nil
2 libsystem_c.dylib _os_crash_msg
3 UIKitCore _UIResponderForwarderWantsForwardingFromResponder
4 UIKitCore __forwardTouchMethod_block_invoke
5 CoreFoundation __NSSET_IS_CALLING_OUT_TO_A_BLOCK__
6 CoreFoundation -[__NSSetM enumerateObjectsWithOptions:usingBlock:]
7 UIKitCore forwardTouchMethod
8 UIKitCore -[UIWindow _sendTouchesForEvent:]
9 UIKitCore -[UIWindow sendEvent:]
10 UIKitCore -[UIApplication sendEvent:]
11 Eax-AppStore EaxApplication.sendEvent(UIEvent)(Application.swift:16)
11 Eax-AppStore @objc EaxApplication.sendEvent(UIEvent)(<compiler-generated>:14)
12 UIKitCore __dispatchPreprocessedEventFromEventQueue
13 UIKitCore __processEventQueue
14 UIKitCore updateCycleEntry
15 UIKitCore _UIUpdateSequenceRun
16 UIKitCore schedulerStepScheduledMainSection
17 UIKitCore runloopSourceCallback
18 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
19 CoreFoundation __CFRunLoopDoSource0
20 CoreFoundation __CFRunLoopDoSources0
21 CoreFoundation __CFRunLoopRun
22 CoreFoundation CFRunLoopRunSpecific
23 GraphicsServices GSEventRunModal
24 UIKitCore -[UIApplication _run]
25 UIKitCore UIApplicationMain
26 Eax-AppStore main(main.swift:11)
27 unknown nil
scenario: page that contains keyboard
os version: 16.5.1
[[Application.swift:16 EaxApplication.sendEvent(UIEvent)]]
![](https://img.haomeiwen.com/i8092146/af295155e44ae372.png)
![](https://img.haomeiwen.com/i8092146/a0d701d5c6df1a5a.png)
Clue
System keyboard: no crash
Third party keyboard: crash
![](https://img.haomeiwen.com/i8092146/4c0c6431f2d16565.png)
- For iOS >= 9 third party keyboard will visible on UIRemoteKeyboardWindow window (UIRemoteKeyboardWindow is above all others window)
![](https://img.haomeiwen.com/i8092146/8a1d5aaa5551246e.png)
-
touch event is sent to **UIRemoteKeyboardWindow **when third party keyboard just raise. Crash will happen when (multiple?) event sent to UIRemoteKeyboardWindow.
-
After keyboard raised, touch event is sent to **UIRemoteKeyboardWindow **without crash
![](https://img.haomeiwen.com/i8092146/a9026112f19a84b9.png)
Recap: Crash happen only when third party keyboard receive (multiple?) event when it is about raise.
Suspect
UIRemoteKeyboardWindowreceive event when keyboard is about raise
Solution
- Block **UIRemoteKeyboardWindow **event chain
class EaxApplication: UIApplication {
override func sendEvent(_ event: UIEvent) {
if EaxABTestKey.shared.ENABLE_KEYBOARD_PROTECTION.isB() {
guard canResponseToEvent(event) else { return }
}
sendNotificationToTTIModuleWhenFirstTouchIsFired(event)
super.sendEvent(event)
}
override func sendEvent(_ event: UIEvent) {
if EaxABTestKey.shared.ENABLE_KEYBOARD_PROTECTION.isB() {
guard canResponseToEvent(event) else { return }
}
sendNotificationToTTIModuleWhenFirstTouchIsFired(event)
super.sendEvent(event)
}
private func sendNotificationToTTIModuleWhenFirstTouchIsFired(_ event: UIEvent) {
guard TTILogCore.defaultCenter.activated, event.type == .touches else { return }
TTILogCenter.submitLog()
}
func canResponseToEvent(_ event: UIEvent) -> Bool {
if UIDevice.current.systemVersion == "16.5.1" {
if event.type == .touches {
let allTouches: [UITouch] = Array(event.allTouches ?? [])
for touch in allTouches {
let windowName = String(describing: touch.window.self)
if windowName.contains("UIRemoteKeyboardWindow") {
guard canResponseToWindow(touch.window) else { return false }
}
}
}
}
self.lastResponseDate = Date()
return true
}
// Block UIRemoteKeyboardWindow event chain
func canResponseToWindow(_ window: UIWindow?) -> Bool {
guard Date().timeIntervalSince(lastResponseDate) >= timerInterval else {
return false
}
return true
}
}
- Block with timer interval for UIRemoteKeyboardWindow
class EaxApplication: UIApplication {
override func sendEvent(_ event: UIEvent) {
if EaxABTestKey.shared.ENABLE_KEYBOARD_PROTECTION.isB() {
guard canResponseToEvent(event) else { return }
}
sendNotificationToTTIModuleWhenFirstTouchIsFired(event)
super.sendEvent(event)
}
override func sendEvent(_ event: UIEvent) {
if EaxABTestKey.shared.ENABLE_KEYBOARD_PROTECTION.isB() {
guard canResponseToEvent(event) else { return }
}
sendNotificationToTTIModuleWhenFirstTouchIsFired(event)
super.sendEvent(event)
}
private func sendNotificationToTTIModuleWhenFirstTouchIsFired(_ event: UIEvent) {
guard TTILogCore.defaultCenter.activated, event.type == .touches else { return }
TTILogCenter.submitLog()
}
func canResponseToEvent(_ event: UIEvent) -> Bool {
if UIDevice.current.systemVersion == "16.5.1" {
if event.type == .touches {
let allTouches: [UITouch] = Array(event.allTouches ?? [])
for touch in allTouches {
let windowName = String(describing: touch.window.self)
if windowName.contains("UIRemoteKeyboardWindow") {
guard canResponseToWindow(touch.window) else { return false }
}
}
}
}
self.lastResponseDate = Date()
return true
}
// Block with timer interval for UIRemoteKeyboardWindow
func canResponseToWindow(_ window: UIWindow?) -> Bool {
if let currentWindow = currentWindow,
currentWindow == window {
return true
} else {
// key point: block event for UIRemoteKeyboardWindow for a period time
currentWindow = window
guard Date().timeIntervalSince(lastResponseDate) >= timerInterval else {
return false
}
return true
}
}
}
UIRemoteKeyboardWindow Response Arear
![](https://img.haomeiwen.com/i8092146/5dddb2f62b261704.png)
![](https://img.haomeiwen.com/i8092146/84ea8c95632b4f08.png)
When a new event is ready, we should check does this event belongs to UIRemoteKeyboardWindow and time interval is too shot to response.
![](https://img.haomeiwen.com/i8092146/9bfb2b517cb66f0a.png)
Increase the time interval for different UIRemoteKeyboardWindow instance calls
网友评论