【问题标题】:GameKit: Connection to plugin interrupted while in useGameKit:使用时与插件的连接中断
【发布时间】:2020-12-15 11:55:30
【问题描述】:

我已经尝试解决这个问题几个星期了。苹果开发者论坛上没有回应。 Apple 开发人员技术支持没有真正的帮助。鉴于我的项目中出现问题的可能性很高,我不敢相信任何人都没有解决这个问题。无论如何,这是我的 GameKitManager 类:

final class GameCenterManager : NSObject, GKLocalPlayerListener {
    
    static let manager = GameCenterManager()
    weak var delegate: GameCenterManagerDelegate?
    var gameCenterViewController: UIViewController?
    var match: GKMatch?
    static var isAuthenticated: Bool {
        return GKLocalPlayer.local.isAuthenticated
    }
    var matchmakerViewController: GKMatchmakerViewController?
    var invite: GKInvite?
    
    
    override init() {
        super.init()
    }

    func authenticatePlayer() {

        GKLocalPlayer.local.authenticateHandler = { gcAuthVC, error in
            
            self.delegate?.didChangeAuthStatus(isAuthenticated: GKLocalPlayer.local.isAuthenticated)

            if GKLocalPlayer.local.isAuthenticated {
                GKLocalPlayer.local.register(self)
            }
            // If the User needs to sign to the Game Center
            else if let vc = gcAuthVC {
                self.delegate?.presentGameCenterAuth(viewController: vc)
            }
            else {
                print(">>>>> Error authenticating the Player! \(error?.localizedDescription ?? "none") <<<<<")
            }
        }
    }
    

    func presentMatchmaker() {
        guard GKLocalPlayer.local.isAuthenticated else { return }
        
        let request = GKMatchRequest()
        request.minPlayers = 2
        request.maxPlayers = 4
        request.inviteMessage = "Would you like to play?"
        
        matchmakerViewController = GKMatchmakerViewController(matchRequest: request)
        matchmakerViewController!.matchmakerDelegate = self
        delegate?.presentMatchmaking(viewController: matchmakerViewController)
    }
    
    
    func player(_ player: GKPlayer, didAccept invite: GKInvite) {
        self.invite = invite
        // Start match making 4 seconds after to let the invitation sliding menu to finish loading
        let seconds = 4.0
        DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
            self.makeMatchmakerVC(from: invite)
        }
    }
    
    
    func makeMatchmakerVC(from invite:GKInvite) {
        // Accepting invitation from GKMatchmakerViewController (Friends are displayed)
        if matchmakerViewController != nil {
            matchmakerViewController!.dismiss(animated: true, completion: {
                self.matchmakerViewController = GKMatchmakerViewController(invite: invite)
                self.matchmakerViewController!.matchmakerDelegate = self
                self.delegate?.presentMatchmaking(viewController: self.matchmakerViewController!)
            })
        }
        // Accepting invitation when GKMatchmakerViewController is not yet presented
        else {
            guard let vc = GKMatchmakerViewController(invite: invite) else { return }
            self.matchmakerViewController = vc
            matchmakerViewController!.matchmakerDelegate = self
            delegate?.presentMatchmaking(viewController: matchmakerViewController!)
        }
    }
}


extension GameCenterManager: GKMatchmakerViewControllerDelegate {
    
    func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFind match: GKMatch) {
        
        print("-----matchmakerVC did find match-------")
        
        viewController.dismiss(animated: true, completion: {
            self.match = match
            self.match!.delegate = self
            self.delegate?.presentGame(match: self.match!)
        })
    }
    

    func matchmakerViewControllerWasCancelled(_ viewController: GKMatchmakerViewController) {
        viewController.dismiss(animated: true)
        delegate?.matchmakingCancelled()
    }
    

    func matchmakerViewController(_ viewController: GKMatchmakerViewController,
                                  didFailWithError error: Error)
    {
        
        viewController.dismiss(animated: true, completion: {

            print("################# fail with error ##################\n\(error.localizedDescription)\n")
            self.matchmakerViewController!.matchmakerDelegate = nil
            self.matchmakerViewController = nil
            self.invite = nil
            self.match = nil
        })
    }
}

这是复制问题的方法。

  • 玩家启动应用。两者都会看到介绍屏幕。

  • 玩家 1 点击“在 GameCenter 中玩”。媒人 VC 现在对玩家 1 开放。

  • 玩家 1 将玩家 2 添加到游戏中,然后点击邀请和开始按钮。

  • 玩家 2 收到邀请(从顶部滑动消息)并立即点击它以接受邀请(不要等待邀请完成播放乐曲)。请注意,玩家 2 仍处于 Intro 场景中。

  • 玩家 2 收到了连接错误,即使他/她接受了邀请,而玩家 1 被通知玩家 2 加入了游戏并进入游戏场景。

  • 就代码流而言,播放器2调用方法'player(player:invite:)';从邀请中创建一个新的 matchmakerViewController 并呈现;完成后,播放器 2 收到以下错误:

    -----player -- 接受邀请-----player2

    ....内幕:委托 PRESENT_MATCHMAKING 呼叫......

    2020-11-08 17:03:07.083450-0500 igkTest[48868:2788074] [生命周期] [u 196C65DD-6BC1-46D7-B43D-1399E5802378:m (null)] [com.apple.GameCenterUI.GameCenterMatchmakerExtension( 1.0)] 在使用时与插件的连接中断。

    2020-11-08 17:03:07.083680-0500 igkTest[48868:2788073] [生命周期] [u 196C65DD-6BC1-46D7-B43D-1399E5802378:m (null)] [com.apple.GameCenterUI.GameCenterMatchmakerExtension( 1.0)] 在使用时与插件的连接无效。

    2020-11-08 17:03:07.160824-0500 igkTest[48868:2788043] [Match] 无法设置播放器的连接状态:(playerID:G:271575631, alias:player),因为还没有设置邀请委托.当我们稍后设置inviteDelegate并调用sendQueuedStatesAndPackets时,状态可能会直接变为Ready。

    2020-11-08 17:03:07.166467-0500 igkTest[48868:2788074] [assertion] 获取断言时出错:

    2020-11-08 17:03:07.169507-0500 igkTest[48868:2788074] [断言] 获取断言时出错:

    2020-11-08 17:03:07.170369-0500 igkTest[48868:2788070] [断言] 获取断言时出错:

    2020-11-08 17:03:07.175163-0500 igkTest[48868:2788043] [错误] 扩展请求因错误而中断:Error Domain=ExtensionErrorDomain Code=-5900 "(null)"

    2020-11-08 17:03:07.218324-0500 igkTest[48868:2788043] viewServiceDidTerminateWithError:: Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted}

    2020-11-08 17:03:07.652617-0500 igkTest[48868:2788043] [ViceroyTrace] [ERROR] VCCTServiceMonitor_GetDataIndicatorStatus:193 设备没有蜂窝基带

    2020-11-08 17:03:07.944964-0500 igkTest[48868:2788203] [ViceroyTrace] [ERROR] OSPFParse_ParsePacketHeader:1083 Bad destination count=0

    2020-11-08 17:03:07.946241-0500 igkTest[48868:2788203] [ViceroyTrace] [ERROR] OSPFParse_ParsePacketHeader:1100 Checksum=42050 不匹配

    2020-11-08 17:03:07.965383-0500 igkTest[48868:2788223] [ViceroyTrace] [错误] gckSessionCheckPendingConnections:1454 gckSessionCheckPendingConnections: iICEChecksLeft=0, iUnconnectedNodeCount=0, iDDsExpected=1

    2020-11-08 17:03:07.966116-0500 igkTest[48868:2788223] [ViceroyTrace] [ERROR] ProcessEvent:1201 Send BINDING_REQUEST failed(801A0016)。

    2020-11-08 17:03:07.967086-0500 igkTest[48868:2788074] [ViceroyTrace] [ERROR] ICEStopConnectivityCheck:2740 ICEStopConnectivityCheck() 发现没有带有呼叫 ID (2014448547) 的 ICE 检查

    2020-11-08 17:03:07.992298-0500 igkTest[48868:2788203] [ViceroyTrace] [错误] gckSessionCheckPendingConnections:1454 gckSessionCheckPendingConnections: iICEChecksLeft=0, iUnconnectedNodeCount=0, iDDsExpected=0

    ################# 失败并出现错误#################

    操作无法完成。 (ExtensionErrorDomain 错误 -5900。)

玩家 2 抛出方法 'matchmakerViewController( viewController: error:)',但由于他/她已经接受了邀请,玩家 1 假设邀请已被接受,并使用 'self.delegate?.presentGame(match : self.match!)'。

这种情况并非每次都发生,而是在玩家 2 过早接受邀请时每 2 次或 3 次发生一次。

如果有人可以提供帮助,请提前非常感谢!

【问题讨论】:

  • 出现错误时我发现了另一个用例。玩家 1 邀请玩家 2 玩游戏,玩家 2 接受邀请。然后任一玩家停止比赛(比赛被取消,现在双方都为零:GameCenterManager.manager.match.disconnect(); GameCenterManager.manager.match = nil)。然后,玩家 2 邀请玩家 1,玩家 1 接受邀请参加另一场比赛。玩家 2 找到匹配并进入游戏场景,而玩家 1 最终出现此错误(接受邀请,然后无法创建新匹配)。

标签: swift gamekit


【解决方案1】:

如果有人遇到同样的问题,以下方法会有所帮助吗?

func player(_ player: GKPlayer, didAccept invite: GKInvite) {
        if matchmakerViewController != nil {
            matchmakerViewController!.dismiss(animated: false, completion: nil)
            self.matchmakerViewController!.matchmakerDelegate = nil
            self.matchmakerViewController = nil
        }

        let delayTime = DispatchTime.now() + .milliseconds(2000)

        DispatchQueue.main.asyncAfter(deadline: delayTime) {
            self.matchmakerViewController = GKMatchmakerViewController(invite: invite)
            self.matchmakerViewController!.matchmakerDelegate = self
            self.delegate?.presentMatchmaking(viewController: self.matchmakerViewController!)
        }
}

Dispatch.asyncAfter 让系统有时间在开始新任务之前对 matchmakerViewController 进行全面“清理”。我现在正在测试它,但其他人的反馈将不胜感激。

编辑: 经过更多测试,这并没有证明是解决方案;问题继续存在。但是,我注意到当第二个玩家打开 GKMatchmakerViewController 的实例时,我没有遇到问题。换句话说,如果我先拨打presentMatchmaker(),然后接受邀请,就可以了。因此,例如,当第二个玩家不在游戏中并收到游戏邀请时,就会出现问题。因此,我将我的代码更改为以下,这似乎是目前为止的工作:

public func player(_ player: GKPlayer, didAccept invite: GKInvite) {
        if matchmakerViewController != nil {
            matchmakerViewController!.dismiss(animated: false, completion: nil)
            self.matchmakerViewController!.matchmakerDelegate = nil
            self.matchmakerViewController = nil
        }
        
        // THIS HELPS AVOID CRASH.
        presentMatchmaker()
        
        let delayTime = DispatchTime.now() + .milliseconds(1000)
        DispatchQueue.main.asyncAfter(deadline: delayTime) {
            self.matchmakerViewController = GKMatchmakerViewController(invite: invite)
            self.matchmakerViewController!.matchmakerDelegate = self
            self.delegate?.presentMatchmaking(viewController: self.matchmakerViewController!)
        }
    }

不是一个非常优雅的解决方案...

【讨论】:

  • 如果其他人遇到此问题,我发现创建和显示GKMatchmakerViewController,然后在DispatchQueue.main.asyncAfter(deadline: .now()) 中设置委托也可以解决此问题。这仍然是一个 hack,但看起来更干净一些,因为不需要额外的视图控制器并且没有延迟。
  • 谢谢。正如您在我的最后一段代码中看到的那样,这就是我所做的。不调用presentMatchmaker() 仍然有同样的问题。干杯。
猜你喜欢
  • 2021-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多