What's new in Wallet
App Store & Distribution 入门 30m

Wallet 新特性

What's new in Wallet

2025年6月10日

在 Apple 官方观看视频

一句话判断

如果你做票务或航空 App,今年 Wallet 的更新能让你砍掉一半的推送逻辑和通行证管理代码——前提是你愿意把航班状态追踪这类核心体验交给 Apple 的系统服务。

这场 Session 讲了什么

过去几年 Wallet 的更新节奏一直不温不火,今年算是来了个大动作。最核心的变化是”一张票不再只是一张票”——upcomingPassInformation 让一张通行证能装下一整个巡演或赛季,每个场次有自己的详情页、场馆信息和独立状态。这对做了多年”一场一张票”的开发者来说,是个底层数据模型的重写。

登机牌那边的改动更激进。Apple 直接把航班状态追踪接进了系统级的 Apple 航班服务(Apple Flight Service),登机口变了、延误了,系统自己更新,开发者不用再维护那套 APNs 推送 + 后端轮询的逻辑。配合 Live Activity,用户在锁屏和灵动岛就能全程盯着航班状态,甚至可以把行程通过信息分享给接机的人。

还有一个容易被忽略的改动:自动添加通行证 API。PKPassLibrary 新增的 addPasses 方法支持一次授权后自动往 Wallet 塞通行证,把用户从”打开 App → 找到订单 → 点添加到 Wallet”这条路径里解放出来。对月票、周卡这种高频场景影响不小。

值得深挖的点

Apple 航班服务介入后,开发者的推送逻辑怎么办?

登机牌集成 Apple 航班服务是这次更新里最值得玩味的决策。表面上看,这是个纯粹的减负——开发者只需要在创建通行证时填好 airlineCodeflightNumber,剩下的航班状态更新全由系统接管。但这里有个 trade-off:你把状态推送的控制权让渡给了 Apple。

过去航空公司的 App 通常维护着一套完整的推送链路:GDS 或航班数据供应商 → 后端服务 → APNs → App 更新通行证。这条链路虽然复杂,但数据是自己的,时机是自己控的,推送内容也是自己定的。现在系统接管了,你的数据准度还重要吗?如果 Apple 航班服务的数据源和你自己的数据源产生了冲突——比如你的系统先拿到了登机口变更,但系统还没更新——用户在 Wallet 里看到的就是过时信息。

实际操作中,开发者应该保留自己的推送通道作为补充,而不是完全依赖系统。特别是涉及中国市场航班时,国内航班数据的实时性可能和 Apple 的数据源存在时差。originalDepartureDatecurrentDepartureDate 的分离设计给了你这个空间——你可以继续更新 current* 字段,系统会自动处理展示。关键是不要因为”系统能自动更新”就彻底放弃自己的数据管道。

自动添加 API 的授权设计:一步到位还是温水煮青蛙?

PKPassLibrary.addPasses 的授权模型值得细看。用户首次调用时会弹出系统授权弹窗,授权后后续通行证可以自动添加。这个”一次授权,永久生效”的模型和通知权限的”每次询问”形成了鲜明对比——Apple 在通行证这个品类上选择了信任开发者。

但”自动”不等于”无感”。addPasses 的回调有三个状态:didAddPasses(成功)、didCancelAddPasses(用户取消)、shouldReviewPasses(需要用户审核)。第三个状态容易被忽略,它意味着系统认为这个通行证需要用户手动确认——可能是因为通行证类型不常见,或者用户之前撤销过授权。如果你的 UI 没处理这个分支,用户会看到一个没有反馈的黑洞。

调用时机也很关键。在用户刚完成购票、情绪高涨的时候弹授权,通过率远高于 App 启动时静默调用。这不是技术问题,是产品设计问题。

代码片段

一张票装下整个巡演

场景:演唱会巡演,一张通行证覆盖多个城市。

{
  "upcomingPassInformation": [
    {
      "type": "event",
      "identifier": "tour-2025-shanghai",
      "displayName": "上海站",
      "date": "2025-08-15T19:30:00+08:00",
      "semantics": {
        "venueName": "上海体育场",
        "venuePlaceID": "ChIJ...",
        "seats": [{ "seatSection": "A区", "seatRow": "5", "seatNumber": "12" }]
      },
      "isActive": true
    },
    {
      "type": "event",
      "identifier": "tour-2025-beijing",
      "displayName": "北京站",
      "date": "2025-08-22T19:30:00+08:00",
      "semantics": {
        "venueName": "国家体育场",
        "venuePlaceID": "ChIJ..."
      }
    }
  ]
}

坑:identifier 必须全局唯一且稳定,通行证更新时如果 ID 变了,Wallet 会把它当成新票重新创建,用户会看到重复项。

购票后自动添加到 Wallet

场景:用户在 App 内完成购票,无需手动操作即添加到 Wallet。

import PassKit

func autoAddPass(_ passData: Data) {
    let library = PKPassLibrary()
    guard let pass = try? PKPass(data: passData) else { return }

    library.addPasses([pass]) { result in
        switch result {
        case .didAddPasses:
            // 添加成功
            break
        case .didCancelAddPasses:
            // 用户取消,考虑降级到手动添加流程
            showManualAddOption()
        case .shouldReviewPasses:
            // 系统要求用户审核,别忽略这个分支
            showReviewPrompt()
        @unknown default:
            break
        }
    }
}

坑:shouldReviewPasses 经常被漏掉,但它的出现概率不低——尤其在用户之前拒绝过授权或通行证类型较新的情况下。

登机牌:把航班追踪交给系统

场景:创建支持自动航班追踪的登机牌。

{
  "semantics": {
    "airlineCode": "MU",
    "flightNumber": "5101",
    "originalDepartureDate": "2025-07-01T08:00:00+08:00",
    "currentDepartureDate": "2025-07-01T08:30:00+08:00",
    "departureAirportCode": "PVG",
    "arrivalAirportCode": "PEK",
    "departureGate": "C22"
  }
}

坑:original*current* 的差异是系统展示延误高亮的依据,但如果你只填了 original* 没填 current*,系统就无法判断是否有变更,航班追踪等于没开。

最佳实践

票务 App 开发者建议先把现有的多场次通行证数据模型梳理一遍,看看能不能用 upcomingPassInformation 替换掉当前”一场一票”的结构。迁移成本不高,但收益是实打实的——用户在 Wallet 里看到的不再是一堆散票,而是一张有组织的通行证。注意 identifier 的稳定性,这决定了迁移过程会不会产生重复票。

航空 App 开发者建议分两步走。第一步:确保登机牌的语义标签完整,特别是 airlineCodeflightNumber 和所有 current* 字段,这是启用系统级航班追踪的最低要求。第二步:不要砍掉自己的推送通道。Apple 航班服务是个加分项,不是替代品。在国内航线的数据时效性被验证之前,保持双通道是稳妥的选择。

自动添加 API 优先用在高频场景——月票、通勤卡、赛季套票。一次性票务(比如单场演唱会)的价值没那么大,因为用户下次购票可能是几个月后,授权状态已经”凉了”。调用时机卡在购票完成的那一刻,不要在 App 启动时静默调用。

还有什么值得关注

  • Live Activity 支持通过信息分享航班状态,这对出行场景是社交属性的补完,但实现上依赖 Widget Extension,项目配置别忘了。
  • 登机牌现在集成了 Maps 机场导航和 Find My 行李追踪,虽然不是开发者直接控制的功能,但如果你的登机牌语义标签够完整,这些系统能力会自动解锁。
  • upcomingPassInformation 中的日期必须按时间顺序排列,否则 Wallet 界面会乱序展示——这个没有校验提示,出了 bug 很难排查。
Wallet PassKit Apple Pay Live Activity