Builds Game Center features with GameKit. Use for local-player authentication and restrictions, access point/dashboard, leaderboards, achievements, challenges, saved games, invitations, real-time or turn-based matchmaking, match data, and server identity verification.
94%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
Use GameKit for Game Center authentication, competition, matchmaking, social surfaces, and saved-game handoffs; keep rendering, board logic, and full SharePlay group-activity design in their owning framework skills.
GKLocalPlayer once, present authentication UI when supplied, and inspect restrictions before enabling features.// DON'T
func submitScore() {
GKLeaderboard.submitScore(100, context: 0, player: GKLocalPlayer.local,
leaderboardIDs: ["scores"]) { _ in }
}
// DO
func submitScore() async throws {
guard GKLocalPlayer.local.isAuthenticated else { return }
try await GKLeaderboard.submitScore(
100, context: 0, player: GKLocalPlayer.local, leaderboardIDs: ["scores"]
)
}// DON'T: Set handler on every scene transition
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
GKLocalPlayer.local.authenticateHandler = { vc, error in /* ... */ }
}
// DO: Set the handler once, early in the app lifecycle// DON'T
func showMultiplayerMenu() { presentMatchmaker() }
// DO
func showMultiplayerMenu() {
guard !GKLocalPlayer.local.isMultiplayerGamingRestricted else { return }
presentMatchmaker()
}// DON'T: Set delegate in dismiss completion -- misses early messages
func matchmakerViewController(_ vc: GKMatchmakerViewController, didFind match: GKMatch) {
vc.dismiss(animated: true) { match.delegate = self }
}
// DO: Set delegate before dismissing
func matchmakerViewController(_ vc: GKMatchmakerViewController, didFind match: GKMatch) {
match.delegate = self
vc.dismiss(animated: true)
}// DON'T
let match = try await GKMatchmaker.shared().findMatch(for: request)
startGame(with: match)
// DO
let match = try await GKMatchmaker.shared().findMatch(for: request)
GKMatchmaker.shared().finishMatchmaking(for: match)
startGame(with: match)// DON'T
func returnToMenu() { showMainMenu() }
// DO
func returnToMenu() {
currentMatch?.disconnect()
currentMatch?.delegate = nil
currentMatch = nil
showMainMenu()
}GKLocalPlayer.local.authenticateHandler set once at app launchisAuthenticated checked before any GameKit API callisUnderage, isMultiplayerGamingRestricted, isPersonalizedCommunicationRestricted)GKGameCenterControllerDelegate dismisses dashboard in gameCenterViewControllerDidFinishfinishMatchmaking(for:) called for programmatic matches; disconnect() and nil delegate on exitmatch.matchDataMaximumSizeendMatchInTurnGKLocalPlayer.local.register(_:).reliable for state, .unreliable for frequent updatesthienqo/ios-skills
6bf8b62
Canonical home
since May 23, 2026
Also appears in
on Sep 6, 2026
since May 22, 2026
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.