Highlight
Xcode 26 新增
.gamekitbundle,把 Leaderboards、Challenges、Activities、Achievements 的配置从 App Store Connect 网页迁回项目源码,可纳入版本控制和 Code Review,并通过 Game Progress Manager 在本地直接调试分数提交与深链跳转。
核心内容
过去做 Game Center 集成的开发者都遇到过一个反复出现的痛点:所有的 Leaderboard、Achievement、Challenge 配置都散落在 App Store Connect 网页上,改一个 ID 要登录浏览器,多人协作没有 diff,回滚靠记忆,连本地跑测试都要打真实数据到服务器。一个简单的”测一下新加的关卡分数能不能正确上报”,往往要先在 ASC 建条目、提交真实分数、刷新榜单、再手动清理脏数据。
WWDC25 的第一刀就砍在这里。Xcode 26 新增了 .gamekit bundle —— 一个本地文件,里面声明你所有的 Game Center 资源。它可以从 App Store Connect “Pull”下来,编辑完再”Push”回去;同时本地配备 Game Progress Manager,所有调试的分数都只活在这次会话里,不会污染线上数据。这意味着 Game Center 的配置从此变成代码资产,可以走 PR、走 Code Review、跟着分支走。
今年另两个主菜是 Challenges 和 Activities。Challenges 直接长在已有的 Leaderboard 之上 —— 如果你已经在用 submitScore(),理论上不写一行代码就能让玩家发起带时限的好友对战;Activities 则是深链入口,把好友点进来的玩家直接送到正确的关卡或多人房间,并通过 Game Center 自动生成的 Party Code 把人聚到同一个对局里。
详细内容
Game Center 的初始化只有两步:加 entitlement,调一次 GameKit。下面这段 Swift 是官方推荐的最早初始化时机(04:17):
GKLocalPlayer.local.authenticateHandler = { _, error in
print("\(GKLocalPlayer.local.alias) is ready to play!")
}
关键点:
GKLocalPlayer.local是单例,代表本机当前登录的 Game Center 玩家。authenticateHandler是一个回调,赋值后 GameKit 才真正开始走鉴权流程。- handler 触发后,
GKLocalPlayer.local.alias才是有效值;之前读到的是空字符串。 - 官方建议把这段挂在 title screen 出现时执行,越早调用,越早进入”Top Played Games”曝光池。
Unity 开发者用同样的语义,写法是 C#(04:29):
var player = await GKLocalPlayer.Authenticate();
Debug.Log($"{player.alias} is ready to play!");
Unity Plugin 从 GitHub 仓库(apple/unityplugins)拉源码自己 build,build 完会生成一个已经带好 entitlement 的 Xcode 工程。
到了 Challenges,这是这次设计上最克制的地方 —— 它不要求你新增 API。你提交分数的那行代码不变(13:07):
GKLeaderboard.submitScore(points,
context: 0,
player: GKLocalPlayer.local,
leaderboardIDs: ["thecoast.lb.capecod"])
关键点:
leaderboardIDs是数组,意味着一次提交可以打到多个榜单。- 同一个 API 会自动把分数同步给所有关联到该榜单的进行中 Challenge,不需要单独调一个
submitChallengeScore。 - 官方反复强调:每次关卡结束后只提交一次分数,不要累加 lifetime 分数 —— Challenge 是技巧比拼,不是肝度比拼。
context是给开发者自由发挥的整数字段,可以塞关卡 ID、武器配置等额外维度。
Activities 把深链拉到了系统层。下面这段是把好友点进来的玩家送回正确关卡的入口(20:24):
extension AppDelegate: GKLocalPlayerListener {
func player(_ player: GKPlayer, wantsToPlay activity: GKGameActivity) async -> Bool {
let activityId = activity.activityDefinition.identifier
if activityId == "thecoast.activity" {
let level = activity.properties["level"]
if level == "capecod" {
startCapeCod(activity)
}
}
return true
}
}
关键点:
GKLocalPlayerListener是协议,注册之后 GameKit 把所有外部唤起都丢到这个 handler。activity.activityDefinition.identifier是你在 Xcode.gamekitbundle 里手填的字符串,要和资源端对齐。activity.properties是字典,承载在 Xcode 里设置的 base properties + 关联资源(如 leaderboard)的 properties 合并结果。- handler 返回
Bool告诉系统是否成功接管这次跳转 —— 返回false时系统会做兜底。
如果做多人游戏,Activity 自带 Party Code 机制(22:35),可以把同一个 Code 的玩家凑成一桌:
extension AppDelegate: GKLocalPlayerListener {
func player(_ player: GKPlayer, wantsToPlay activity: GKGameActivity) async -> Bool {
let activityId = activity.activityDefinition.identifier
if activityId == "thecoast.multiplayer" {
startMultiplayer(partyCode: activity.partyCode)
}
return true
}
}
关键点:
activity.partyCode由 Game Center 自动生成,无需自建房间号系统。- iMessage 分享 Activity 时,Code 会被嵌进 OpenGraph 网页,对端即使没装 Games app 也能看到分享卡片。
- UI 上必须显示当前 Party Code 并提供手动输入入口,因为玩家可能从另一台设备/平台收到 Code。
如果你不想自建房间匹配,也可以一行接入 Game Center 现成的 matchmaking(22:48):
let match = try await activity.findMatch()
调试流程也是这次的亮点。Scheme → Run Options 里勾选 “GameKit Configuration Debug Mode”,启动游戏后 Debug 菜单里打开 Game Progress Manager,所有 .gamekit bundle 里的资源都列在面板上。你可以以任意玩家身份提交任意分数,Activity 的深链可以直接在 Xcode 里点击触发,效果等同于真机点击。所有调试数据只活在本次会话里,不会写到服务器(24:03)。
核心启发
-
做什么:把现有项目里的 Game Center 配置从 App Store Connect 迁回
.gamekitbundle。- 为什么值得做:配置和代码一起进 Git,PR 里能看到 diff,回滚不再靠记忆,多人协作不会互相覆盖。
- 怎么开始:Xcode 26 → New File → “GameKit Bundle” → 在 ellipsis 菜单选 “Pull from App Store Connect”,选好 team 和游戏,资源会原样落地到本地文件。
-
做什么:给已有的 Leaderboard 加 Challenge,零代码获得”好友约战”功能。
- 为什么值得做:复用现有
submitScore调用路径,零侵入;Challenge 自带时限和好友邀请 UI,把单机榜单瞬间变社交对局。 - 怎么开始:在
.gamekitbundle 里给目标 Leaderboard 添加一个 Challenge 条目,配置图、displayName、允许时长(1 天/3 天/1 周),确认submitScore()的leaderboardIDs写对即可。
- 为什么值得做:复用现有
-
做什么:为常用关卡或多人房间配 Activity 深链。
- 为什么值得做:好友从 Games app 或 iMessage 点进来直接到关卡现场,跳过开屏、菜单、章节选择这些摩擦层,转化率显著高于”打开游戏让用户自己找”。
- 怎么开始:在
.gamekitbundle 新建 Activity,关联对应 Leaderboard 并填properties(如level: "capecod");实现GKLocalPlayerListener.player(_:wantsToPlay:),根据identifier和properties做路由。
-
做什么:把 Game Progress Manager 写进开发流程,替代真实服务器调试。
- 为什么值得做:调试期间不写脏数据到线上榜单;深链可以直接在 Xcode 里点;可以用任意玩家身份模拟提交,方便测多人交互场景。
- 怎么开始:编辑 Scheme → Run Options,勾上 GameKit Configuration Debug Mode;启动后从 Debug 菜单开 Game Progress Manager,选当前设备和你的游戏。
关联 Session
- Engage players with the Apple Games app — 新 Games app 的曝光机制与上架要点
- Level up your games — Apple 统一游戏平台的整体技术地图
- Discover Metal 4 — Metal 4 新特性,给游戏渲染做底层升级
- WWDC25 Platforms State of the Union Recap — 今年开发者大会的全平台速览
评论
GitHub Issues · utterances