스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
지갑 및 Apple Pay의 새로운 기능
지갑 및 Apple Pay의 최신 업데이트를 확인하세요. 앱과 웹 사이트에서 지갑을 이용한 주문을 지원하는 방법과 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입니다 그리고 저는 David입니다 우리가 발표할 내용은 지갑과 Apple Pay에서의 올해 새로운 기능들입니다 우린 2014년에 Apple Pay를 출시해서 상점과 온라인과 앱 내에서 빠르고 안전하고 사적인 지불을 만드는 데 있어서 새 벤치마크를 확립했습니다 그 후로 우린 전 세계로 Apple Pay를 확대했습니다 Apple Pay는 현재 72군데의 국가 및 지역에서 이용 가능하고 매일 백만 건이 넘는 거래를 처리하고 있습니다 오늘 우린 지갑과 Apple Pay에 들어가는 흥미진진한 새 기능과 API를 소개하겠습니다 Lais가 자세히 알려드릴 겁니다 고마워요, David 오늘의 주요 논제를 살펴보죠 먼저 간단한 업데이트를 설명하겠습니다 단일 거래에서 다수의 상인에 대한 지불을 위한 지원을 추가합니다 또한 구독을 포함한 자동 지불에 대한 지원을 크게 개선합니다 주문 추적으로 여러분은 고객들을 위한 구매 후 체험을 향상시킬 수 있습니다 그리고 마지막으로 데이비드가 지갑 내 ID로 하는 신분 확인에 관해 설명하겠습니다 말씀드릴 흥미진진한 업데이트가 몇 가지 있습니다 iPhone의 Tap to Pay가 올해 초에 발표됐고 미국에서는 iOS 15.4에서 출시되었습니다 iPhone의 Tap to Pay는 비접촉 지불을 받기 위한 안전하고 사적이고 편리한 방법을 제공합니다 여러분은 그걸 여러분의 앱에 쉽게 통합시켜서 비접촉 지불을 매끄럽고 안전하게 받을 수 있습니다 그것에는 Apple Pay와 비접촉 신용 및 현금 카드와 다른 디지털 지갑들이 포함됩니다 거래는 iPhone에서의 간단한 1회 탭으로 완료되어 추가 하드웨어나 지불 터미널의 필요가 없어졌습니다 한편 macOS 13에서 우린 Apple Pay 체험을 재디자인했습니다 작년의 iOS 지불 시트 재디자인은 크게 성공했습니다 올해 우린 macOS에 유사한 체험을 도입합니다 우린 SwiftUI를 써서 그걸 실행했는데 그건 iOS와 동시에 macOS에 새 기능을 도입하는 데 도움이 됐습니다 오늘 우리가 소개하는 모든 Apple Pay 기능은 Mac에서도 지원됩니다 우린 새로운 SwiftUI API를 소개합니다 Add to Apple 지갑이나 SwiftUI 앱에서의 Apple Pay 버튼 통합이 훨씬 쉬워집니다 이 새로운 API들은 여러분이 작성해야 할 코드의 양을 크게 줄여줄 겁니다 버튼을 추가해서 사용자가 항공권을 추가하도록 유도할 수 있는 방법을 살펴보죠 먼저 항공권을 만듭니다 여러분은 그것의 로딩이 실패했던 경우를 처리해야 합니다 그건 항공권 데이터가 잘못 형성됐거나 예를 들어 서명이 제대로 안 됐을 때 일어날 수 있죠 다음으론 항공권 배열로 AddPass ToWalletButton을 호출합니다 이 사례에는 요소가 하나뿐인 배열이 있는데 동일한 버튼에 항공권이 다수가 있어도 됩니다 그 결과는 Bool로 전달되고 여러분은 앱의 다른 동작들을 저장하고 기록하고 촉발할 수 있습니다 사용자가 항공권을 추가했는지의 여부를 바탕으로요 이 사례에서 저는 그걸 상태 변수에 저장합니다 그게 다예요 또한 여러분은 버튼 크기와 스타일을 최소 값들의 집합 내에서 맞춤화할 수 있습니다 이건 기본 설정입니다 너비 250, 높이 50이죠 여러분은 그걸 더 넓게 아니면...
더 높게 할 수도 있습니다
여기까지 여러분이 SwiftUI에 Add to Apple 지갑 버튼을 추가할 수 있는 방법이었습니다 그럼 이제 Apple Pay 버튼으로 Pay를 추가하는 방법을 알아보죠 먼저 지불 요청을 만듭니다 PKPaymentRequest 클래스를 쓰고 거기에 여러분의 평소 설정을 정해서요 그런 다음 authorizationChange 기법을 만듭니다 이제 이 두 가지의 준비가 완료됐으니 코드를 넣어서 버튼을 나타내죠 PayWithApplePayButton에 호출을 추가해서 레이블과 paymentRequest object와 authorizationChange 기법을 전달해 넣습니다 현재 기기에서 Apple Pay가 지원되지 않는 경우를 처리하기 위해 대체 뷰를 전달해 넣을 수 있습니다 Add Pass 버튼처럼 여러분은 그 크기와 스타일을 맞춤화할 수 있습니다 모두 합쳐 레이블은 17가지라서 여러분은 지불 버튼을 맞춤화해서 여러분의 이용 사례에 일치하게 할 수 있습니다 그것들은 iOS, iPadOS, macOS watchOS에서 이용 가능합니다 그럼 이제 다수 상인 지불을 살펴보죠 iOS 16에서는 동일한 거래에서 서로 다른 상인들에게 다수의 지불 토큰을 요청할 능력을 도입합니다 이건 온라인 시장, 여행 예약 티켓 서비스 등에 유용합니다 한 가지 사례를 자세히 살펴보죠 Allison이 여행을 계획한다고 생각합시다 Allison이 여행사 웹 사이트로 가보니 그쪽에선 Allison이 예약하는 데 필요한 모든 걸 편리하게 제공합니다 항공권, 호텔 숙박권 렌트카까지 말이죠 Allison은 총 500달러만 지불하면 됩니다 Allison은 여행사에 자신의 신용 카드 전체 정보를 제공합니다 이제 여러분은 이렇게 생각할 수 있죠, 여행사가 Allison의 신용 카드사에 500달러를 청구하고 연관된 다른 업체들에 비용을 지불할 거라고요 하지만 일반적으로 일어나는 일은 여행사가 신용 카드 정보를 각각의 업체에 전달해서 그들이 개별적으로 청구하게 하는 겁니다 그건 효과가 있지만 Allison의 개인 정보와 보안에 아주 좋진 않습니다 그 신용 카드 정보가 여기저기 공유되거든요 이제 새로운 다수 상인 지불 API로 하나의 거래에 관련된 각각의 상인을 위해 지불 토큰을 요청하는 게 가능합니다 이 지불 토큰을 사용해서 관련된 다수의 업체는 Allison이 승인한 관련 금액을 각각 그녀에게 청구할 수 있습니다 Allison은 이제 여행을 예약하고 비용을 지불하는 동시에 Apple Pay가 제공하는 개인 정보 보호 및 보안 혜택을 누릴 수 있습니다 지불 시트는 업데이트되어 고객들에게 거래에 관련된 하위 상인들의 내역을 보여줍니다 고객들은 총계 필드를 두드려서 지불 요약으로 찾아갈 수 있습니다 여기에서 고객은 거래와 관련된 모든 상인의 내역을 볼 수 있습니다 상인별로 승인된 금액도 함께 볼 수 있습니다 그럼 이제 여러분의 앱에 다수 상인 지불을 추가할 수 있는 방법을 살펴보죠 먼저 지불 요청을 만듭니다 PKPaymentRequest 클래스를 사용해서요 거기에 여러분의 평소 설정을 정합니다 그리고 총액을 포함하여 지불의 요약 항목들을 추가합니다 다음으로 거래와 관련된 상인별 지불 토큰 맥락을 하나씩 만듭니다 새로운 PKPayment TokenContext 클래스를 사용해서요 각 상인에 대한 세부 사항을 제공합니다 각자에게 승인할 금액도 함께요 마지막으로 지불 요청에 지불 토큰 맥락을 정합니다 명심할 점은 여러분의 지불 토큰 맥락 전부에 대한 금액의 총합은 지불 요청의 총액보다 작거나 그것과 같아야 한다는 겁니다 또한 동일한 상인에 대해 동일한 외부 식별자를 써야 한다는 겁니다 여러분 앱의 그 상인에 대한 지불 토큰을 요청할 때마다요 Apple Pay로 인터넷에서 다수 상인 지불을 채택하려면 Apple Pay JS API 문헌을 확인해보세요 그럼 자동 지불에 대한 우리의 개선 사항들을 살펴보도록 하죠 iOS 16에서 우린 사람들이 상인들과 관련해서 구성한 자동 지불을 보고 관리하는 능력을 도입합니다 지갑 앱에서 곧바로 말이죠 이번 출시에서 우린 두 종류의 자동 지불을 지원합니다 반복 지불입니다 거기에 포함되는 건 구독료나 할부금이나 반복 청구액 같은 겁니다 그리고 자동 재적재 지불입니다 상점 카드 잔액 보충 같은 게 있습니다 우린 새 API를 도입해서 여러분이 지불 요청을 할 때 자동 지불을 구성하는 걸 요청할 수 있게 합니다 또한 우린 Apple Pay 상인 토큰을 도입합니다 그건 고객의 Apple ID에 연계된 새로운 종류의 지불 토큰으로 여러분이 지속성을 기반으로 고객들에 대한 청구를 더욱 확실하게 하는 데 도움이 될 수 있습니다 Apple Pay 상인 토큰을 더 자세히 살펴보면서 그게 유용할 수 있는 방법을 알아보죠 Julie가 iPhone의 Apple Pay를 써서 북클럽 멤버십 요금을 지불한다고 생각해봅시다 북클럽은 지불 요청을 하고 Julie가 그 지불을 승인하면 북클럽은 지불 토큰을 받고 그걸 이용해서 매달 Julie에게 멤버십 요금을 청구할 수 있습니다 이 지불 토큰은 Julie가 지불을 승인하는 데 사용한 기기와 연결되어 있습니다 그런데 Julie가 새 iPhone을 갖게 되면 어떻게 될까요? 새로운 자동 지불 기능으로 북클럽은 대신에 Apple Pay 상인 토큰을 받습니다 Julie의 지불 네트워크가 그걸 지원한다면요 이 지불 토큰은 Julie의 Apple ID와 연계되어 있습니다 그녀의 iPhone이 아니고요 그건 지속적인 승인에 있어서 보다 나은 보장을 제공합니다 이게 뜻하는 건 Julie가 자신의 iPhone을 업그레이드하거나 현재 휴대폰을 재설정해도 북클럽에선 Julie에게 월간 멤버십 요금을 확실하게 계속 청구할 수 있다는 겁니다 여러분이 이런 종류의 지불에 Apple Pay를 받는다면 자동 지불을 채택해서 고객들에게 계속해서 확실하게 청구할 수 있게 하는 건 참 좋은 생각입니다 그 서비스의 중단을 방지하는 것과 함께요 이번 출시에서 우리가 지원하는 첫 번째 종류의 자동 지불은 반복 지불입니다 반복 지불은 고정 혹은 변동 금액으로 정기적인 일정으로 청구됩니다 가령 주간, 월간, 연간이 있습니다 이런 지불은 특정 일자에 종료되거나 취소될 때까지 계속될 수 있습니다 체험 기간이나 도입 기간도 지원됩니다 구독, 할부 구매 정기적인 청구가 이런 종류의 지불에 가장 잘 맞는 사용입니다 그럼 자동 지불을 사용해서 여러분의 앱에서 반복 지불을 구성할 수 있는 방법을 살펴보죠 먼저 반복 지불의 금액과 기간을 명시합니다 PKRecurringPaymentSummaryItem 클래스를 써서요 반복 지불의 경우 여러분은 정기적인 청구 기간과 체험 혹은 도입 기간을 명시할 수 있습니다 여러분은 startDate와 endDate 속성을 이용해서 체험 기간이 언제 끝나는지와 정기 청구 기간이 언제 시작되는지 표시할 수 있습니다 다음으론 반복 지불 요청을 만드세요 새로운 PKRecurringPaymentRequest 클래스를 써서요 제공할 건 지불에 대한 설명과 정기 청구 기간과 웹 페이지로 가는 관리 URL입니다 고객이 반복 지불에 대한 지불 방법을 업데이트하거나 삭제할 수 있는 페이지 말이죠 여러분은 선택에 따라 체험 청구 기간과 함께 청구 동의 텍스트도 제공해서 고객에게 지불 조건을 설명하게 할 수 있습니다 마지막으로 선택에 따라 토큰 공지 URL을 제공할 수 있는데 거기에서 서버는 지불을 위한 Apple Pay 상인 토큰에 대한 수명 주기 공지를 받을 수 있습니다 토큰이 발행됐다면요 예를 들어 카드 발행사나 사용자가 토큰을 삭제하면 여러분은 공지를 받을 수 있습니다 상인 토큰 수명 주기 공지에 관한 더 자세한 정보가 필요하면 Apple Pay Merchant Token Management API 문헌을 보세요 마지막으로 반복 지불 요청을 paymentRequest 객체에 정하세요 요약 항목들에 관해 짧게 덧붙이자면 반복 지불은 지불 요청의 요약 항목들에 자동으로 추가되지 않습니다 그러니 그것에 대한 항목들을 요약 항목 배열에 꼭 추가하세요 지불 요청의 총액은 고객이 청구받을 최초 금액이 되어야 합니다 따라서 이 사례에서 총액은 체험 기간 금액을 표시하도록 정해져 있습니다 그게 고객이 청구받을 최초 금액이니까요 지불 시트는 고객들에게 반복 지불의 세부 사항을 보여주고 그들은 Billing Details 섹션을 두드려서 자세한 걸 읽을 수 있습니다 이제 이번 출시에서 우리가 지원하는 두 번째 종류의 자동 지불을 살펴봅시다 자동 재적재 지불입니다 이런 종류의 지불의 경우 잔액이 고정 금액으로 자동 보충됩니다 잔액이 특정 기준 금액 아래로 떨어질 때마다요 자동 재적재 지불은 상점 카드 보충과 사전 지불 잔액 같은 것에 딱 좋습니다 자동 재적재 지불 구성을 요청하려면 먼저 재적재 및 기준 금액을 명시하세요 새로운 PKAutomaticReloadPayment SummaryItem 클래스를 써서요 다음으로 자동 재적재 지불 요청을 만드세요 새로운 PKAutomaticReload PaymentRequest 클래스를 써서요 지불에 대한 설명과 청구와 관리 URL을 전달해 넣어서요 반복 지불의 경우처럼요 여러분은 역시 선택에 따라 청구 동의 텍스트와 토큰 공지 URL을 제공할 수 있습니다 마지막으로 지불 요청 객체에 자동 재적재 지불 요청을 정하세요 이번에도 자동 재적재 지불을 요약 항목들에 반드시 포함시키고 지불 요청의 총액을 적절하게 정하세요 인터넷에서 Apple Pay로 자동 지불을 채택하는 것에 관해선 Apple Pay JS API 문헌을 확인해보세요 이건 여러분의 고객용 지불 시트에 자동 재적재 지불이 나타나는 모습입니다 마지막으로 이건 고객들에게 가능한 최고의 체험을 선사하기 위해 기억해야 할 몇 가지입니다 여러분이 앱에 자동 지불을 채택할 때요 잊지 말고 자동 지불을 위한 요약 항목들을 포함시키세요 그것들은 추가되지 않으니까요 여러분의 지불 요청 총액은 고객에게 청구될 최초 금액이 되어야 합니다 여러분은 청구 동의 텍스트를 짧게 해야 합니다 지불 시트는 처음 500글자만 보여줄 겁니다 청구 동의 텍스트는 여러분의 일반 청구 및 법적 합의를 대신하기 위한 게 아닙니다 여러분 지역의 반복 청구 법률을 준수하는 건 여러분에게 달려 있습니다 고객에게 보여줄 법적 합의문이 여러분에게 있으면 그건 지불 시트를 제시하기 전에 고객에게 합의문을 보여줘야 한다는 뜻일 수 있습니다 여러분은 단일 거래에서 한 종류의 자동 지불만을 요청할 수 있습니다 또한 자동 지불은 다수 상인 지불과 함께 사용될 수 없습니다 마지막으로 여러분이 지불에 대해 발행된 Apple Pay 상인 토큰에 대한 수명 주기 공지를 받고 싶다면 토큰 공지 URL을 반드시 제공하고 서버에 있는 Apple Pay Merchant Token Management API를 채택하세요 이 새 API들과 Apple Pay 상인 토큰의 혜택들을 여러분이 참 좋아할 거라고 믿습니다 이건 자동 지불에 대한 지원을 채택할 우리 파트너들 중 일부입니다 Apple Pay 상인 토큰을 지원할 곳은 American Express, Discover, Mastercard, Visa이고 앞으로 다른 지불 네트워크에 대한 지원도 있을 예정입니다 우린 구매 후 체험을 향상시킬 주문 추적을 도입하게 되어 기쁩니다 iOS 16에 새로 나온 주문 추적은 사용자들이 참여 상인들에게 했던 주문을 추적할 수 있게 해줍니다 지갑은 이제 진행 중인 주문과 최근 완료된 주문과 과거 주문에 대한 직관적인 개요를 제공합니다 저한텐 현재 제빵 제품에 대한 진행 중인 주문이 하나 있습니다 그 주문은 아직 처리 중인데요 나중에 다시 알아보겠습니다 저는 일단 Pet Avenue에서 제 고양이를 위한 장난감과 액세서리를 구입하고 싶습니다 저는 Apple Pay로 결제하기를 선택했습니다 제가 지불을 승인하고 얼마 안 지나 저는 지갑에서 주문 추적을 위한 공지를 받습니다 그 공지와 상호 작용을 하다 보면 제 주문의 세부 사항으로 가게 되는데요 거기에서 저는 현재 상태를 확인할 수 있습니다 주문 상태를 볼 수 있습니다 배송 및 추적 정보와 제가 주문한 품목명의 목록을 포함해서요 더 아래엔 Pet Avenue에 연락하고 지불 정보를 확인하고 Pet Avenue 앱으로 돌아가는 다수의 옵션이 있습니다 이제 Pet Avenue에서 들어오는 주문의 처리를 아주 빨리 해서 제 물건들을 방금 발송했다고 가정해보죠 Pet Avenue에서 제 주문을 발송하자마자 이용 가능한 정보를 업데이트했습니다 '배송 중'으로 상태가 바뀐 게 보이죠 동시에 예상 전달 일자는 6월 10일입니다 그쪽에선 맞춤형 메시지와 배송 관련 추적 정보도 포함시켰습니다 제 제빵 제품 기억하시죠? 그걸 방문 수령 해도 된다는 공지를 방금 받았습니다 확인해보죠 저는 제빵 제품을 방문 수령으로 주문했습니다 수령할 준비가 됐네요 아주 좋습니다 Bake My Breath Away는 제 방문 수령 창과 방문 수령 지시 사항과 제가 도착했을 때 제시할 바코드를 제공했습니다 Apple Pay로 주문 추적이 매끄럽게 작동되는 걸 봤습니다 여러분이 주문 추적을 고객 체험에 통합할 수 있는 방법을 살펴보죠 주문 추적을 시작하려면 먼저 여러분의 개발자 계정에 Order Type ID를 만들어야 합니다 Order Type ID는 여러분의 조직을 주문 정보를 제공하는 개체로 식별합니다 여러분은 다수의 Order Type ID를 등록할 수 있습니다 예를 들어 다수의 상인을 대신해서 주문 정보를 제공하기 위해서죠 또한 Order Type ID Certificate을 만드세요 여러분은 그 인증서를 써서 주문 패키지를 구축하고 주문을 업데이트합니다 주문은 주문 패키지로 배포됩니다 주문 패키지에는 주문에 대한 모든 메타데이터와 정보가 포함됩니다 그건 광범위한 상황을 나타낼 수 있습니다 배송, 방문 수령 다수 처리 주문들을 포함해서요 주문 패키지에는 이미지도 포함됩니다 가령 여러분의 로고나 품목명 이미지처럼요 로컬라이제이션도 추가해서 폭넓고 다양한 고객들을 지원할 수 있습니다 모든 주문 패키지는 암호화 서명되어 그 출처를 입증해야 합니다 일단 모든 게 자리를 잡으면 주문 패키지는 배포를 위해 압축됩니다 이 세션에 첨부된 샘플 주문 패키지를 확인하세요 그리고 주문 패키지에 관한 추가 정보가 필요하면 개발자 문헌을 보세요 주문을 지갑에 추가하는 건 Apple Pay로 매끄럽게 잘 됩니다 여러분의 고객이 지불을 승인했을 때 여러분의 앱이나 웹 페이지는 지불 정보를 받은 다음 처리를 위해 그걸 여러분의 서버로 보냅니다 지불 정보 처리가 성공하면 여러분의 서버는 주문과 메타데이터를 만듭니다 그런 다음 그 주문에 관한 세부 사항을 여러분의 앱이나 웹 페이지로 돌려줘서 결과에 포함시킵니다 주문 세부 사항은 기기가 여러분의 서버로부터 그 주문을 비동기로 요청할 수 있게 합니다 그럼 여러분의 서버는 주문 패키지를 기기에 돌려줍니다 여러분의 서버가 주문을 만들면 여러분 Order Type ID의 네임 스페이스 내에 고유한 Order ID를 지정하세요 여러분의 서버는 안전한 인증 토큰도 생성해야 합니다 그건 공유된 비밀로 주문 세부 사항의 일부입니다 기기는 주문을 요청할 때 그 토큰을 써서 스스로를 인증합니다 지불 인증 결과를 되돌려주는 것의 사례를 한 가지 살펴보죠 여러분의 고객이 지불을 인증했을 때 여러분의 앱은 지불 정보를 서버로 보내주고 그것에 주문을 만들어달라고 요청합니다 서버 결과가 성공을 나타내는지 확인하고 서버가 돌려주는 모든 오류를 처리하세요 서버 결과가 성공을 나타내면 적절한 승인 결과로 지불을 완료하세요 주문 세부 사항과 함께 지불 승인 결과를 되돌려주려면 먼저 그걸 서버 결과에서 추출하세요 그런 다음 PKPaymentOrderDetails 객체를 만드세요 Order Type ID와 Order ID와 여러분의 서버로 가는 URL과 인증 토큰으로요 PKPaymentOrderDetails 객체를 PKPaymentAuthorizationResult의 orderDetails 속성에 지정하세요 됐습니다 주문 세부 사항이 있는 지불은 인터넷에서도 완료할 수 있습니다 이전처럼 서버 결과에서 주문 세부 사항을 추출합니다 그리고 여러분이 지불을 완료하는 데이터에 주문 세부 사항을 포함시키세요 주문을 업데이트할 수 있으려면 자동 업데이트를 위한 지원을 표시하는 주문 패키지를 만드세요 주문이 추가되면 기기는 그것에 대한 업데이트에 등록됩니다 여러분의 서버는 등록 관련 정보를 저장해야 합니다 나중에 여러분의 서버가 주문을 업데이트하면 등록 정보를 사용해서 그것에 대한 업데이트에 등록된 기기들에 공지하세요 기기가 푸시 알림을 받으면 여러분의 서버에서 주문을 다시 요청합니다 여러분의 서버는 업데이트된 주문 페키지를 기기로 되돌려줍니다 여러분의 고객과 여러분만이 뭘 주문했는지 알아야 합니다 개인 정보 보호를 염두에 두고 우린 주문 추적을 디자인했습니다 주문 정보는 기기들과 여러분의 서버 사이에서 직접 교환됩니다 주문이 iCloud를 통해 동기화되면 그건 종단간 암호화됩니다 이런 관례를 따라서 가능한 최고의 고객 체험을 제공하세요 여러분의 앱을 여러분이 제공하는 주문과 연관 지으세요 여러분의 앱이 공지를 전달하고 설치됐으면 여러분은 주문 추적 공지를 해제할 수 있습니다 이는 중복 공지를 예방하는 데 도움이 됩니다 고객 선호에 관한 여러분의 지식을 이용해서 의미 있는 로컬라이제이션만 제공하세요 주문 패키지의 크기에 유의하세요 크기를 작게 유지하려 노력해서 부담되는 네트워킹 비용을 줄이세요 여러분이 주문을 업데이트할 때 그것에 대한 업데이트에 등록된 기기들에 즉시 알리세요 지갑에 있는 주문은 그 주문의 실제 상태와 일치해야 합니다 주문 추적을 위한 HIG도 반드시 확인하세요 플랫폼은 주문 추적의 통합을 훨씬 간단하게 해줄 수 있습니다 Shopify, Narvar, Route가 올 가을 전에 주문 추적을 지원할 거란 걸 발표하게 되어 기쁩니다 앞으로 몇달 동안 주문 추적 지원 플랫폼들이 늘어나는 모습을 주목하세요 주문 추적은 여러분 고객들의 구매 후 체험을 향상시킬 아주 좋은 방법입니다 자동 업데이트로 고객들은 자신의 주문 상태에 관한 최신 정보를 항상 갖고 있습니다 우린 여러분의 고객들이 이 체험을 아주 좋아할 걸로 보고 여러분과 함께 조만간 주문하길 기대합니다 이제 David에게 발표를 넘기죠 고마워요, Lais iOS 16의 지갑 내 ID에 우리가 추가한 새 기능을 설명하게 되어 무척 기쁩니다 우린 올해 초 iOS 15.4에서 지갑 내 ID를 출시했습니다 그건 지원되는 미국 주들의 사용자들이 운전 면허증이나 주 신분증을 지갑에 추가할 수 있게 해줍니다 지갑 내 ID는 사용자들의 물리적 신분증을 발행한 기관과 동일한 곳에서 발행합니다 미국에서 그건 그들 주의 차량관리국이나 그와 동등한 조직입니다 iOS 16에서 우린 앱과 App Clip이 지갑 내 ID에 있는 정보를 요청할 수 있게 하는 새로운 API를 추가했습니다 사용자의 나이나 신분을 인증하기 위해서요 여러분의 앱은 정보를 요청하고 사용자는 요청을 검토하고 승인합니다 그리고 여러분의 앱은 암호 해독과 확인을 위해 서버에 반응을 보냅니다 여러분은 사용자의 ID에서 여러 데이터 요소를 요청할 수 있습니다 거기에 포함되는 건 그 사람의 이름, 주소 생년월일, 사진... 사진은 '포트레이트'라고도 하죠 그 ID를 발행해준 발행 기관 일련 번호, 물리적 ID의 만료 일자 그 ID가 부여하는 운전 특권입니다 그게 존재하는 경우에요 ID의 아주 흔한 이용 사례는 사람의 나이를 입증하는 겁니다 물리적 ID에서 그건 생년월일을 살펴보는 걸 뜻합니다 하지만 생년월일은 나이를 입증하기 위해 필요한 것보다 훨씬 더 많은 정보를 드러냅니다 여러분이 제 나이를 확인하는데 제가 태어난 정확한 연도나 날짜를 알 필요가 없습니다 심지어 정확히 몇 살인지도요 제가 나이 기준을 통과한다는 것만 알면 되죠 지갑 내 ID로 여러분은 그 질문을 직접할 수 있습니다 여러분의 앱은 불 데이터 요소를 요청해서 사용자가 특정 나이를 초과하는지 표시할 수 있습니다 나이를 입증할 때 생년월일 전체를 확인하는 것보다 개인 정보를 보호해주는 방식을 제공합니다 여러분의 앱이 그 API를 부르면 시트가 사용자에게 여러분이 어떤 정보를 요청하는지 보여줍니다 그건 또한 그 정보를 여러분이 저장할 의향이 있는지와 얼마나 오래 저장하고 싶은지도 보여줍니다 이는 사용자가 그 정보를 여러분의 앱에 공유할지에 관한 현명한 판단을 내릴 수 있게 해줍니다 그들의 Face ID나 Touch ID를 사용해서 명시적인 승인을 하기 전까지 어떤 정보도 공유되지 않습니다 여러분이 받는 반응에는 여러분이 요청한 요소들만 들어 있습니다 다른 신분 인증 메커니즘들은 가령 물리적 신분증 스캔은 신분증에 있는 모든 걸 공유합니다 여러분이 필요한 것만으로 공유를 제한함으로써 지갑 내 ID는 사용자를 위한 개인 정보 보호성이 더 강하고 여러분의 서버에 안전하게 보관해야 하는 민감한 정보의 양을 줄여줍니다 반응은 ID 발행 기관이 서명해서 반응에 있는 정보가 진본이라는 점의 확인을 간단하게 해줍니다 주의할 점은 발행 기관이 ID를 만들지만 여러분이 그 API를 부를 때는 관여하지 않는다는 점입니다 그들은 사용자가 언제 정보를 공유하는지나 누구와 공유하는지를 알지 못합니다 그 API를 사용하려면 여러분은 자신의 개발자 계정을 통해 자격을 요청해야 합니다 그런 다음 상인 ID와 암호화 인증서를 구성해야 합니다 이 과정은 Apple Pay로 앱 내 지불을 구성하는 것과 매우 유사합니다 ID와 인증서 사용법에 관해서는 잠시 후에 자세히 설명하겠습니다 지금은 확인 흐름을 설명하죠 높은 수준에서 보면 그건 4단계로 이루어집니다 첫째, 여러분의 앱은 PassKit 프레임워크의 API를 부르고 여러분이 요청하는 정보를 명시합니다 그런 다음 시스템은 사용자에게 그 요청의 승인을 유도하는 시트를 보여줍니다 일단 그렇게 했으면 여러분의 앱은 암호화된 반응을 수신합니다 그런 다음 여러분의 앱은 암호 해독과 확인을 위해 그 반응을 여러분의 서버에 전달합니다 먼저 PassKit에서 API를 사용하는 방법을 설명하죠 여러분의 앱이 SwiftUI를 쓰면 여러분은 이걸 쓸 겁니다 VerifyIdentityWithWalletButton SwiftUI 뷰를요 이건 누르면 신분 확인 흐름을 촉발하는 버튼을 보여줍니다 Pay with Apple Pay와 Add Pass to Wallet 버튼처럼 Verify Identity with Wallet 버튼은 그 API를 쓰는 앱들에 친숙하고 일관된 체험을 제공합니다 여러분은 네 가지 레이블 중에서 하나를 골라 여러분의 이용 사례에 적합한 버튼을 보여줄 수 있습니다 그건 단일 및 다중 라인 버전 사이에서 자동으로 바뀝니다, 그것이 이용 가능한 공간에 따라서요 그 버튼을 만들 때 여러분은 PKIdentityRequest 객체를 명시해야 합니다 그건 여러분이 요청하고 싶은 정보와 그게 되돌려져야 할 방법을 설명합니다 그걸 만드는 방법을 살펴보죠 이걸 만들어서 시작합니다 PKIdentity DriversLicenseDescriptor입니다 그건 여러분이 찾고 있는 데이터 요소들을 설명합니다 addElements 기법을 써서 여러분이 요청하고 싶은 요소들을 명시하세요 여러분에게 그걸 저장할 의향이 있는지도요 여러분은 addElements 기법을 여러 번 불러서 저장할 다양한 intent가 있는 다양한 요소들의 집합을 명시할 수 있습니다 이 사례에서 저는 그걸 두 번 호출합니다 먼저 '최소 18세' 요소를 추가합니다 그건 저장되지 않을 겁니다 그리고 addElements 기법을 다시 호출해서 사용자의 이름, 성 포트레이트를 요청하는데 그 모든 건 최대 30일까지 저장될 수 있습니다 그 서술자는 PKIdentityRequest로 들어갑니다 다음 단계는 사용을 위한 상인 식별자를 명시하는 겁니다 상인 식별자가 나타내는 건 암호화 인증서로 그것에 API 반응이 암호화됩니다 여러분은 개발자 계정을 통해 상인 식별자와 그 암호화 인증서를 설정합니다 마지막으로 여러분은 임시값을 명시해야 합니다 임시값은 여러분이 API에서 수신하는 반응과 연계됩니다 그건 중요한 보안 기능으로 반응의 재생을 방지하고 그걸 특정 사용자 세션에 묶는 데 사용됩니다 임시값을 정확히 어떻게 관리할지는 여러분의 몫입니다 여러분의 보안 요건에 따라서요 그건 여러분의 서버에서 올 때가 많습니다, 이유는 나중에 여러분의 서버가 임시값이 유효하다는 걸 집행하는 일을 담당할 테니까요 그 속성들이 모두 구성되면 여러분은 PKIdentityRequest를 얻습니다 이제 버튼으로 돌아와보죠 신분 확인이 이용 가능하다면 그 버튼이 여러분의 앱에 표시됩니다 그걸 두드리면 여러분의 요청으로 신분 확인 흐름이 시작됩니다 신분 확인이 이용 불가능하다면 여러분이 명시하는 대체 뷰가 대신 표시됩니다 예를 들어 이 iPhone에 지갑 내 ID가 없으면 그런 일이 일어납니다 여러분은 대체 뷰를 사용해서 신분을 확인할 다른 방법을 제공할 수 있습니다 이렇게 가정해보죠 신분 확인이 이용 가능해서 사용자가 버튼을 누른다고요 그럼 시스템은 여러분의 요청이 있는 시트를 보여줍니다 여러분이 요청한 요소들과 그것의 저장에 관한 여러분의 의향까지 포함해서요 사용자는 Face ID나 Touch ID로 그 요청을 승인할 수 있습니다 아니면 승인 없이 시트를 닫을 수도 있습니다 그런 다음 여러분의 코드는 요청 결과를 담은 결과 객체를 받습니다 요청이 승인됐다면 여러분은 성공 결과를 받을 겁니다 이건 암호화된 반응이 포함된 PKIdentityDocument 객체와 함께 오는데 그건 암호 해독과 확인을 위해 여러분의 앱이 서버로 보내는 겁니다 요청이 실패했다면 여러분은 실패 결과를 받습니다 가장 흔한 실패 원인은 요청이 승인받지 못한 겁니다 그 경우 여러분은 취소된 오류를 받습니다 여기까지 VerifyIdentity WithWalletButton이었습니다 API의 SwiftUI 버전이죠 그걸 써서 버튼이 나타나게 하세요 신분 확인 흐름을 개시해주고 지갑 내 ID를 요청하는 버튼입니다 여러분이 자신의 앱에서 SwiftUI를 사용하지 않는다면 PKIdentityButton과 PKIdentityAuthorization Controller 클래스를 사용해서 같은 걸 해낼 수 있습니다 좋아요, 그럼 이제 여러분이 정보를 요청했고 사용자가 그 요청을 승인했고 여러분의 앱이 서버에 암호화된 반응을 전송했습니다 이제 그 반응을 해독하고 확인하기 위해 서버가 해야 할 일을 설명해보죠 저는 이 주제를 대충 훑고 지나갈 테니 자세한 내용은 개발자 문헌에서 확인해주세요 반응 형식은 몇 가지의 국제 표준을 사용하니 그것들에도 익숙해지시길 강력하게 추천합니다 여러분이 받을 반응 데이터는 CBOR로 암호화된 암호 봉투 내에 있습니다 CBOR은 RFC 8949에서 정의된 데이터 형식입니다 그건 JSON과 유사하지만 객체를 암호화하는 데 이진 데이터를 사용합니다 암호 봉투에는 암호 해독 과정에 필요한 메타데이터가 들어 있습니다 암호화된 데이터 자체와 함께요 그 데이터는 HPKE를 사용해서 암호화됩니다 HPKE는 RFC 9180에서 정의된 암호화 제도입니다 서버는 그 비밀 키를 써서 이 데이터를 해독합니다 일단 해독되면 여러분은 mdoc 반응 객체를 얻습니다 mdoc 반응은 ISO 18013 5부에 정의되어 있습니다 모바일 운전 면허증과 주 신분증의 ISO 표준이죠 mdoc 반응 개체에는 여러분이 요청한 데이터 요소들이 들어 있습니다 거기에는 여러분의 서버가 인증해야 하는 여러 보안 기능도 포함됩니다 반응이 진본이란 걸 보장해주기 위해서요 주의할 점은 여러분의 서버가 암호 해독과 인증을 직접 수행한다는 겁니다 Apple 서버와 발행 기관의 서버는 둘 다 관련이 없습니다 암호 해독과 반응 인증을 설명하기 전에 세션 기록 얘기를 해야 합니다 이것은 CBOR 구조로 반응 페이로드를 특정 앱에서의 특정 요청에 묶어줍니다 여러분의 서버는 이 구조를 구축하고 해독 및 인증 도중에 그걸 사용해야 합니다 세션 기록엔 앞에서 PKIdentityRequest에서 썼던 것과 동일한 임시값과 상인 ID가 들어 있습니다 여러분 개발 팀의 ID와 암호화 인증서 공개 키의 SHA256 해시도 들어 있고요 세션 기록을 구축할 때 서버는 여러분이 쓰는 입력들이 모두 유효하다는 걸 확인해야 합니다 그건 임시값이 이미 사용되지 않았어야 하며, 현재 사용자와 연계되어 있어야 한다는 뜻입니다 다른 값들은 여러분의 개발자 계정에서 예상되는 것과 일치해야 합니다 이제 암호화된 데이터를 해독하는 걸 설명해보죠 여러분에게 필요한 건 방금 만든 세션 기록과 암호 봉투에 있는 메타데이터입니다 여러분의 비밀 키도 필요합니다 이게 비밀 키입니다 앞에서 여러분의 개발자 계정에서 구성한 인증서에 대응되는 키죠 사용자 정보의 비밀을 보호하기 위해 여러분은 비밀 키의 기밀이 유지되게 해야 합니다 그걸 서버에 안전하게 보관하고 여러분의 앱에 포함시키지 마세요 여러분의 비밀 키가 혹시라도 유출되면 여러분의 개발자 계정에 있는 인증서를 즉시 삭제하세요 암호화된 데이터의 해독한 후 여러분은 mdoc 반응 개체를 받습니다 거기에는 두 개의 암호법 서명과 함께 여러분이 요청한 데이터 요소들이 있습니다 여러분은 mdoc 반응에 있는 두 개의 서명을 모두 확인한 다음 그 데이터 요소들을 사용할 수 있습니다 먼저 여러분은 발행자 서명을 확인해야 합니다 그건 사용자 ID를 발행한 기관의 서명입니다 이 서명을 확인함으로써 여러분은 반응에 있는 데이터가 실제 발행 기관에서 나왔다는 점과 조작되지 않았다는 점을 인증하는 겁니다 여러분은 그 서명이 유효할 뿐만 아니라 신뢰하는 발행자 인증서의 서명이 있다는 걸 확인해야 합니다 지갑 내 ID가 사용하는 발행자 인증서에 관한 자세한 내용은 문헌을 찾아보시기 바랍니다 다음으로 여러분은 기기 서명을 확인해야 합니다 이건 사용자 iPhone의 Secure Element에 있는 키가 만든 서명입니다 그건 여러분이 받은 반응이 발행 기관이 그 ID를 원래 발행해줬던 것과 동일한 iPhone에서 왔다는 걸 증명해줍니다 여기에서 여러분은 세션 기록을 다시 사용해야 합니다 발행자 서명이 보장해주는 몇 가지 정보와 함께요 마침내 여러분이 요청했던 데이터 요소들을 사용할 준비가 됐습니다 여러분은 먼저 발행자 및 기기 서명을 확인한 다음에만 이 요소들을 사용해야 합니다 안 그러면 여러분이 받은 데이터가 진본인지 알 수 없으니까요 그 단계들을 모두 완료했으면 다 된 겁니다 여러분의 앱은 그 정보를 요청했고 서버는 암호 해독을 했고 반응을 확인했습니다 여러분의 지갑에 ID가 없다면 자신의 실행을 테스트할 방법이 궁금할 수도 있습니다 여러분이 그걸 할 수 있게 우리가 몇 가지 메커니즘을 제공했습니다 먼저 여러분은 iOS Simulator에서 API가 모의 반응을 어디로 돌려줄지 테스트할 수 있습니다 이 반응은 실제와 유사하지만 거기엔 진짜 서명이 없습니다 유사하게 여러분은 테스트 프로파일을 써서 진짜 iPhone에서 모의 반응을 받을 수 있습니다 그 iPhone에 지갑 내 ID가 없더라도요 이 방법에 관한 자세한 내용이 필요하면 문헌을 찾아보세요 주의할 점은 여러분의 서버가 이 모의 반응 중 하나라도 진짜처럼 취급하면 안 된다는 겁니다 여러분의 서버 실행을 돕기 위해 문헌에는 본보기 반응과 함께 그걸 해독하고 인증하는 데 여러분에게 필요한 모든 것도 포함되어 있습니다 여기까지 iOS 16에서 지갑 내 ID로 신분 확인을 수행하는 방법이었습니다 우리가 설명한 건 여러분의 앱에서 그 API를 쓰는 방법과 그 반응을 여러분의 서버에서 처리하는 방법과 여러분의 실행을 테스트하는 방법이었습니다 올해 우리는 지갑과 Apple Pay에 다양하고 멋진 새 기능을 도입했습니다 그것에 포함되는 건 다수 상인 지불과 자동 지불에 대한 개선된 지원 주문 추적, 신분 확인입니다 더 자세한 정보가 필요하면 개발자 문헌을 확인해보세요 시청해주셔서 감사합니다 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 } }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.