상세 컨텐츠

본문 제목

[애플월렛 패스] 참가증, 쿠폰, 티켓같은 패스 만들어 애플월렛에 넣어보기

iOS 캐기/토이 프로젝트

by Atlas 2023. 11. 17. 14:07

본문

728x90
반응형

시나리오 : 컨퍼런스 참가증을 애플월렛으로 받아서 유니크하고 Apple-like한 느낌을 받았다는 소식을 듣고 해보기로 결심했다. 
참고로 Apple 월렛 패스는 지갑 앱을 통해 다양한 카드, 포인트, 쿠폰, 탑승권, 티켓 등을 한 곳에 저장하고 사용하는 기능이다.
 
준비물 : 인증서가 필요해서 Apple Membership가입이 필수요소이다.


이번 포스팅은 로컬에서 패스를 생성하는 포스팅입니다. 서버 API로 패스를 생성하려고 한다면 아래의 포스팅을 참고 부탁드립니다.

2024.08.12 - [iOS 캐기/토이 프로젝트] - [애플월렛 패스] 참가증, 쿠폰, 티켓같은 패스 서버 API 호출로 생성하기- 개발환경 세팅

2024.08.12 - [iOS 캐기/토이 프로젝트] - [애플월렛 패스] 참가증, 쿠폰, 티켓같은 패스 서버 API 호출로 생성하기- 구조 작성

2024.08.12 - [iOS 캐기/토이 프로젝트] - [애플월렛 패스] 참가증, 쿠폰, 티켓같은 패스 서버 API 호출로 생성하기-기능구현

2024.08.13 - [iOS 캐기/토이 프로젝트] - [애플월렛 패스] 참가증, 쿠폰, 티켓같은 패스 서버 API 호출로 생성하기- 인증서 관련 작업 정리

 

한줄요약

폴더를 하나 생성하고 pass.json 파일을 생성하고 필요한 내용을 넣어주고 이미지도 필요하면 넣어주고 해당 폴더를 zip 파일로 압축하고 확장자를 .pkpass 로 변경하고 실행하면 된다.(feat. 인증서관련 작업은 zip파일 압축할 때 필요하다.)
 
한줄요약으로 보면 간단해 보이지만 생각보다 손이가는 부분도 있기에 차근차근 진행해보자. 
 

Let's Deep dive

패스 생성하기 

출처 : https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html#//apple_ref/doc/uid/TP40012195-CH4-SW1

 
패스를 생성하기 위해서는 아래와 같은 디렉토리 구조로 소스파일과 이미지를 추가하여 정의할 수 있다. 
- 아이콘 / 로고와 같은 이미지 파일 
- 패스에 표시하는 문자열과 패스를 정의하는 메타데이터가 포함된 pass.json 
- 로컬라이제이션도 추가할 수 있다.
 
지원하는 패스스타일은 5종류이다. 
 

출처 : https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html#//apple_ref/doc/uid/TP40012195-CH4-SW1

 

출처 : https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html#//apple_ref/doc/uid/TP40012195-CH4-SW1
출처 : https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html#//apple_ref/doc/uid/TP40012195-CH4-SW1
출처 : https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html#//apple_ref/doc/uid/TP40012195-CH4-SW1
출처 : https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html#//apple_ref/doc/uid/TP40012195-CH4-SW1
출처 : https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html#//apple_ref/doc/uid/TP40012195-CH4-SW1

 
 
이처럼 패스스타일에 따라서 전면에 표현할 수 있는 필드의 수가 결정된다. 
* 텍스트가 너무 많으면 일부 필드는 표시되지 않을 수도 있다고 한다 * 

1. pass.json

구성요소들을 알아보자.

{
    "formatVersion" : 1,
    "passTypeIdentifier" : "pass.com.yourdomain.atlasevent",
    "serialNumber" : "001",
    "teamIdentifier" : "<YOUR TEAM IDENTIFIER>",
    "organizationName" : "Atlas Labs",
    "description" : "test event coupon"
}

 
json에 필수로 들어가야하는 키,밸류 이다. 

타입 설명
formatVersion 정수 파일형식버전, 문자열을 제공하면 파일이 검증되지 않는다.
passTypeIdentifier 문자열 패스의 식별자, iOS의 번들아이디와 유사하다
serialNumber 문자열 패스의 일련번호 , 문자와 숫자조합으로도 자유롭게 생성가능
teamIdentifier 문자열 Apple 멤버쉽 가입하게되면 할당받는 고유한 10자리 식별자
organizationName 문자열 발행한 엔티디의 이름 
description 문자열 패스에 대한 간단한 설명

 

{

....
     "logoText" : "아틀라스 1일 이용권" ,
     "foregroundColor" : "rgb(255, 255, 255)" ,
     "BackgroundColor" : "rgb(100, 100, 100)" ,
     "labelColor" : "rgb(20, 20 , 20)"

}

 

타입 설명
logoText 문자열 로고 이미지 옆에 패스 헤더에 표시되는 텍스트
foregroundColor 문자열 텍스트색
backgroundColor 문자열 패스의 배경색
labelColor 문자열 레이블색

 

{
    ....
    "barcode" : {
             "message" : "바코드 메시지" ,
             "format" : "PKBarcodeFormatPDF417" ,
             "messageEncoding" : "iso-8859-1"
      }
}

 

타입 설명
message 문자열 바코드에 포함하려는 데이터 , 고유코드 또는 전달자의 클라이언드 ID등이 될 수 도 있다.
format 문자열 바코드 형식 이름 (PKBarcodeFormatQR, PKBarcodeFormatPDF417, PKBarcodeFormatAztec 중 택 1)
messageEncoding 문자열 메시지를 디코등하는데 사용되는 텍스트 인코딩의 이름 latin1이 아닌 언어를 사용하는 경우 UTF8 또는 자신에게 적합한 다른 텍스트 인코딩을 사용하는 것이 좋다.(영어,숫자를 사용하는경우 기본값은 ios-8859-1)

 
 

    "coupon" : { // 패스종류 5가지 제공 coupon/storeCard/boardingPass/generic/eventTicket
    
           "primaryFields" : [
           {
           "key" : "필드 이름",
           "label" : "레이블",
           "value" : "표현되는 값"
           }
       ]

    }

 

타입 설명
key 문자열 필드 이름 
label 문자열 필드에 수반되는 레이블 
value 문자열 필드에 표현되는 텍스트 

 
 
더 많은 필드들을 확인하기 위해서는 레퍼런스를 확인하는 것을 권장합니다! 
https://developer.apple.com/library/archive/documentation/UserExperience/Reference/PassKit_Bundle/Chapters/TopLevel.html

 

Top-Level Keys

Top-Level Keys The top level of the pass.json file is a dictionary. The following sections list the required and optional keys used in this dictionary. For each key whose value is a dictionary or an array of dictionaries, there is also a section in Lower-L

developer.apple.com

 

전면 pass.json

{
    "formatVersion" : 1,
    "passTypeIdentifier" : "pass.atlas.event",
    "serialNumber" : "XD",
    "teamIdentifier" : "팀아이디",
    "barcodes" : [
        {
            "message" : "https://www.udemy.com/user/imdongju-2/",
            "format" : "PKBarcodeFormatQR",
            "messageEncoding" : "iso-8859-1"
        }
    ],
    "organizationName" : "Atlas labs",
    "description" : "Atlas labs",
    "foregroundColor" : "rgb(255, 255, 255)",
    "backgroundColor" : "rgb(55, 117, 50)",
    "labelColor" : "rgb(190, 57, 57)",
    "eventTicket" : {
        "primaryFields" : [
          {
            "key" : "event",
            "label" : "EVENT",
            "value" : "아틀라스와 함께 떠나요~"
          }
        ],
        "secondaryFields" : [
          {
            "key" : "timestamp",
            "label" : "DATE",
            "value" : "RIGHT NOW!"
          }
        ]
    }
}

 
 

전면/후면 pass.json

{
    "formatVersion" : 1,
    "passTypeIdentifier" : "pass.atlas.event",
    "serialNumber" : "XD",
    "teamIdentifier" : "팀아이디",
    "barcodes" : [
        {
            "message" : "https://www.udemy.com/user/imdongju-2/",
            "format" : "PKBarcodeFormatQR",
            "messageEncoding" : "iso-8859-1"
        }
    ],
    "organizationName" : "Atlas labs",
    "description" : "Atlas labs",
    "foregroundColor" : "rgb(255, 255, 255)",
    "backgroundColor" : "rgb(55, 117, 50)",
    "labelColor" : "rgb(190, 57, 57)",
    "eventTicket" : {
        "primaryFields" : [
          {
            "key" : "event",
            "label" : "EVENT",
            "value" : "아틀라스와 함께 떠나요~"
          }
        ],
        "secondaryFields" : [
          {
            "key" : "timestamp",
            "label" : "DATE",
            "value" : "RIGHT NOW!"
          }
        ],
        "backFields" : [
            {
                "key" : "back-name",
                "label" : "NAME",
                "value" : "임동주 a.k.a Atlas"
            },
            {
                "key" : "back-role",
                "label" : "OCCUPATION",
                "value" : "iOS Developer & Instructor"
            },
            {
                "key" : "back-email",
                "label" : "EMAIL",
                "attributedValue" : "<a href='mailto:atlas9539@gmail.com'>atlas9539@gmail.com</a>"
            },
            {
                "key" : "back-blog",
                "label" : "BLOG",
                "attributedValue" : "<a href='https://artieee.tistory.com/6'>감자밭 개발자</a>"
            },
            {
                "key" : "back-website",
                "label" : "UDEMY",
                "attributedValue" : "<a href='https://www.udemy.com/user/imdongju-2/'>@Atlas</a>"
            },
            {
                "key" : "back-instagram",
                "label" : "INSTAGRAM",
                "attributedValue" : "<a href='https://www.instagram.com/reel/Cq7j5ycrG9e/?igshid=MzRlODBiNWFlZA%3D%3D'>@dev._.artiee</a>"
            },
            {
                "key" : "back-github",
                "label" : "GITHUB",
                "attributedValue" : "<a href='https://github.com/PotatoArtie'>@아틀라스</a>"
            }
        ]
    }
}

 
 
 
 

2. 인증서 

패스를 사용하기 위해서는 인증서가 필요하다. 
개발자 포털 사이트에서 PassTypeIDs를 선택하고 인증서를 만들어 보자

 

 

 

 

 

 

 

 
여기까지왔다면 Certificate Signing Request 파일이 필요할 것이다. 
이것도 차근차근 생성해보자. 

 

 
 
Choose File을 하여 생성한 Certificate Signing Reques 파일을 추가해 주자. 

 

다운로드 버튼을 클릭하면 pass.cer 파일을 받을 수 있다. 다운받은 .cer 인증서를 두 번 클릭하여 Keychain Access에 설치

 

3. Pass Manifest

패스 매니페스트는 생성해야 하는 또 다른 JSON 파일로 패스 번들에 포함된 모든 파일과 해당 SHA1 체크섬을 뜻한다.
 

 
이런 과정은 각설하고 일단 돌아가는걸 보고싶어하는 분들을 위해서 TimOliver/PassKit-Business-Card 에서 편의성있게 만들어 놓으셨다. (Thanks to TimOliver)
 
필자의 깃헙에도 업데이트되어 있으니 가서 다운로드해보자.
https://github.com/PotatoArtie/Potato-iOS/tree/master/Labs/Playground/WalletEventPass
 

실행방법

1. pass.json 의 teamID를 입력해준다. 
2. Pass-Event-Card-Demo 폴더에서 

./signpass -p ExampleCard

 
실행시키면 ExampleCard 파일이 생성된다. 이 파일을 실행시키면 된다. 
 
 

DEEP DIVE 

실제 어떤 프로세스가 필요한 것이고 진행되고 있는지 차근차근 알아보자.  (From Kodeco)
 
1. 각 파일에 대한 SHA1 체크섬을 직접 생성해보자.

cd ~/desktop/작업중인폴더

openssl sha1 pass.json


결과 
SHA1(pass.json)= c24766ef5aa92197eace640fcc4fb584a505a733

 
manifest.json 파일을 생성하고 키,값을 넣어주자. 

manifest.json

{
  "pass.json" : "c24766ef5aa92197eace640fcc4fb584a505a733" 
   ...
}

 
이미지도 동일하게 작업해준다. 

manifest.json

{
  "strip.png" : "25b4c9ff2bafe056f3e28379db0ef3fb460c718b" ,
  "strip@2x.png" : "dee775ed6fb3c7278b84c65853401e760caabc92" ,
  "icon.png" : "8eaa0896db93f2165 fa417df3d002ce9c61fcd92" ,
  "icon@2x.png" : "555ce7f70f2f44fb7ac9d9f46df5738ec6250f37" ,
  "logo.png" : "e8c4edfbcae41d9d88fad7137d8ed30ae5f73e67" ,
  "logo@2x.png" : "1f9b1cc4c75b380ade07e9f2b7f37f988d9d14c3" ,
  "pass.json" : "<여기에 패스 SHA1을 입력하세요>" 
}

 
 
그리고 패스를 만들기 위해서 필수로 필요한 서명작업임으로 시작해보자. 
 
우리가 받은 passId 인증서를 키체인에서 찾아 내보내기를 통해 Certificates.p12로 저장한다. 
Certificates.p12 파일에는 패스인증서와 개인키가 모두 포함되어 있기 때문에 OpenSSL에는 이러한 항목이 별도의 파일에 필요하므로 .12파일에서 추출해야한다. 
 

//폴더의 파일 목록이 표시되어야하며 여기에는 인증서 파일이 포함되어 있어야합니다.
//동일한 폴더 내에 "passcertificate.pem" 으로 저장된다.
openssl pkcs12 -in Certificates.p12 -clcerts -nokeys -out passcertificate.pem -passin pass:

//키를 별도의 파일로 내보내는 명령어
//키파일을 내보내려면 비밀번호를 제공해야한다.12345는 테스트를 위한 간단하게 설정한것이기 때문에 
//프로덕션환경에서는 강력한 비밀번호를 사용하는게 좋다. 
openssl pkcs12 -in Certificates.p12 -nocerts -out passkey.pem -passin pass: -passout pass:12345

 
 
패스번들에 서명하기위해서는 자체 인증서 발급자인 Apple을 인증하는 WWDR 중간인증서라는 인증서가 하나 더 필요하다. 키체인에서 Apple Worldwide Developer Relations Certification Authority 를 찾는다.
 
1.인증서를 찾아서 마우스 오른쪽 클릭을 하여 내보니기 옵션을 선택한다.
2. file 포맷을 개인정보 보호 향상 메일(.pem)으로 설정하고 
3. 파일명은 WWDR로 하고 저장한다. 
 

 
 

 
 
 
이제 진짜 서명할 준비가 되었다. 

//Manifest.json에 서명하는데 사용되는 키파일 
openssl smime -binary -sign -certfile WWDR.pem -signer passcertificate.pem -inkey passkey.pem -in manifest.json -out signature -outform DER -passin pass:12345

/*
inkey는 manifest.json에 서명하는 데 사용되는 키 파일
in은 입력 파일 이름
outform은 출력 파일 이름
outform은 출력 형식 (분리된 서명을 만들려면 "DER"가 필요)
passin은 키 파일의 암호
*/

 
 
 
마지막단계로 서명을 받은 파일을 .pkpass로 만들어 주기만하면 된다. 

// 파일을 .pkpass로 만들어 주기 
zip -r freehugcoupon.pkpass manifest.json pass.json signature logo.png logo@2x.png icon.png icon@2x.png strip.png strip@2x.png

 
 
이런 과정을 편하게 만들어 둔 팀 올리버상 ... 아리가또 👍👍👍
 
조금 더 상세한 설명이 필요하신 분들은 코데코사이트에서 참조해보시길 바란다. (저한테도 알려주세요!🙇)
 
https://www.kodeco.com/2855-beginning-passbook-in-ios-6-part-1-2?page=4

 

Beginning Passbook in iOS 6: Part 1/2

Note from Ray: This is the second iOS 6 tutorial in the iOS 6 Feast! This tutorial is an abbreviated version of one of the chapters from our new book iOS 6 By Tutorials. Marin Todorov wrote this chapter – the same guy who wrote most of the “bonus” ch

www.kodeco.com

 

 

💁‍♂️ 압축된 파일을 해제해보면 어떨까?

 

manifest.json 파일과 signature 파일이 추가되어 있는것을 확인 할 수있다.👍👍👍
 


 
 
결과화면

 
 
 
에어드랍으로 실기기에 옮겨도 보았다. 
 

 

 


서버를 만들어서 패스를 생성하고자 한다면 아래의 포스팅을 참고하면 된다. 

2024.08.12 - [iOS 캐기/토이 프로젝트] - [애플월렛 패스] 참가증, 쿠폰, 티켓같은 패스 서버 API 호출로 생성하기- 개발환경 세팅

2024.08.12 - [iOS 캐기/토이 프로젝트] - [애플월렛 패스] 참가증, 쿠폰, 티켓같은 패스 서버 API 호출로 생성하기- 구조 작성

2024.08.12 - [iOS 캐기/토이 프로젝트] - [애플월렛 패스] 참가증, 쿠폰, 티켓같은 패스 서버 API 호출로 생성하기-기능구현

2024.08.13 - [iOS 캐기/토이 프로젝트] - [애플월렛 패스] 참가증, 쿠폰, 티켓같은 패스 서버 API 호출로 생성하기- 인증서 관련 작업 정리


 

마무리

- 우리나라말로 된 자료가 1도 없었지만 아직 우리나라에서 애플월렛을 활용하기 쉽지않아 많은 관심을 받지못해서이지 않을까 생각했다.
- 조금 더 확장해서 컨퍼런스 참가증용도 사용하기 위해서는 인증서를 관리하는 서버를 두고 사용자마다 입장QR등을 생성해서 주면 된다고 한다. (인증서 때문에 애플이 권장하는 방식이기도 하다)
- NFC 지원도 가능하지만 애플에게 별도로 문의해서 관련 인증서를 받아야하는데 쉽게 갈 수 없는 길이라고 한다. 😭

 

 

Airdrop으로 모바일 디바이스 to 디바이스로 시도해봤는데 잘 동작했다. 진짜 애플의 이런 애니메이션은 애플 감성에 한 몫 톡톡히 하는것 같다.

 

 

 

 

 


 
 
깃헙주소
https://github.com/PotatoArtie/Potato-iOS/tree/master/Labs/Playground/WalletEventPass
 
 
ref.
 
https://developer.apple.com/documentation/passkit

 

PassKit (Apple Pay and Wallet) | Apple Developer Documentation

Process Apple Pay payments in your app, and create and distribute passes for the Wallet app.

developer.apple.com

 
 
https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/index.html#//apple_ref/doc/uid/TP40012195-CH1-SW1

 

Wallet Developer Guide: Introducing Wallet

developer.apple.com

 
https://developer.apple.com/library/archive/documentation/UserExperience/Reference/PassKit_Bundle/Chapters/TopLevel.html

 

Top-Level Keys

Top-Level Keys The top level of the pass.json file is a dictionary. The following sections list the required and optional keys used in this dictionary. For each key whose value is a dictionary or an array of dictionaries, there is also a section in Lower-L

developer.apple.com

 
https://github.com/TimOliver/PassKit-Business-Card

 

GitHub - TimOliver/PassKit-Business-Card: A template for iOS Wallet passes that can be used like business cards.

A template for iOS Wallet passes that can be used like business cards. - GitHub - TimOliver/PassKit-Business-Card: A template for iOS Wallet passes that can be used like business cards.

github.com

 
https://developer.apple.com/documentation/walletpasses

 

Wallet Passes | Apple Developer Documentation

Create, distribute, and update passes for the Wallet app.

developer.apple.com

 
 
https://www.kodeco.com/2855-beginning-passbook-in-ios-6-part-1-2?page=2#toc-anchor-006

 

Beginning Passbook in iOS 6: Part 1/2

Note from Ray: This is the second iOS 6 tutorial in the iOS 6 Feast! This tutorial is an abbreviated version of one of the chapters from our new book iOS 6 By Tutorials. Marin Todorov wrote this chapter – the same guy who wrote most of the “bonus” ch

www.kodeco.com

 
 
https://developer.apple.com/documentation/walletpasses/creating_the_source_for_a_pass

 

Creating the Source for a Pass | Apple Developer Documentation

Create the directory structure and add source files and images to define a pass.

developer.apple.com

 

반응형

관련글 더보기

댓글 영역