ハイライト
iOS 16 では、SwiftUI ボタン、マルチマーチャント支払い、自動控除、注文追跡、Wallet と Apple Pay 用の Wallet 認証 API が追加され、アプリが支払い承認、注文ステータス、および ID データ要求を同じ PassKit プロセスに統合できるようになります。
主要内容
通常、支払いは単独のアクションではありません。
旅行プラットフォームは、航空会社、ホテル、レンタカー会社の間で注文を分割する必要があります。ユーザーが携帯電話を変更した後も、サブスクリプション サービスは引き続き引き落とされます。電子商取引企業は、支払い後に配送、集荷、アフターセールスのステータスをユーザーに同期する必要があります。年齢確認を必要とするアプリでは、完全な生年月日、ID 番号、写真の収集も避ける必要があります。
このセッションでは、これらのシナリオを Wallet と Apple Pay の間の同じリンクに組み込みます。 Apple は、iOS 16 に、SwiftUI ネイティブ ボタン、マルチマーチャント支払い、自動控除、ウォレット注文追跡、ウォレット内の ID からの ID データのリクエストという 5 つのカテゴリの機能を追加しました。
最初の変更は小さいですが、日々の開発に影響を与えます。 Apple Wallet への追加、Apple Pay での支払い、Wallet での ID の確認にはすべて SwiftUI の入り口があります。ボタンはシステムの一貫した外観を表示する役割を果たし、開発者はリクエスト オブジェクトとコールバックを提供するだけで済みます。
2 番目の変更は、複雑なトランザクションに向けたものです。複数の販売者による支払いでは、1 つの Apple Pay 認証で複数の支払いトークンを生成できます。ユーザーには合計価格と販売者の分割が表示され、販売者は完全なカード番号を互いに渡すことなく独自のトークンを取得できます。
3 番目の変更は長期控除を対象としています。 Apple Pay 販売者トークンは、支払いを開始するデバイスではなく、Apple ID にバインドされます。ユーザーが iPhone をアップグレードまたはリセットした後も、対象となる加盟店はユーザーの許可に従って引き続き請求を行うことができます。
4 番目の変更では、支払い済みの注文がウォレットに追加されます。販売者が注文の詳細を返した後、デバイスは販売者サーバーから注文パッケージを非同期にプルします。注文が更新されると、サーバーは登録されたデバイスに再度プルするように通知します。
5 番目の変更は認証です。アプリは、ウォレット内の ID の特定のフィールドをリクエストすることも、「18 歳以上かどうか」のブール結果のみをリクエストすることもできます。ユーザーはシステム シートでリクエストを確認します。承認後、アプリは暗号化された応答を取得し、復号化と検証のためにサーバーに渡されます。
詳細
SwiftUI の Wallet ボタンと Apple Pay ボタン
(02:39) 以前は、SwiftUI に Wallet ボタンを配置する場合、UIKit コントロールをブリッジし、可用性、スタイル、コールバックを自分で処理するのが一般的でした。 iOS 16で利用可能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
}
}
キーポイント:
@State var addedToWalletユーザーが追加を完了したかどうかを保存します。これは、後でインターフェイスを更新したりステータスを記録したりするために使用できます。 -createAirlinePass()失敗するかもしれない。逐語的には、パスデータの形式が不正であるか、正しく署名されていない場合に、失敗したパスを処理することに言及しています。 -AddPassToWalletButton([pass])受信パス配列。この例には要素が 1 つだけありますが、複数のパスを配置することもできます。- 閉鎖中
addedシステムから返されるブール値の結果です。 -.frame(width: 250, height: 50)セッションに表示されるデフォルトのサイズを使用します。 -.addPassToWalletButtonStyle(.blackOutline)ボタンのスタイルを設定します。 -elseこのブランチは、パスを作成できない場合にインターフェイスに出口がないことを防ぐためのフォールバックです。
(03:40) 支払いボタンの SwiftUI バージョンもあります。まずは準備をPKPaymentRequest、その後、認可ステータスの変更を に引き渡します。onPaymentAuthorizationChange対処する。
// 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)
キーポイント:
PKPaymentRequest()依然として支払い設定の中心的なオブジェクトです。 -authorizationChange引き継ぐPayWithApplePayButtonPaymentAuthorizationPhase、承認プロセスにおけるステータスの変更を処理するために使用されます。 -PayWithApplePayButton(.plain, request: ...)ボタンのコピー、支払いリクエスト、承認コールバックをまとめます。- 現在のデバイスが Apple Pay をサポートしていない場合、フォールバック クロージャが使用されます。
-
.payWithApplePayButtonStyle(.automatic)システムに適切なスタイルを選択させます。 - 逐語的には、Pay ボタンには 17 のラベルがあり、iOS、iPadOS、macOS、watchOS をサポートしていると述べられています。
1 つのトランザクションで複数のマーチャント トークンが生成される
(04:38) 複数の販売者による支払いは、市場、旅行、発券などの集合的なトランザクションを解決します。ユーザーには合計価格が 1 つだけ表示されますが、実際には複数の受取人が存在します。以前は、このプラットフォームは完全なクレジット カード情報を各販売者に送信する可能性があり、プライバシーとセキュリティにとって良くありませんでした。
(06:34) iOS 16 が行うことは、PKPaymentTokenContext、そして同じにハングアップしますPKPaymentRequest優れた。
// 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
キーポイント:
paymentSummaryItemsまず、ユーザーが承認する合計金額を設定します。ここでは 500 です。- それぞれ
PKPaymentTokenContext追加の販売者について説明します。 -merchantIdentifier販売者 ID です。 -externalIdentifier同じ販売者に対しては安定したままである必要があります。逐語的な草案では、同じ販売者がトークンを要求するたびに同じ値を使用することが明確に要求されています。 -merchantNameそしてmerchantDomainビジネス情報を表示するために使用されます。 -amount販売者によって承認される金額です。 -paymentRequest.multiTokenContextsこのコンテキストを支払いリクエストに追加します。 - すべてのトークン コンテキストの金額の合計は、支払いリクエストの合計以下である必要があります。
自動引き落とし: サブスクリプションと自動リチャージ
(07:36) 自動控除に関する中心的な問題は、長期的な承認です。通常の支払いトークンはデバイスに関連しています。ユーザーが iPhone を変更するかデバイスをリセットすると、販売業者のその後の控除が中断される場合があります。 iOS 16 では Apple Pay 加盟店トークンが導入されています。決済ネットワークがサポートしている場合は、ユーザーの Apple ID にバインドされ、継続的な控除のためのより安定した認証基盤を提供できます。
(10:14) サブスクリプション、分割払い、定期請求の使用PKRecurringPaymentRequest。この例では、まず試用期間と正式なアカウント期間を作成し、次に定期的なリクエストをPKPaymentRequest。
// 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]
キーポイント:
PKRecurringPaymentSummaryItem定期課金を説明する表示項目。 -trialBilling.endDate試用期間の終了時刻をマークします。 -regularBilling.startDate正式な控除開始時刻をマークします。 -PKRecurringPaymentRequest支払いの説明、正式な請求期間、管理ページの URL を受け取ります。 -managementURLユーザーが支払い方法を更新または削除できるページを指す必要があります。 -trialBillingオプションの試用アカウント期間があります。 -billingAgreementチャージバック条件を説明するには短いテキストを使用します。支払いシートへの逐語的な参照では、最初の 500 文字のみが表示されます。 -tokenNotificationURL発行銀行またはユーザーによってトークンが削除されるなど、マーチャント トークンのライフ サイクル通知をサーバーが受信できるようにします。 -paymentRequest.recurringPaymentRequest自動引き落としリクエストを支払いリクエストに追加します。- 定期的な支払いでは集計項目は自動的に追加されないため、開発者は手動で追加する必要があります。
-
totalユーザーが初めて引き落とされる金額が表示されます。ここでは試用期間の金額 10 が表示されます。
(12:39) 自動リチャージはストアド バリュー カードおよびプリペイド残高に適しています。残高がしきい値を下回ると、システムは固定金額に従ってリチャージします。
// 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]
キーポイント:
PKAutomaticReloadPaymentSummaryItemオートチャージ金額について説明します。 -thresholdAmountリチャージをトリガーする残高のしきい値です。 -PKAutomaticReloadPaymentRequest支払いの説明、自動リチャージ項目、管理ページの URL を受け取ります。 -billingAgreement即時チャージ金額や発動基準、解約方法を解説。 -tokenNotificationURL定期支払いなどの販売者トークンのライフサイクル通知に使用されます。 -paymentRequest.automaticReloadPaymentRequestこの支払いには自動リチャージ承認が必要であることを示します。- 集計項目は手動で設定する必要があります。
- 草案は逐語的に次のようにも述べています: 取引に対して要求できる自動控除は 1 種類のみであり、自動控除は複数の加盟店の支払いでは使用できません。
ウォレット注文追跡
(15:14) 支払い後、ユーザーが最も気になるのは注文状況です。 iOS 16 のウォレット注文追跡では、アクティブな注文、最近完了した注文、および過去の注文に加えて、配送、受け取り期間、バーコード、販売者の連絡先情報、アプリに戻るためのエントリ ポイントを表示できます。
(17:08) 統合する前に、開発者はアカウントに注文タイプ ID と証明書を作成する必要があります。注文は、注文メタデータ、画像、ローカライズされたリソースを含む注文パッケージで配布され、圧縮して配布する前に暗号化および署名する必要があります。
(19:17) アプリ内で Apple Pay を使用すると、支払いが正常に処理された後、サーバーは注文の詳細を返します。クライアントはこれらの詳細をPKPaymentAuthorizationResult.orderDetails。
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)
}
}
}
キーポイント:
onAuthorizationChangeApple Pay 認証ステータスの変更を処理します。 -.didAuthorizeステージで手に入れましょうpaymentそしてresultHandler。server.createOrder(with: payment)支払い情報をサーバーに渡して処理します。 -guard case .success(let orderDetails)サーバーが注文を正常に作成したことを確認します。 -PKPaymentAuthorizationResult(status: .success, errors: nil)支払いの承認が成功したことを示します。 -PKPaymentOrderDetails注文タイプ ID、注文 ID、サーバー URL、および認証トークンが含まれます。 -authenticationTokenこれは、その後注文パッケージを要求するときにデバイスによって使用される共有秘密です。 -result.orderDetailsiOS 16の新たな入り口です。 -resultHandler(result)認証結果の返却を完了します。
(20:13) Web ページでは、支払い完了時に注文の詳細を渡すこともできます。
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);
});
});
キーポイント:
paymentRequest.show()Web 支払いリクエストのプロセスを示します。 -server.createOrder(response)サーバー側でオーダーを作成します。 -details決済完了時にブラウザに返されるデータです。 -response.methodName === "https://apple.com/apple-pay"現在の支払い方法が Apple Pay であることを確認します。 -details.data.orderDetails4 つのフィールドは、PKPaymentOrderDetails。response.complete("success", details)支払いを完了し、注文の詳細をシステムに送信します。
注文の更新も販売者のサーバーに送信されます。注文パッケージが自動更新のサポートを宣言した後、デバイスは更新のために登録されます。販売者が注文を更新すると、登録情報をデバイスに通知します。通知を受信した後、デバイスは最新の注文パッケージを再度要求します。この文書には、注文情報がデバイスと販売者のサーバー間で直接交換され、iCloud に同期された注文情報がエンドツーエンドで暗号化されることが逐語的に記載されています。
ウォレットの ID から ID データをリクエストします
(23:10) iOS 16 では、アプリとアプリ クリップがウォレット内の運転免許証または州 ID から情報を要求できるようになります。この API の目標は、機密データの収集を減らすことです。たとえば、年齢確認には完全な誕生日は必要なく、リクエストのみが必要です。age(atLeast:)ブール値の結果。
(27:05) SwiftUI は使用しますVerifyIdentityWithWalletButtonプロセスを開始します。ユーザーが ID をウォレットに追加しなかった場合など、利用できない場合のフォールバックを提供します。
@ViewBuilder var verifiyIdentityButton: some View {
VerifyIdentityWithWalletButton(
.verifyIdentity,
request: createRequest(),
) { result in
// ...
} fallback: {
// verify identity another way
}
}
キーポイント:
VerifyIdentityWithWalletButtonSwiftUIのエントリーポイントです。 -.verifyIdentityボタンのラベル タイプの 1 つです。 -request: createRequest()供給PKIdentityRequest。- 結果クロージャーは、ユーザーの承認またはキャンセル後に結果を受け取ります。
- フォールバック クロージャは、認証が利用できないシナリオで使用されます。
(27:18) リクエスト オブジェクトは、記述子、マーチャント識別子、およびノンスで構成されます。記述子は、要求されるデータ要素と、それらの要素が保存されるかどうかを指定します。
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
}
キーポイント:
PKIdentityDriversLicenseDescriptor()ドキュメントからどのようなデータを要求するかを説明します。- 最初のグループ
addElements「18歳以上ですか」とリクエストし、保存しない旨を明記してください。 - グループ 2
addElements名前、姓、肖像画を要求し、最長 30 日間保存できると述べています。 -PKIdentityRequest()ボタンに渡されるリクエスト オブジェクトです。 -request.descriptorバインドデータリクエストの説明。 -merchantIdentifier開発者アカウントで構成された販売者 ID と暗号化証明書を指定します。 -nonce現在のユーザー セッションにバインドし、応答のリプレイを防ぐために使用されます。通常、逐語的な提案はサーバーによって生成され、検証されます。
(29:37) ユーザーが承認すると、アプリは次のメッセージを受け取ります。PKIdentityDocument、復号化と検証のためにサーバーに送信する必要があります。失敗の一般的な原因は、ユーザーによるキャンセルです。
@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
}
}
キーポイント:
.success(let document)ユーザーの承認を示します。document暗号化された応答が含まれます。- 注釈では、復号化と検証のためにドキュメントをサーバーに送信することが明示的に要求されます。
-
.failure(let error)プロセスが失敗したことを示します。 -PKIdentityError.cancelledこれは、ユーザーがリクエストを承認しない場合の一般的な失敗経路です。 - フォールバックは、API が利用できないシナリオにも引き続き対応します。
(30:46) 暗号化と署名はサーバー側で処理されます。応答は、HPKE を使用して暗号化された、CBOR でエンコードされた暗号化エンベロープです。サーバーは秘密キーを使用してそれを復号化し、ISO 18013-5 で定義された mdoc 応答を取得します。データを使用する前に、サーバーは発行者の署名とデバイスの署名を検証します。 Apple サーバーと発行局サーバーはこのステップには関与しません。
重要ポイント
-
旅行パッケージの支払いページを作成: 航空券、ホテル、レンタカーを複数に分割します
PKPaymentTokenContext。このようにして、ユーザーは合計価格のみを承認し、各販売者は独自の支払いトークンを取得して、販売者間で完全なカード番号が送信されることを回避します。 -
会員登録による Apple Pay の自動引き落とし: を使用します
PKRecurringPaymentRequestトライアル期間、公式アカウント期間、管理ページ、トークン通知アドレスを記載します。サーバーは Apple Pay Merchant Token Management API に接続して、トークンの削除などのライフサイクル イベントを処理します。 -
コーヒーカードの自動リチャージ: 使用する
PKAutomaticReloadPaymentRequestそしてPKAutomaticReloadPaymentSummaryItemチャージ金額としきい値を設定します。残高がしきい値を下回ると、ユーザーの承認に従って自動的にリチャージされ、ウォレットに管理入り口が提供されます。 -
電子商取引注文のウォレット追跡: 注文タイプ ID と証明書を作成し、支払いが成功した後に返却します
PKPaymentOrderDetails。サーバーは署名付きの注文パッケージを生成し、出荷時、受け取り可能時、完了時に更新するようにデバイスに通知します。 -
より少ないデータ収集で年齢確認を行う: を使用します。
PKIdentityDriversLicenseDescriptor聞く.age(atLeast: 18)、と置きますintentToStoreに設定.willNotStore。サーバーは暗号化された応答と署名のみを検証し、完全な生年月日は保存しません。
関連セッション
- アプリ内購入の新機能 — Apple Pay の自動引き落としとの比較に適した、支払いエクスペリエンス、トランザクション ステータス、StoreKit 2 に焦点を当てます。
- StoreKit テストの新機能 - 支払いプロセスのローカル検証リンクを完了するのに適した、購入およびサブスクリプションのテスト ツールを紹介します。
- アプリ内購入の統合と移行を検討する — サーバー側の API と通知の移行について説明し、ウォレットの注文とマーチャント トークンのサーバー側の処理を補完します。
- パスキーについて - また、システムレベルの ID と資格情報のセキュリティに関しても、機密情報の公開を減らすという Apple の設計方向性を理解するのに適しています。
コメント
GitHub Issues · utterances