大多数浏览器和
Developer App 均支持流媒体播放。
-
钱包与 Apple Pay 的新功能
探索“钱包”和 Apple Pay 的最新更新。我们将介绍如何在您的 App 和网站中为“钱包”中的订单提供支持,并借助 Identity Verification API 安全验证用户的年龄和身份。我们还将探索 SwiftUI 的 PassKit 支持,讨论您可以如何利用自动付款优化您的 Apple Pay 体验。
资源
- Apple Pay
- Apple Pay Merchant Token Management API
- Apple Pay on the Web
- Apple Pay on the Web Interactive Demo
- ApplePayPaymentRequest
- Example Order Packages
- Human Interface Guidelines: Wallet
- PassKit (Apple Pay and Wallet)
- Requesting identity data from a Wallet pass
- Verifying Wallet identity requests
- Wallet Orders
相关视频
WWDC23
-
下载
♪ 柔和乐器演奏的嘻哈音乐 ♪ ♪ Lais Minchillo: 嗨 我叫 Lais David Silver:我是 David 我们将为您介绍 今年 钱包 和 Apple Pay 的新功能 我们在 2014 年 推出了 Apple Pay 为在实体店 在线商店和 App 内进行 快速 安全 私密的支付 设定了新的基准 从那时起 我们在全球范围内 推广了 Apple Pay Apple Pay 现已在 72 个国家和地区提供服务 每天处理超过一百万笔交易 今天 我们将为 钱包和 Apple Pay 引入令人兴奋的新功能和 API Lais 会为您具体介绍 Lais :谢谢您 David 让我们来看看这场讲座的主要议程 首先 我们将聊一聊快速更新 我们增加了在单笔交易中 向多个商户支付的支持 我们还大大改善了 包括订阅服务在内的 自动支付的支持 通过订单跟踪 您可以增强 客户的购后体验 最后 David 将聊一聊 用钱包中的 ID 进行身份验证 我们要先分享一些 令人振奋的更新内容 iPhone 上的 Tap to Pay 于今年早些时候发布 并在美国 iOS 15.4 平台上发布 iPhone 上的 Tap to Pay 提供了一种安全 私密 便捷的 非接触式支付方式 您可以轻松地将它 集成到您的 App 中 无缝且安全地接收非接触式支付 这种支付方式 包括 Apple Pay 非接触式信用卡和借记卡 和其他数字钱包 只需在 iPhone 上轻触一下 交易就能完成 无需额外的硬件 或支付终端 同时 在 macOS 13 中 我们重新设计了 Apple Pay 的体验 去年 iOS 的付款表单重新设计 取得了巨大的成功 今年我们将为 macOS 引入类似的体验 我们使用了 SwiftUI 来重新设计 从而让我们 为 macOS 与 iOS 同时引入了新功能 我们今天介绍的 所有 Apple Pay 功能 在 Mac 上也支持 我们将引入 新的 SwiftUI API 在您的 SwiftUI App 中集成 “添加到 Apple 钱包” 或 “Apple Pay” 按钮会更容易 这些新的 API 将大大减少 您需要编写的代码量 让我们看看如何添加按钮 以提示用户添加航空通票 首先 创建航空通票 您应该处理好未成功加载的情况 例如 航空通票数据不正确 或未正确签名 就可能发生这种情况 接下来 使用通票数组调用 AddPassToWalletButton 在这个例子中 只有一个元素的数组 但是同一个按钮上可以有多个通票 结果作为 Bool 传入 您可以根据 用户是否添加了通票 来保存 记录或触发 App 中的其他操作 在此示例中 我将它保存到状态变量 这样就完成了 您还可以在一组最小值中 自定义按钮的大小和样式 这是默认尺寸 宽 250 高 50 您也可以把按钮变宽
或变高
以上就是如何 在 SwiftUI 中添加 “添加到 Apple 钱包”按钮 接下来 看看如何添加 “使用 Apple Pay 支付”按钮 首先 使用 PKPaymentRequest 类 创建一个支付请求 在上面设置您通常的配置 然后创建一个 authorizationChange 方法 这两个部分完成后 就可以添加代码来显示按钮 添加对 PayWithApplePayButton 的调用 传入标签 paymentRequest 对象 和 authorizationChange 方法 如果要处理前设备 不支持 Apple Pay 的情况 通过当前设备 您可以传入回退视图 就像“添加航空通票”按钮一样 您同样可以自定义其大小和样式 总共有 17 个不同的标签 因此 您能够自定义支付按钮 以与您的用例保持一致 这些适用于 iOS iPadOS macOS 和 watchOS 接下来 再来看看多商户支付 在 iOS 16 中 我们引入了在同一笔交易中 为各个不同商户 单独请求交易令牌的功能 这种功能对于在线市场 旅行预订和票务服务等很有帮助 我们来详细看看这个例子 想象一下 Allison 正在计划一次旅行 她访问一家旅行社网站 网站方便地为她提供了 客户需要预订的一切 机票 酒店住宿和汽车租赁 Allison 总共 只需要支付 500 美元 Allison 向 旅行社网站提供了 她完整的信用卡信息 现在 您可能会认为旅行社 将从 Allison 的信用卡 扣除 500 美元 然后支付给其他相关公司 但通常情况下 旅行社只需 简单地将信用卡信息传递给每家公司 让各家公司进行各自的收费 这行么做得通 但是 把她的信用卡信息泄露出去 对 Allison 的隐私 和安全不利 现在 有了新的多商户支付 API 就可以为交易中涉及的每个商户 请求支付令牌 有了支付令牌 各家公司可以 分别向 Allison 收取 她授权的相关金额 Allison 现在可以预订 并支付旅行费用 同时也能享受 Apple Pay 提供的 隐私和安全优势 付款表已经更新 能够向客户显示 交易中涉及的子商户明细 客户可以点击“总金额” 前往到付款摘要 摘要中 客户可以看到涉及到交易的 所有商户的分类 以及每个商户授权的金额 现在 让我们看看如何在应用中 添加多商户支付 首先 使用 PKPaymentRequest 类 创建一个支付请求 在上面设置您通常的配置 然后 为您的付款 添加汇总项目 包括总额 接下来 使用新的 PKPaymentTokenContext 类 为交易中涉及的每个额外商户 创建一个支付令牌 context 提供每个商户的详细信息 以及为每个商户授权的金额 最后 在支付请求上 设置支付令牌 contexts 请记住 所有 支付令牌 context 的金额总和 必须小于或等于 支付请求本身的总金额 此外 在 App 中 为商家请求支付令牌时 您应该始终为同一个商户 使用相同的外部标识符 要在网页上采用 多商户支付的 Apple Pay 请查看 Apple Pay JS API 文档 接下来看一看 我们对自动支付的改进 在 iOS 16 中 我们引入了 用户可以通过钱包应用查看和管理 他们设置的自动向商家支付的功能 在这个版本中 我们支持两种类型的自动支付 定期自动扣除 其中包括 订阅 分期付款或定期计费 和自动充值支付 例如商店卡余额充值 我们将引入新的 API 以让您在提出支付请求时 向客户请求设置自动支付 我们还推出了 Apple Pay 商户令牌 这是一种与客户的 Apple ID 绑定的 新型支付令牌 可以帮助您在现有基础上 更可靠地向客户收费 我们来详细看一下 Apple Pay 商户令牌 看看它们是如何发挥作用的 想象一下 Julie 正在用 iPhone 上的 Apple Pay 支付读书俱乐部的会员费 读书俱乐部提出付款请求 当 Julie 授权付款时 读书俱乐部收到付款令牌 每个月 俱乐部都可以用付款令牌 向 Julie 收取会员资格费用 此付款令牌 链接到 Julie 的设备 用于授权支付 但如果 Julie 买了一台 新的 iPhone 会怎样? 有了新的自动支付功能 如果 Julie 的支付网络支持 俱乐部会将收到 Apple Pay 商户令牌 此支付令牌与 Julie 的 Apple ID 绑定 而不是与她的 iPhone 绑定 这样就能更好地保证正在进行的授权 也就是说 如果 Julie 升级了 iPhone 或重置了她当前的手机 读书俱乐部依旧能可靠地 向 Julie 收取 每月的会员资格费用 如果您接受 Apple Pay 进行这些类型的付款 采用自动支付是一个好主意 能够确保 您可以持续可靠地向客户收费 且能避免服务中的任何中断 我们在这个版本中支持的 第一种自动支付方式是定期自动扣除 定期自动扣除的金额 可以是固定或可变的 按定期计划收取 如每周 每月或每年收费 这些付款可以在特定日期结束 也可以一直持续到取消 我们也支持试用期或优惠期 定期自动扣除可以完美用于 订阅 分期付款计划 和定期计费 让我们看看如何在 App 中 用自动支付设置定期自动扣除 首先使用 PKRecurringPaymentSummaryItem 类 指定自动扣除的金额 和持续时间 对于定期自动扣除 您可以同时指定常规计费周期 也可以指定优惠期或试用期 您可以使用 startDate 和 endDate 属性 来指示试用期何时结束 常规计费周期何时开始 接下来 使用新的 PKRecurringPaymentRequest 类 创建一个定期自动扣除请求 提供付款说明 正常计费周期 以及前往网页的管理 URL 客户可以在这个页面上更新或删除 定期自动扣除服务 您还可以选择提供试用计费期 以及计费协议文本 以帮助向客户解释付款条款 最后 您可以选择 提供令牌通知 URL 如果发布了令牌 您的服务器可以接收 关于 Apple Pay 商家支付令牌的 生命周期 例如 如果卡颁发者或用户 删除令牌 您可以收到通知 有关商户令牌生命周期通知的 更多信息 请参阅 Apple Pay 商户令牌 管理 API 文档 最后 在 paymentRequest 对象上 设置定期自动扣除请求 关于汇总项目 简要说明一下 您的定期自动扣除 不会自动添加到付款请求的 汇总项目上 因此 请务必将定期自动扣除的项 添加到汇总项数组中 支付请求的总额 应该是向客户收取的 第一笔金额 所以在这个例子中 总金额设置为 显示试用期的金额 因为这是向客户收取的第一笔金额 付款表单将向客户显示 定期自动扣除的详细信息 他们可以点击“账单详情”部分 进一步阅读 接下来是我们在这个版本中支持的 第二种自动支付方式 自动充值支付 通过这种付款方式 每当余额低于 一定阈值金额时 就会自动为余额充值 自动充值支付非常适合 商店卡充值和预付余额之类的付款 要请求设置自动充值支付 首先使用新的 PKAutomaticReloadPaymentSummaryItem 类 指定充值和阈值金额 接下来 使用新的 PKAutomaticReloadPaymentRequest 类 创建一个自动充值支付请求 传入支付描述 账单 和管理 URL 和前文定期自动扣除部分一样 您还可以选择提供计费协议文本 和一个令牌通知 URL 最后 在支付请求对象上 设置自动充值支付请求 同样 请确保在汇总项目中包含 自动充值支付项 并适当设置支付请求的总额 关于在网络页面上 使用 Apple Pay 自动支付 查看 Apple Pay JS API 文档 这是您客户的付款表单 自动充值支付是这样显示的 最后 当您在应用中采用自动支付时 您需要记住以下几点 以便为客户提供最佳体验 记住要包括自动付款的汇总项目 因为这些项目不会自动添加 付款请求的总金额应该是 将向客户收取的第一笔金额 计费协议文本应当简短 付款单将仅显示前 500 个字符 计费协议文本不应当取代 您的正常账单和法律协议 是否遵守当地的定期自动扣除法规 取决于您的主张 如果您要向客户展示法律协议 请先向客户展示法律协议 再展示付款单 在单笔交易中 您只能请求一种类型的自动付款 此外 自动支付不能用于 多商户支付 最后 如果您希望接收 Apple Pay 商户令牌的 生命周期通知 请务必提供令牌通知 URL 并在服务器上采用 Apple Pay 商户令牌 管理 API 我们认为您 会喜欢这些新的 API 也会享受 Apple Pay 商户令牌带来的好处 以上是我们的一些合作伙伴 他们也将要支持自动支付 Apple Pay 商户令牌 将得到 American Express Discover Mastercard 和 Visa 的支持 未来还将支持其他支付网络 我们也将引入订单跟踪 以提升购后体验 iOS 16 新增了订单跟踪功能 以便用户跟踪与商家下的订单 现在 钱包能提供直观的概览 展示正在进行中的订单 最近完成的订单 和历史订单 现在展示的是 正在进行中的烘焙食品订单 这个订单仍在处理中 稍后再谈这个话题 现在 我想在 Pet Avenue 给我的猫 买一些玩具和配饰 我选择使用 Apple Pay 结账 在我授权付款后不久 我收到一条通知 在钱包中跟踪我的订单 点击该通知 可以看到订单的详细信息 我可以检查当前状态 可以看到订单状态 包括物流运输和跟踪信息 以及我订购的订单项列表 接下来 我有多种联系方式 可以联系 Pet Avenue 检查付款信息 然后返回 Pet Avenue App 好了 想象一下 Pet Avenue 处理新订单的速度非常快 他们刚刚运送了我的物品 Pet Avenue 发货后 他们已更新了可用信息 我可以看到状态更改为“在路上” 预计到货日期为 6 月 10 日 页面还包含一条自定义消息 以及货件的跟踪信息 哦 还记得我的烘焙食品吗? 我刚收到通知 他们可以取货了 让我们来看一下 我订购了自提的烘焙食品 我已经可以取货了 太好了 Bake My Breath Away 提供了我的取货窗口 取货说明 和取货时需出示的条形码 我们已经知道了 订单跟踪与 Apple Pay 无缝衔接 让我们看看如何将订单跟踪 集成到客户体验中 要开始订单跟踪 首先 您必须在开发者帐户中 创建一个 Order Type ID Order Type ID 将您的组织标识为 提供订单信息的实体 您可以注册多个 Order Type ID 例如 代表多个商家 提供订单信息 然后 创建一个 Order Type ID 证书 您将使用证书来构建 订单包和更新订单 订单以订单包的形式分发 订单包包括订单的 所有元数据和信息 订单包可以代表广泛的场景 包括运输 取货和多重履行订单 订单包也包括图像 比如您的徽标和行式项目图片 您还可以添加本地化 以支持不同范围的客户 每个订单包都必须经过加密签名 以验证订单包来源 一切就绪后 订单包被压缩以进行分发 请查看这个讲座附带的 示例订单包 有关订单包的更多信息 请参阅开发人员文档 将订单添加到 钱包 可与 Apple Pay 无缝协作 当您的客户授权付款时 您的应用或网页将接收到支付信息 然后将支付信息 发送到服务器进行处理 如果支付信息处理成功 您的服务器会创建 一个订单和一些元数据 然后 服务器返回订单细节 到 App 或网页 以显示结果 订单详细信息使设备能够以异步方式 从服务器请求订单 然后 服务器将订单包返回给设备 当服务器创建订单时 分配一个 Order ID 这个 ID 在 Order Type ID 命名空间中 不可与其他重复 您的服务器还必须生成 安全的身份验证令牌 身份验证令牌是共享密钥 是订单详细信息的一部分 当设备请求订单时 将使用令牌来验证这个设备 让我们来看一个 返回支付授权结果的例子 当您的客户授权付款时 App 将付款信息发送到服务器 并要求服务器创建一个订单 请检查服务器结果是否表示成功 并处理服务器返回的任何错误 如果服务器结果确实表明成功 则使用适当的授权结果 完成付款 要返回包含订单详细信息的 支付授权结果 首先 从服务器结果中 提取订单详细信息 然后创建一个 PKPaymentOrderDetails 对象 这个对象带有 Order Type ID 或 Order ID 到服务器的 URL 和身份验证令牌 将 PKPaymentOrderDetails 对象 分配到 PKPaymentAuthorizationResult 上的 新 orderDetails 属性 这样就完成了 您也可以在网页上使用 订单详细信息完成付款 和刚才一样 从服务器结果中提取订单详细信息 然后在完成支付的数据中 列入订单细节 要更新订单 创建一个指示支持 自动更新的订单包 添加订单后 设备将注册订单的更新 您的服务器必须存储有关注册的信息 以后 当服务器更新订单时 使用注册信息通知 已注册更新订单的设备 当设备收到推送通知时 设备将再次向您的服务器请求订单 然后 服务器将更新后的订单包 返回给设备 只有您和您的客户 才可知道客户订购了什么 我们在设计订单跟踪时 考虑到了客户隐私 订单信息直接在 设备和服务器之间交换 订单通过 iCloud 同步时 内容是端到端加密的 请遵循这些做法 以为客户提供最好的体验 将您的应用与您提供的订单关联起来 如果您的应用提供通知并已安装应用 您可以禁用订单跟踪通知 这么做可以防止重复通知 利用您对客户偏好的了解 只提供相关的本地化内容 请注意订单包的大小 尽量减小订单包 以降低昂贵的网络成本 当您更新订单时 及时通知已注册更新的设备 钱包中的订单 应与订单的实际状态相匹配 还要确保检查 HIG 以进行订单跟踪 平台可以使订单跟踪的集成 更加简单 我们很高兴地宣布 Shopify 及 Narvar 和 Route 将在今秋支持订单跟踪 请留意未来几个月 更多支持订单跟踪的平台 订单跟踪是增强客户 购后体验的好方法 通过自动更新 您的客户将能及时了解 他们订单的最新状态 我们相信您的客户会喜欢这种体验 我们期待能尽快向您订购产品 接下来 David 将继续讲座 David:谢谢 Lais 我非常高兴能与大家聊一聊 我们在 iOS 16 的钱包中 添加了 ID 的新功能 今年早些时候 我们在 iOS 15.4 中 推出了钱包中的 ID 美国境内支持这个功能的各州 用户能将驾照或身份证添加到钱包 钱包中的 ID 是由 发行实体身份证的机构发行 在美国 就是各州的机动车管理局 或同等机构 在 iOS 16 中 我们增加了一个新的 API 允许 App 和 App Clips 从钱包中的 ID 请求信息 以验证用户的年龄或身份 您的 App 将请求信息 用户会审查并批准请求 然后 App 会将响应发送到服务器 进行解密和验证 您可以从用户 ID 请求许多数据元素 包括他们的姓名、地址 出生日期、照片 也叫肖像 颁发身份证件的颁发机构 身份证号码和有效期 以及 如果有的话 用户的的身份证件 授予的驾驶特权 ID 的常见的用例 是验证用户的年龄 查看实体身份证 能够看到用户出生日期 但要验证用户年龄 具体出生日期是不必要的 如果要验证我的年龄 实际上不需要知道 我出生的确切日期或年份 甚至不需要知道我多少岁 只需要知道我是否达到年龄标准 使用钱包中的 ID 您可以直接验证年龄 您的应用可以请求布尔数据元素 表明用户是否超过一定年龄 这种验证年龄的方式 比查看具体出生日期更保护隐私 当您的应用调用 API 时 用户会收到一张表单 显示您在请求什么信息 表单还会显示您是否打算 存储这些信息 以及您打算存储多长时间 这样 用户可以更明智地决定 是否与您的 App 共享信息 用户使用 Face ID 或 Touch ID 明确批准之前 设备不会共享信息 您收到的响应仅包含 您请求的元素 其他身份验证机制 比如扫描实体身份证 会共享身份证上的所有信息 把共享信息限制在您需要的范围内 钱包中的 ID 更能保护用户的隐私 并减少您需要在服务器上储存的 敏感信息数量 响应由 ID 的颁发机构签名 这样就可以直接验证 响应中的信息是否真实 请注意 ID 是由颁发机构创建 但在调用 API 时 颁发机构并不参与 颁发机构不知道用户何时共享信息 也不知道用户向谁共享了信息 要使用 API 您需要通过 开发者帐户请求授权 然后 您需要设置商户 ID 和加密证书 这个过程与使用 Apple Pay 设置应用内支付 非常相似 稍后我们将详细讨论 如何使用 ID 和证书 现在 我们来看看验证流程 概括地说 包括四个步骤 首先 您的应用将调用 PassKit 框架中的 API 并指定您正在请求的信息 然后 系统将显示一个表单 提示用户批准请求 用户通过请求后 您的 App 将收到一个加密的响应 然后 应用会将该响应传递给服务器 进行解密和验证 首先 来看看如何使用 PassKit 中的 API 如果您的应用使用 SwiftUI 您应该使用 VerifyIdentityWithWalletButton SwiftUI 视图 这里会显示一个按钮 按下时触发身份验证流程 就像“使用 Apple Pay 支付” 和“添加航空通票到钱包”按钮一样 “使用钱包验证身份”按钮 提供了一个熟悉的 一致的 使用 API 的 App 体验 有四种不同的标签供您选择 以显示适合您的用例的按钮 按钮会根据可用空间自动切换 单行和多行的按钮 创建按钮时 您需要指定一个 PKIdentityRequest 对象 这个对象描述您希望请求的信息 以及应该如何返回它 让我们来看看如何创建按钮 首先创建一个 PKIdentityDriversLicenseDescriptor 它描述了您需要的 数据元素 使用 addElements 方法 指定您想请求的元素 以及您是否打算存储元素 您可以多次调用 addElements 方法 指定具有不同的存储意图的 不同的元素集 在这个例子中 我调用了两次 首先 添加一个 “年龄至少 18 岁”元素 这个元素不会被存储 然后 再次调用 addElements 方法 来请求用户的名字 姓氏和肖像 所有元素都可以存储长达 30 天 然后描述符进入 PKIdentityRequest 下一步是指定要使用的商户标识符 商户标识符表示 API 响应将加密到的 加密证书 您将通过您的开发者帐户 配置商家标识符及其加密证书 最后 您需要指定一个随机数 它将绑定到 从 API 接收的响应 这是一项重要的安全功能 用于防止响应重放 并将其绑定到特定的用户会话 具体如何管理随机数 取决于您自己的安全需求 通常 它来自您的服务器 因为稍后 您的服务器将负责执行 随机数是有效的 设置所有这些属性后 PKIdentityRequest 就准备好了 现在 我们再回到按钮部分 如果身份验证可用 这个按钮将显示在您的 App 中 点击它将启动与您的请求的 身份验证流程 如果身份验证不可用 则将显示您指定的回退视图 例如 如果这款 iPhone 上的 钱包中没有 ID 就会发生这种情况 您可以使用回退视图 提供其他方式来验证身份 我们假设身份验证是可用的 用户点击按钮 系统会显示一张表单 上面有您的请求 其中包括您请求的元素 以及您存储元素的意图 用户可以通过 Face ID 或 Touch ID 批准请求 或不批准并关闭表单 然后您的代码将收到一个结果对象 其中包含请求的结果 如果请求受到批准 您将收到成功结果 结果带有一个包含加密响应的 PKIdentityDocument 对象 App 将发送给服务器 进行解密和验证 如果请求不成功 您会收到一个失败的结果 最常见的失败原因 是请求未获批准 在这种情况下 您将收到“取消”的错误 以上就是 VerifyIdentityWithWalletButton SwiftUI 版本的 API 您可以用它来显示按钮 用按钮启动身份验证流程 并请求钱包中的 ID 信息 如果您的应用中 没有使用 SwiftUI 您还可以使用 PKIdentityButton 和 PKIdentityAuthorizationController 类 来完成相同的流程 好了 现在您请求到了信息 用户批准了请求 App 向服务器发送了 加密的响应 现在 我们来看看服务器需要做什么 来解密和验证响应 我只会大致地略微聊聊这个话题 那么 请查看开发人员文档 以获取更多详细信息 响应格式使用多个国际标准 所以我强烈建议您 也熟悉这些标准 您将收到的响应数据 位于 CBOR 编码的加密信封中 CBOR RFC 8949 中定义的数据格式 类似于 JSON 但使用二进制数据对对象进行编码 加密信封包含解密过程 所需的元数据 连同加密数据本身 数据使用 HPKE 加密 HPKE 是 RFC 9180 中 定义的加密方案 您的服务器将使用私钥解密数据 解密后 您将获得 一个 mdoc 响应对象 mdoc 响应的定义 在 ISO 18013 第 5 部分 这是移动驾驶执照 和州 ID 的 ISO 标准 mdoc 响应对象包含 您请求的数据元素 还包括许多服务器需要验证的 安全特性 以确保响应是真实的 请注意 您的服务器将执行解密 和验证服务器本身 Apple 服务器 和发行机构的服务器 都不会参与其中 在讨论解密 和响应验证之前 我们需要讨论会话记录 这是一个 CBOR 结构 它将响应负载绑定到 来自特定 App 的特定请求 您的服务器将需要构建此结构 并在解密和验证期间使用它 会话记录包含您之前在 PKIdentityRequest 中 使用的同一个随机数和商户 ID 以及您的开发团队的团队 ID 以及您的加密证书的公钥的 SHA256 散列 在构建会话记录时 服务器应该检查您正在使用的输入 都是有效的 这意味着随机数不应该已经被使用 而应该被绑定到当前用户 其他值应该与您的开发者帐户上 所期望的值相匹配 现在我们来聊聊解密加密数据 您需要刚刚创建的会话记录 以及来自加密信封的元数据 您还需要个人密钥 这是与您之前 在开发者帐户中 设置的证书相对应的个人密钥 为保护用户信息的机密性 您需要确保个人密钥保持私有 安全存储在您的服务器上 并且永远不要储存在 App 中 如果您的个人密钥泄露 请立即撤销开发者帐户中的证书 解密加密数据后 您将收到一个 mdoc 响应对象 包含两个加密签名 以及您要求的数据元素 您需要检查 mdoc 响应中的两个签名 然后才能使用它的数据元素 首先 您需要检查颁发者签名 这是用户 ID 颁发机构的 签名 通过检查这个签名 您正在验证响应中的数据 来自真正的发证机关 并且没有被篡改 您应该检查签名不仅是有效的 而且签名是由 您信任的颁发者证书签署的 查看文档 了解关于 钱包中 ID 使用的 颁发者证书的更多详细信息 接下来 您需要验证设备签名 这是由用户 iPhone 的 Secure Element 中的 密钥创建的签名 这说明您收到的回复来自 发卡机构最初发给您 ID 的 那台 iPhone 在这里 您需要再次使用会话记录 以及颁发者签名所涵盖的一些信息 最后 可以使用请求的 数据元素了 在没有首先验证颁发者 和设备签名之前 永远不要使用这些元素 否则您不知道您收到的数据 是否真实 完成所有这些步骤后 就完成了 您的应用已经请求了信息 并且您的服务器已经解密 并验证了响应 您可能想知道如果 在钱包中没有 ID 如何测试您的设置 我们提供了一些机制来帮助您 首先 您可以在 iOS 模拟器中测试 模拟器中的 API 将返回一个模拟响应 测试的响应类似于真实的响应 但没有真正的签名 同样 您可以使用测试配置文件 在真正的 iPhone 上 接收模拟响应 哪怕 iPhone 上的钱包中 没有 ID 也可以做到 关于如何执行这项操作的 更多详细信息 请参阅文档 请注意 您的服务器不应该将 像处理真实响应一样处理模拟响应 要帮助您设置服务器 文档中还有一个示例响应 以及解密和验证所需要的一切 这就是在 iOS 16 中 使用钱包中 ID 进行身份验证的方式 我们讨论了如何 在您的应用中使用 API 如何处理服务器上的响应 以及如何测试您的设置 Lais:今年我们为 钱包和 Apple Pay 推出了很多很棒的新功能 新功能包括多商户支付 改进了对自动支付的支持 订单跟踪和身份验证 请查看开发者文档 以了解更多信息 David:感谢您的收看 希望您在 WWDC 体验愉快 ♪
-
-
2:39 - AddPassToWalletButton
@State var addedToWallet: Bool @ViewBuilder private var airlineButton: some View { if let pass = createAirlinePass() { AddPassToWalletButton([pass]) { added in addedToWallet = added } .frame(width: 250, height: 50) .addPassToWalletButtonStyle(.blackOutline) } else { // Fallback } }
-
3:40 - PayWithApplePayButton
// Create a payment request let paymentRequest = PKPaymentRequest() // ... // Create a payment authorization change method func authorizationChange(phase: PayWithApplePayButtonPaymentAuthorizationPhase) { ... } PayWithApplePayButton( .plain, request: paymentRequest, onPaymentAuthorizationChange: authorizationChange ) { // Fallback } .frame(width: 250, height: 50) .payWithApplePayButtonStyle(.automatic)
-
6:34 - Multi-merchant payments
// Create a payment request let paymentRequest = PKPaymentRequest() // ... // Set total amount paymentRequest.paymentSummaryItems = [ PKPaymentSummaryItem(label: "Total", amount: 500) ] // Create a multi token context for each additional merchant in the payment let multiTokenContexts = [ PKPaymentTokenContext( merchantIdentifier: "com.example.air-travel", externalIdentifier: "com.example.air-travel", merchantName: "Air Travel", merchantDomain: "air-travel.example.com", amount: 150 ), PKPaymentTokenContext( merchantIdentifier: "com.example.hotel", externalIdentifier: "com.example.hotel", merchantName: "Hotel", merchantDomain: "hotel.example.com", amount: 300 ), PKPaymentTokenContext( merchantIdentifier: "com.example.car-rental", externalIdentifier: "com.example.car-rental", merchantName: "Car Rental", merchantDomain: "car-rental.example.com", amount: 50 ) ] paymentRequest.multiTokenContexts = multiTokenContexts
-
10:14 - Automatic Payments - Recurring payment request
// Specify the amount and billing periods let regularBilling = PKRecurringPaymentSummaryItem(label: "Membership", amount: 20) let trialBilling = PKRecurringPaymentSummaryItem(label: "Trial Membership", amount: 10) let trialEndDate = Calendar.current.date(byAdding: .month, value: 1, to: Date.now) trialBilling.endDate = trialEndDate regularBilling.startDate = trialEndDate // Create a recurring payment request let recurringPaymentRequest = PKRecurringPaymentRequest( paymentDescription: "Book Club Membership", regularBilling: regularBilling, managementURL: URL(string: "https://www.example.com/managementURL")! ) recurringPaymentRequest.trialBilling = trialBilling recurringPaymentRequest.billingAgreement = """ 50% off for the first month. You will be charged $20 every month after that until you cancel. \ You may cancel at any time to avoid future charges. To cancel, go to your Account and click \ Cancel Membership. """ recurringPaymentRequest.tokenNotificationURL = URL( string: "https://www.example.com/tokenNotificationURL" )! // Update the payment request let paymentRequest = PKPaymentRequest() // ... paymentRequest.recurringPaymentRequest = recurringPaymentRequest // Include in the summary items let total = PKRecurringPaymentSummaryItem(label: "Book Club", amount: 10) total.endDate = trialEndDate paymentRequest.paymentSummaryItems = [trialBilling, regularBilling, total]
-
12:39 - Automatic Payments - Automatic reload payment request
// Specify the reload amount and threshold let automaticReloadBilling = PKAutomaticReloadPaymentSummaryItem( label: "Coffee Shop Reload", amount: 25 ) reloadItem.thresholdAmount = 5 // Create an automatic reload payment request let automaticReloadPaymentRequest = PKAutomaticReloadPaymentRequest( paymentDescription: "Coffee Shop", automaticReloadBilling: automaticReloadBilling, managementURL: URL(string: "https://www.example.com/managementURL")! ) automaticReloadPaymentRequest.billingAgreement = """ Coffee Shop will add $25.00 to your card immediately, and will automatically reload your \ card with $25.00 whenever the balance falls below $5.00. You may cancel at any time to avoid \ future charges. To cancel, go to your Account and click Cancel Reload. """ automaticReloadPaymentRequest.tokenNotificationURL = URL( string: "https://www.example.com/tokenNotificationURL" )! // Update the payment request let paymentRequest = PKPaymentRequest() // ... paymentRequest.automaticReloadPaymentRequest = automaticReloadPaymentRequest // Include in the summary items let total = PKAutomaticReloadPaymentSummaryItem( label: "Coffee Shop", amount: 25 ) total.thresholdAmount = 5 paymentRequest.paymentSummaryItems = [total]
-
19:17 - Order Tracking (swift)
func onAuthorizationChange(phase: PayWithApplePayButtonPaymentAuthorizationPhase) { switch phase { // ... case .didAuthorize(let payment, let resultHandler): server.createOrder(with: payment) { serverResult in guard case .success(let orderDetails) = serverResult else { /* handle error */ } let result = PKPaymentAuthorizationResult(status: .success, errors: nil) result.orderDetails = PKPaymentOrderDetails( orderTypeIdentifier: orderDetails.orderTypeIdentifier, orderIdentifier: orderDetails.orderIdentifier, webServiceURL: orderDetails.webServiceURL, authenticationToken: orderDetails.authenticationToken, ) resultHandler(result) } } }
-
20:13 - Order Tracking (JS)
paymentRequest.show().then((response) => { server.createOrder(response).then((orderDetails) => { let details = { }; if (response.methodName === "https://apple.com/apple-pay") { details.data = { orderDetails: { orderTypeIdentifier: orderDetails.orderTypeIdentifier, orderIdentifier: orderDetails.orderIdentifier, webServiceURL: orderDetails.webServiceURL, authenticationToken: orderDetails.authenticationToken, }, }; } response.complete("success", details); }); });
-
27:05 - VerifyIdentityWithWalletButton 2
@ViewBuilder var verifiyIdentityButton: some View { VerifyIdentityWithWalletButton( .verifyIdentity, request: createRequest(), ) { result in // ... } fallback: { // verify identity another way } }
-
27:18 - Create a PKIdentityRequest
func createRequest() -> PKIdentityRequest { let descriptor = PKIdentityDriversLicenseDescriptor() descriptor.addElements([.age(atLeast: 18)], intentToStore: .willNotStore) descriptor.addElements([.givenName, .familyName, .portrait], intentToStore: .mayStore(days: 30)) let request = PKIdentityRequest() request.descriptor = descriptor request.merchantIdentifier = // configured in Developer account request.nonce = // bound to user session }
-
27:19 - VerifyIdentityWithWalletButton 3
@ViewBuilder var verifiyIdentityButton: some View { VerifyIdentityWithWalletButton( .verifyIdentity, request: createRequest(), ) { result in // ... } fallback: { // verify identity another way } }
-
29:37 - VerifyIdentityWithWalletButton 4
@ViewBuilder var verifiyIdentityButton: some View { VerifyIdentityWithWalletButton( .verifyIdentity, request: createRequest(), ) { result in switch result { case .success(let document): // send document to server for decryption and verification case .failure(let error): switch error { case PKIdentityError.cancelled: // handle cancellation default: // handle other errors } } } fallback: { // verify identity another way } }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。