iOS GameCenter私有API `GKNotificationBannerViewController::hideBannerQuickly`崩溃

nr7wwzry  于 2023-05-30  发布在  iOS
关注(0)|答案(1)|浏览(146)

bounty将在5天内到期。此问题的答案有资格获得+50声望奖励。OMGPOP希望引起更多关注这个问题。

我在Firebase中找到了这个崩溃日志:

Crashed: com.apple.main-thread
0  libdispatch.dylib              0x4b20 dispatch_semaphore_signal + 8
1  GameCenterUI                   0x9ebd8 __56-[GKNotificationBannerViewController hideBannerQuickly:]_block_invoke_2 + 40
2  libdispatch.dylib              0x3f88 _dispatch_client_callout + 20
3  libdispatch.dylib              0x7418 _dispatch_continuation_pop + 504
4  libdispatch.dylib              0x1aa58 _dispatch_source_invoke + 1588
5  libdispatch.dylib              0x12748 _dispatch_main_queue_drain + 756
6  libdispatch.dylib              0x12444 _dispatch_main_queue_callback_4CF + 44
7  CoreFoundation                 0x9a6c8 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16
8  CoreFoundation                 0x7c02c __CFRunLoopRun + 2036
9  CoreFoundation                 0x80eb0 CFRunLoopRunSpecific + 612
10 GraphicsServices               0x1368 GSEventRunModal + 164
11 UIKitCore                      0x3a1668 -[UIApplication _run] + 888
12 UIKitCore                      0x3a12cc UIApplicationMain + 340
13 libswiftUIKit.dylib            0x35308 UIApplicationMain(_:_:_:_:) + 104
14 BinMinesweeper                 0x7050 main + 4345163856 (AppSceneDelegate.swift:4345163856)
15 ???                            0x1e6d6c960 (Missing)

上面的例子来自iOS 16.3.1,iPhone XR。我无法重现这次坠机。这种情况很少发生(不到1%的用户)。
我假设GKNotificationBannerViewController是启动应用程序时显示的顶部横幅“Welcome user_abc”。
我唯一一次与Game Center交互是当用户单击排行榜按钮时,我显示游戏中心VC。下面是一些代码:

import GameKit

public enum GameCenterUtil {
  
  private static var g_isEnabled: Bool = false
  
  public static func setupIfNeeded() {
    GKLocalPlayer.local.authenticateHandler = { loginVC, error in
      if loginVC != nil {
        // Nothing. Do not present login. 
        // User generally don't use game center. It's annoying.
        return
      }
      if error != nil {
        g_isEnabled = false
        return
      }
      g_isEnabled = true
    }
  }
  
  public static func reportScore(_ score: Int, category: String) {
    guard g_isEnabled else { return }
    GKLeaderboard.submitScore(score, context: 0, player: GKLocalPlayer.local, leaderboardIDs: [category]) { error in
      // nothing
    }
  }
  
  public static func presentLeaderboard(in vc: UIViewController) {
    // when disabled, this will be an alert.
    let gameCenterVC = GKGameCenterViewController()
    gameCenterVC.gameCenterDelegate = LeaderboardDismisser.shared
    vc.present(gameCenterVC, animated: true, completion: nil)
  }
}

final class LeaderboardDismisser: NSObject, GKGameCenterControllerDelegate {
  static let shared = LeaderboardDismisser()
  func gameCenterViewControllerDidFinish(_ gameCenterViewController: GKGameCenterViewController) {
    // This is required. When user is not logged in, the alert prompts up. If we don't dismiss it, the game vc will be not responding. 
    gameCenterViewController.dismiss(animated: true, completion: nil)
  }
}

然后在didFinishLaunching中调用GameCenterUtil.setupIfNeeded(),在排行榜按钮回调中调用GameCenterUtil.presentLeaderboard(in: vc)
编辑:还有一个非常类似的崩溃,也无法重现,很少发生:

Crashed: com.apple.GameKit.banner
0  libdispatch.dylib              0x4a60 dispatch_semaphore_wait + 8
1  GameCenterUI                   0x9abe4 __42+[GKNotificationBannerWindow enqueBanner:]_block_invoke_2 + 60
2  libdispatch.dylib              0x2320 _dispatch_call_block_and_release + 32
3  libdispatch.dylib              0x3eac _dispatch_client_callout + 20
4  libdispatch.dylib              0xb534 _dispatch_lane_serial_drain + 668
5  libdispatch.dylib              0xc0d8 _dispatch_lane_invoke + 436
6  libdispatch.dylib              0x16cdc _dispatch_workloop_worker_thread + 648
7  libsystem_pthread.dylib        0xddc _pthread_wqthread + 288
8  libsystem_pthread.dylib        0xb7c start_wqthread + 8
l5tcr1uw

l5tcr1uw1#

这些崩溃的原因可能是死锁:在这两种情况下,崩溃的线程尝试获取信号量,但在看门狗取消应用程序之前无法获取它。
我不知道GameCenterUI,但由于它与UI相关,可能只能在主线程上调用。但是,第二个堆栈跟踪显示它是在另一个线程上调用的。
因此,请检查是否可以在其他线程上调用GameCenterUI

相关问题