App Crash in GameController when accessing GCKeyboard.coalesced on iPad

We are developing a hybrid iOS app where Angular content is rendered inside a WKWebView, hosted by a native Swift application.

We use the GameController framework to detect whether an external Bluetooth keyboard is connected to an iPad. The following code is executed when the app enters the foreground and also when requested by the web layer:

    func keyboardStatusHandler(){
        let isKeyboardConnected = GCKeyboard.coalesced != nil
        if(!isKeyboardConnected){
            //sent status to Angular
        } else {
            //sent status to Angular
        }
    }

Crash details

We are seeing intermittent crashes on iPad with the following stack trace:

Crashed: GCDeviceSession.HID
0  libobjc.A.dylib                0x7db8 objc_retain_x8 + 16
1  libsystem_blocks.dylib         0xfb8 void HelperBase<ExtendedInline>::copyCapture<(HelperBase<ExtendedInline>::BlockCaptureKind)3>(unsigned int) + 48
2  libsystem_blocks.dylib         0xbc4 HelperBase<GenericInline>::copyBlock(Block_layout*, Block_layout*) + 108
3  libsystem_blocks.dylib         0xc94 _call_copy_helpers_excp + 60
4  libsystem_blocks.dylib         0xef8 _Block_copy + 412
5  libdispatch.dylib              0x1a70 _dispatch_Block_copy + 32
6  libdispatch.dylib              0x792c dispatch_async + 56
7  libdispatch.dylib              0x792c dispatch_channel_async + 56
8  GameController                 0xea6dc -[GCKeyboardInput _handleKeyboardEvent:] + 324
9  GameController                 0x22508 __53-[_GCKeyboardEventHIDAdapter initWithSource:service:]_block_invoke + 376
10 GameController                 0x11d30 -[_GCHIDEventSubject publishHIDEvent:] + 268
11 GameController                 0xb79cc __40-[_GCHIDEventUIKitClient initWithQueue:]_block_invoke_3 + 44
12 libdispatch.dylib              0x1b584 _dispatch_client_callout + 16
13 libdispatch.dylib              0x12088 _dispatch_async_and_wait_invoke_and_complete_recurse + 272
14 libdispatch.dylib              0x8448 _dispatch_async_and_wait_f + 108
15 GameController                 0xb7984 __40-[_GCHIDEventUIKitClient initWithQueue:]_block_invoke_2 + 132
16 GameController                 0xb746c __48-[__GCHIDEventUIKitClient _initWithApplication:]_block_invoke + 256
17 UIKitCore                      0x11fd394 __61-[UIEventFetcher _setHIDGameControllerEventObserver:onQueue:]_block_invoke_3 + 40
18 libdispatch.dylib              0x1aac _dispatch_call_block_and_release + 32
19 libdispatch.dylib              0x1b584 _dispatch_client_callout + 16
20 libdispatch.dylib              0xa2d0 _dispatch_lane_serial_drain + 740
21 libdispatch.dylib              0xadac _dispatch_lane_invoke + 388
22 libdispatch.dylib              0x151dc _dispatch_root_queue_drain_deferred_wlh + 292
23 libdispatch.dylib              0x14a60 _dispatch_workloop_worker_thread + 540
24 libsystem_pthread.dylib        0xa0c _pthread_wqthread + 292
25 libsystem_pthread.dylib        0xaac start_wqthread + 8

Observed scenarios

  • Crash occurs when the app transitions from background to foreground
  • Crash also occurs when the Angular layer requests keyboard status, triggering the same code path

Questions

  • Has anyone encountered crashes related to GCKeyboard.coalesced or GCKeyboardInput like this?
  • Are there known issues with the GameController framework when querying keyboard state during app lifecycle transitions?
  • Is there a recommended or safer way to detect external keyboard connection status on iPad (especially when using WKWebView)?

Any insights, known platform issues, or suggested workarounds would be greatly appreciated.

Thanks!

Hello

Can you post the full, symbolicated crash report? Is the above code snippet your code's only interaction with GCKeyboard?

-- Justin

Hello Justin,

Thank you for your reply!!.

when i look at the full crash report, in the com.apple.main-thread there is a [_UIKeyboardStateManager updateDelegatePasteSupport] line.

i attached the whole crash report to the message.

Your help and suggestions would be greatly appreciated.!

Hello

Thank you for sharing the crash report. It appears either your custom crash reporter did not capture the iOS version where the crash occurred, or the iOS version information was redacted before you posted the report.

If you can obtain a crash report generated by the Apple crash reporter, that crash report will have the iOS version information. See Posting a Crash Report. Otherwise, can you share the latest iOS version that you have encountered this crash occur on?

Would you also answer my other question above:

Is the snippet in your original post your code's only interaction with the GCKeyboard API?

-- Justin

Hello,

I'm sorry, i forgot to mentioned the iPad OS version in the initial post. Crash happen in iPad OS is 18.6.2 tablet.

Is the snippet in your original post your code's only interaction with the GCKeyboard API?

To this question , Yes this is the only function that called GCKeyboard, For the places we called "keyboardStatusHandler()" function is like below,

  • In the Scenedelgate , inside sceneDidBecomeActive(_:)
  • Via a NotificationCenter observer registered in the view controller, triggered when the keyboard is shown:
        NotificationCenter.default.addObserver(self, selector: #selector(XXXXX), name: UIResponder.keyboardWillShowNotification,object: nil)

Hello

I put together a small code example to test the scenario described in your original post.

import UIKit
import GameController

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        keyboardStatusHandler()
        NotificationCenter.default.addObserver(self, selector: #selector(keyboard(willShow:)), name: UIResponder.keyboardWillShowNotification,object: nil)
        
        return true
    }
    
    @objc func keyboard(willShow notification: Notification) {
        keyboardStatusHandler()
    }
    
    func keyboardStatusHandler(){
        let isKeyboardConnected = GCKeyboard.coalesced != nil
        if(!isKeyboardConnected){
            NSLog("Keyboard is not connected")
        } else {
            NSLog("Keyboard is connected")
        }
    }
}

Running this app on an iPad with iOS 18.6.2 and keyboard connected, I do not encounter any crash when repeatedly backgrounding & foregrounding the application while typing on the keyboard.

I suspect there is more app-specific code involved that is contributing to this crash.

Since the crash log points to a memory issue, have you attempted to:

  1. Replicate the crash while the Address Sanitizer is enabled for your process?
  2. Replicate the crash while profiling your application with the Zombies Instrument?

I suggest starting with (2). If you are able to capture a Zombies trace of the crash, you can attach it to a feedback report submitted for the Game Controllers feedback area so that I may analyze it.

-- Justin

Hello,

Thank you for the suggestions!!. Below is a simplified structure of our current implementation,

SceneDelegate.swift

import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate, UIApplicationDelegate {

var viewController:ViewController!

  func sceneDidBecomeActive(_ scene: UIScene) {
    viewController.keyboardStatusHandler()
  }
}

ViewController.swift

import UIKit
import Foundation
import GameController

class ViewController: UIViewController, WKUIDelegate, UINavigationControllerDelegate, AVAudioPlayerDelegate, WKNavigationDelegate, ConnectWebViewDelegate{
  override func viewDidLoad() {
        super.viewDidLoad()
       //other code
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
    }

    @objc func keyboardWillShow(_ notification: NSNotification) {
        self.keyboardStatusHandler()
    }
    func keyboardStatusHandler(){
        let isKeyboardConnected = GCKeyboard.coalesced != nil
        if(!isKeyboardConnected){
          //use webView.evaluateJavaScript to send result to Angular
        } else {
            //use webView.evaluateJavaScript to send result to Angular
        }
    }
}

As mentioned in my initial message, application is a hybrid app, and the steps described above reflect the code.

Based on your suggestion, I agree that this issue may be related to a memory management problem. I will attempt to reproduce the crash using both the Zombies Instrument and the Address Sanitiser as suggested.

Hello Justin,

As you suggested, I have repeated the tests multiple times, but I was not able to reproduce the crash. As mentioned, it appears to be difficult to encounter the issue consistently.

I would also like to share an additional observation: we ran the same application on iPads with iPadOS 18.1 for nearly six months without encountering any crashes. However, after updating the devices to iPadOS 18.6.2, the crashes started occurring.

Since the only change during this period was the iPadOS update from 18.1 to 18.6.2, I would appreciate your insight on whether any changes in this OS update could potentially contribute to this behavior?

App Crash in GameController when accessing GCKeyboard.coalesced on iPad
 
 
Q