Passbook 是蘋果發布的 iOS 6 技術中最火熱的一個, 它所帶來的開創性超過我們的想象。
Passbook 是一些是一個非常棒的組合。 四項獨立的技術結合到一起,為 iPhone 用戶帶來了一個全新的體驗:
Passbook 和你曾經用到過的其他蘋果的技術很不同。 讓他變得與眾不同的是關於一個文件格式的概念。 由你來創建 Passbook 文件, 然後用你希望的方式將他們展現給用戶。 用什麼技術和編程語言來實現它也完全取決於你!
毫無疑問, 通過這樣的設置,相比其他蘋果的技術, 你能夠對你實現的東西有更多的控制。
因為蘋果並沒有處理 Passbook 的後端機制, 你需要使用一系列不同的技術來實現它。 在這篇教程中, 你將會用到 Objective-C 和 iOS,使用 JSON, 發送帶有附件的多部分 Email, 使用 OpenSSL 對文件進行數字簽名, 還有更多。
這篇教程被分為兩個部分:
這個章節看起來有些凌亂, 但非常有好處 – 看完它之後, 你將會精通蘋果最新的技術!
蘋果關於 Passbook 的介紹中說 “你口袋裡面的一切東西”。 我非常喜歡這句話, 因為它非常好的演示了你怎樣能夠並且應該創造性的創建你的應用程序和服務。 Passbook 可以是任何東西。
“但他們是什麼呢?”, 你可能會這樣問.
好吧, 這就是 Passbook 在 iPhone 上面的樣子:
你能夠很容易的認出這個 Pass 上面的幾個不同的元素, 他們給了你一些重要的信息:一個 logo 和 公司的名稱在最上方, “Free hug!” 清楚的描述了這個 Pass, 並且還有關於它的可用性的信息 (起始時間,持續時間)。
然後,在最下面,有一個條形碼。 它和你在火車票,飛機票,購物券上面看到的條形碼很象。如果你仔細的想一想, 你的 iPhone 中的 Pass 可以和那些塞滿你口袋的紙質的票據保存同樣的信息,對吧? 一些文字,一個條形碼 – 就是這些了。相信我,你的 iPhone 上面的數字票卷可以做更多的事情。
再看一下 pass 中有什麼, 想一想它擁有的不同部分:
所有類型的 pass 都有這些重要的東西:
現在,你可能會想紙質的票和購物券是什麼樣的。 這些你每天用到的東西可以被轉換到 iPhone 上面。
在你寫任何代碼之前, 看一下不同類型的 pass。
蘋果定義了 4 種不同的 pass, 每個都很常用, 還有第 5 種, 用作 “普遍” 用途。 為什麼有這麼多不同的 pass 呢, 你怎樣識別他們呢?
預定義的這些 pass 類型,每一個都是為了顯示不同種類的信息,以適應不同的用途。這也是為什麼你的健身房會員證和你的音樂會門票的布局和內容是不同的! 前者需要你的照片,而後者不需要。
布局是區分這些不同種類的 pass 的主要方式, 但是一些 UI 特性, 比如圓角,剪紙同樣能很容易的識別出 pass 來。 這些不同之處很小, 但是很明顯, 這也是為什麼你要確保用的是正確的 pass 類型的原因。
這裡是四個預定義的 pass 類型:
但讓, 還有通用類型的 pass。 教程的第二部分會討論所有這五種類型。
現在,看一下下面這個登機牌的例子。 你會看到他和前面的那個擁抱優惠券很像, 但有一些關鍵的不同點:它提供了兩列的布局方式, 這樣能夠很容易的找出離開和到達的城市; 離開的站台號,事件和座位號也都擺放整齊。
現在,我確定你已經被說服了, pass 是 iPhone 上面一個很偉大的東西! 讓我們看看 pass 是如何設置的, 並且如何創建一個!
這部分將會介紹 pass 的構成部分。 pass 通過一個擴展名為 .pkpass 的文件展現給用戶。 (“pkpass” 的意思是 PassKit Pass – 很好理解,對嗎?)
.pkpass 只是一個 .zip 文件。 如果你將它重新命名為 ZIP 並解壓它, 你會找到一些文件。 這是你前面看到的Free Hug Pass 的內容:
這就是所有了!
正如你看到的, pass 的主文件是 pass.json 這個 JSON 文件。 在它裡面你聲明了這個 pass 正面和反面的所有信息, 你提供了這個 pass 需要顯示的所有圖片(在優惠券的情況中, 你僅僅需要指定background.png和它的視網膜版本)。最終,你需要一個清單文件,它包含了所有這些文件的 SHA1 校驗和,和一個分開的簽名, 這樣 Passbook 能夠驗證這個 pass 在你創建之後沒有被修改過。
現在你可以寫一些代碼了。 讓我們看看你能否重新創建一個Free Hug pass!
等一下! JSON 不是 Objective-C。 它甚至不是任何一種編程語言。 它僅僅是一個標記語言, 用來描述數據結構。 那麼,你如何寫 JSON 呢? 實際上你可以使用任何的文本編輯器 – Xcode, TextMate, Coda 或者 TextEdit. 在這章中, 你會用到 Xcode。
在 Xcode 的菜單中, 選擇 File/New/File… 然後選擇 iOS/Other/Empty 作為文件類型。 將新文件命名為pass.json 並將它保存到你選擇的目錄中。 注意你可能想要創建一個新的目錄來存放 pass, 因為你會將很多和 pass 相關的文件存放到同一個目錄中, 將他們放在一起是一個不錯的選擇。
你現在應該能看到這個空白的窗口, 就像這個:
但那沒什麼問題 – 不用擔心!
你可以了解更多關於 JSON 的信息:http://en.wikipedia.org/wiki/JSON
你可能注意到了,蘋果的 plist 文件存放著和 JSON 一樣的信息 – 數組,字典,數字和其他。你可能會感到奇怪, 為什麼蘋果用 JSON 而不用 plist 呢。
是這樣, pass 很有可能是在非 iOS 或者 OS X 的環境下生成的 – 更有可能的是, pass 是由 web 服務器作為對用戶請求的響應生成的。 蘋果想讓你能夠很容易的從所有的 web 腳本語言中生成這個文件, 因為 JSON 都被 PHP, .NET, Rubym Python 這樣的語言良好的支持,最終, JSON 看起來是最佳的選擇。
讓我們從 Free Hug Pass 的架構開始! 將這些代碼復制到 pass.json 文件中:
{ "formatVersion" : 1, "passTypeIdentifier" : "pass.com.yourdomain.couponfreehug", "serialNumber" : "001", "teamIdentifier" : "", "organizationName" : "Free Hugs LLC", "description" : "Coupon for 1 Free Hug" }
這是你需要提供的最小量的元數據:
這包含了很多信息, 所以讓我們看看他們如何被蘋果應用。
因為 pass 不是必須要和 iOS 應用相關聯, 所以沒有一個自動化的方式來讓 pass 和指定的 iOS 開發者賬號相關聯(需要驗證 pass 中的內容), Pass 可以獨立於應用到達用戶的設備上, 通過郵件或者下載的方式, 這也是為什麼在 pass 的元數據中要包含 teamIdentifier 了 – 用於將 pass 和開發者賬號相關聯。一旦蘋果知道了創建這個 pass 的開發者標識,它就會用 passTypeIdentifier 來確定它是哪種類型的 pass。 每種類型的 pass 都有它自己的證書,這樣蘋果就能過通過這個證書來驗證包含在 pass 中的簽名了 – 確保沒有人篡改 pass 的內容。
最後, serialNumber 為指定的 pass 類型分配的序列號。
復習一下, 想一下這個例子:
現在你應該明白 pass 標識是如何工作的了。 所以, “通過” 這節,去看看下面的吧, 你將會創建你自己的 pass 類型。
進入 iOS Developer Portal (https://developer.apple.com/devcenter/ios/index.action), 在你登錄進去之後, 在右邊的菜單欄中打開 iOS Provisioning Portal。
如果你已經得到了簽出到最新的 iOS 6 版本了,你可能已經注意到左邊多了一個菜單項 Pass Type IDs。 點擊那個鏈接,在接下來的頁面中, 你將會看到你已經創建過的 pass 類型的列表(這時可能還是空的)。
點擊 New Pass Type ID 按鈕, 你將會進入一個創建新的類型的頁面。 在描述區域填入 “Free Hug Pass”, 在標識區域填入 “pass.com.yourdomain.couponfreehug”。 對於 Pass Type ID, 蘋果推薦使用以 “pass“ 開頭的反向域名表示法。 這就是你要用的格式。
注意: 對於這章的目的來說, 你可以使用 “com.yourdomain” 這種形式, 但是在正式的應用中, 記住要將 com.yourdomain 這種替換成實際你自己的域名的方向表示法。?
還要注意,如果你決定將標識從 “pass.com.yourdomain.couponfreehug” 修改為別的, 你還要相應的修改 pass.json 文件中的 passTypeIdentifier 的值。
接下來, 點擊 Submit 按鈕來創建你的 pass。
順便說一句,那個指示燈沒有變成綠色, 你可能已經猜到,還缺一些東西。 你是對的。 你還需要生成一個 pass 證書。 點擊 Configure 按鈕。 將要展示的下一個頁面是說明 pass 的標識的好地方。
這裡你能看到你的 teamIdentifier (以 ABC 開頭的前10個字符), 用這個 ID 來更新 pass.json 文件 – 確保僅替換占位符,並保留兩邊的引號!
好了! 你的 pass.json 現在更新了。 然而, 還有一些額外的步驟將你的證書導入你的開發環境。
返回 iOS Provisioning Portal, 點擊 Configure 按鈕:
這將會打開 Pass Certificate Assistant (*奇特的名字!), 它將會引導你完成證書的生成。 仔細看一下對話框中的內容,並跟隨它的步驟。
當你提交你的簽名請求之後, 你的證書將會及時的生成出來,並且你應該看到一個成功對話框:
點擊 Continue 幾次, 然後點擊 Download 按鈕來得到證書文件。 文件被下載後, 找到他,並雙擊它將它導入到鑰匙串中。 注意大多數情況下它在你的用戶目錄中的 Downloads 文件夾中,除非你在浏覽器中設置了另外一個默認下載地址。
如果鑰匙串讓你確定是否導入, 點擊 Add 按鈕:
然後, 你將會在鑰匙串中看到你的證書:
你已經完成了證書的制作! 現在你在 JSON 文件裡有了真實的數據, 並且當需要簽名的時候你有了正確的證書。
讓我們繼續構建 pass.json 文件 – 接下來修改它的外觀。
打開 pass.json 並且在最後定義一個 ”description“ 鍵, 添加一個逗號 – 因為你需要在字典中增加多個鍵。 在大括號結束前, 添加:
"logoText" : "Free Hugs LLC", "foregroundColor" : "rgb(255, 255, 255)", "backgroundColor" : "rgb(135, 129, 189)", "labelColor" : "rgb(45, 54, 129)"
這些鍵的作用:
現在你的 pass 有了一些樣式! Heidi Klum 會感到很榮幸。
除非你達到了在 Passbook 中構建並測試的最小要求, 否則你還需要繼續添加更多的元素。 接下來,你將會添加一個條形碼。
聽起來很復雜,對嗎? 幸運的是,做起來很簡單。 PassKit 支持三種不同的條形碼 (所有這些都是二維條碼格式):QR,
PDF417 and Aztec。
描述一下我的意思:
換句話說, pass 不支持那些老式的條形碼, 你通常會在雜貨店的商品包裝上看到它們, 並且今後也不會支持它們。 PassKit 使用的是 2D 格式,可以讓基於圖片掃描的設備(像是 iPhone) 很容易的閱讀它。
你將會使用 PDF417 標准來構建 Free Hug 優惠券的條形碼 (上面這些圖的中間那個), 在代碼的最後一行添加一個逗號(在結尾大括號的前面),並把它粘貼到 barcode 的 JSON 中:
"barcode" : { "message" : "All you need is love", "format" : "PKBarcodeFormatPDF417", "messageEncoding" : "iso-8859-1" }
不管你信不信, 這是所有你需要做的 – 蘋果會幫你生成一個條形碼! barcode 字典有三個鍵:
目前為止, pass 的源代碼看起來是這樣的:
{ "formatVersion" : 1, "passTypeIdentifier" : "pass.com.yourdomain.couponfreehug", "serialNumber" : "001", "teamIdentifier" : "ABC1230000", "organizationName" : "Free Hugs LLC", "description" : "Coupon for 1 Free Hug", "logoText" : "Free Hugs LLC", "foregroundColor" : "rgb(255, 255, 255)", "backgroundColor" : "rgb(135, 129, 189)", "labelColor" : "rgb(45, 54, 129)", "barcode" : { "message" : "All you need is love", "format" : "PKBarcodeFormatPDF417", "messageEncoding" : "iso-8859-1" } }
接下來,你會添加一些有價值的信息到 pass 的正面。
再說一便, 在 barcode 字典的結尾大括號後面添加一個逗號。(你要保持這樣, 因為我希望你的 JSON 文件在任何時候都是有效的。 一旦你習慣於寫有效的 JSON, 你可以節省很多調試的時間。)
繼續並添加一個鍵,用來表示這個 pass 是一個優惠券(將這段代碼粘貼到最後一個結尾大括號的前面):
"coupon" : { }
在這個空的字典中, 你將會添加所有的定義和數據來顯示優惠券上面的信息。
在 “coupon” 中添加:
"primaryFields" : [ { "key" : "offer", "label" : "for you", "value" : "Free hug" } ]
這種結構第一眼看上去比較奇怪, 但是相信我 – 它是有意義的。 首先你添加了一個新鍵 “primaryFields”, 它的值是一個數組。 為什麼是數組呢? 因為每一節都可以顯示一個或多個字段,所以你需要一個有序列表來指定他們的先後順序。
在個列表中的每一個字典都描述了一個字段。 你大概已經看明白它們了, 但讓我用例子來說明它。 對於每一個字段你都會得到如下幾個基本鍵:
對於每一個字段,還有很多鍵可以用, 但你會在稍後看到它們。
重要的東西是 – 你現在有了一個完整的 pass.json 文件! 太酷了!
他們說一張圖片頂得上千言萬語 – 你很幸運, 在 pass 的正面沒有地方顯示上千個文字, 所以為了適應這個限制, 你也要使用圖片。
下載我為你准備的資源:PassAssets.zip。 解壓這些文件, 並在 FreeHugCoupon 目錄下,你將會找到一系列的 PNG 文件。 將它們拷貝到你的 pass 工作目錄中。
就是這樣 – 你完成了! 非常容易。
等一下, 什麼? 你不需要在 pass.json 添加任何代碼來告訴 Passbook 要加載哪一張圖片。 沒錯!
Passbook 會根據標准的命名規范來加載圖片。這意味著名稱為 icon.png; [email protected]; logo.png; [email protected]; strip.png and [email protected] 的圖片
將會顯示在 pass 上面。 除了需要把這些文件包含在 pass 的包中, 不需要在做任何其他事情(教程後面還會用到更多的圖片。)
注意: 這裡有一點 pass 圖片比較難理解的地方 – 我花了一段時間才弄明白 – 圖片文件需要導出成 PNG24 格式。 由於某些原因,比較小尺寸的 PNG8 格式不會顯示在 Passbook 上面。
“讓我們試試這個 pass 吧! 我已經想看看它了!”,
不幸的是, 在 pass 包完成,並且簽名,壓縮之前, 你不能夠預覽它。 Passbook 不能顯示任何無效的(不完整的) pass。 所以,再忍耐一會兒, 繼續工作。
pass 清單文件是另外一個你需要創建的 JSON 文件, 並且它描述了 pass bundle 中包含的所有文件和他們的 SHA1 校驗和。
你可以通過自己生成 SHA1 校驗和(稍後我會給你展示),但為了更快的創建完你的第一個 pass, 我將一個已經生成好的 manifest.json 文件放到了 PassAssets.zip 文件中,你已經下載並解壓它了。在你解壓 zip 的地方找到 manifest.json 文件, 將它拷貝到你的 pass 工作目錄中。
它的內容如下:
{ "strip.png":"25b4c9ff2bafe056f3e28379db0ef3fb460c718b", "[email protected]":"dee775ed6fb3c7278b84c65853401e760caabc92", "icon.png":"8eaa0896db93f2165fa417df3d002ce9c61fcd92", "[email protected]":"555ce7f70f2f44fb7ac9d9f46df5738ec6250f37", "logo.png":"e8c4edfbcae41d9d88fad7137d8ed30ae5f73e67", "[email protected]":"1f9b1cc4c75b380ade07e9f2b7f37f988d9d14c3", "pass.json":"" }
這些圖片的 SHA1 校驗和已經填好了, 但是最終的校驗和 – pass.json 文件的 – 還沒有。
你將會自己生成它的 SHA1。 這非常簡單 – 打開終端並定位到你的 pass 目錄。
注意: 如果你不熟悉如何在終端定位目錄, 這樣做: 將你的 pass 文件移動到桌面的 “FreeHugCoupon” 文件夾中, 然後打開終端,輸入這個命令:
cd ~/Desktop/FreeHugCoupon
這樣就好了
在終端提示符中輸入這個命令:
openssl sha1 pass.json
命令行的輸出看起來是這樣(實際的校驗和可能會不同):
SHA1(pass.json)= c24766ef5aa92197eace640fcc4fb584a505a733
注意!
一個很重要的事情,就是在我沒讓你修改 pass.json 這個文件之前, 不要再修改它了。即便你僅僅向 pass.json 添加了一個字符, SHA1 校驗和就會改變, 這樣你的 manifest.json 文件將會失效,因為這裡給出的校驗和不再和修改後的 pass.json 文件的校驗和相匹配。
這是你最後一個要修改的源文件了。 棒極了!
現在,進行創建 pass 中最有趣的一部分。
還記得你為你的 pass 類型從蘋果獲得的證書嗎? 你已經將它導入到鑰匙串中了, 並且還沒有接觸過它。 現在你將會把這個證書和秘鑰導出成 PEM 格式, 這樣你可以把它們用於 OpenSSL。
打開鑰匙串訪問, 在左邊的菜單中選擇證書(在類型下面),並找到叫做 “Pass Type ID: pass.com.yourdomain.couponfreehug” 的證書。 確保你選中的是證書本身,而不是它下面的私鑰:
接下來, 右鍵點擊這個證書, 在彈出菜單中選擇導出 “Pass Type ID: pass.com.yourdomain.couponfreehug”…,將導出的文件保存成 “Certificates.p12” 到你的工作目錄中。將會有一個彈出框,讓你輸入一個密碼:
為了讓這個過程更簡單一點, 直接點擊 OK – 這個證書將會導出為不帶密碼保護的。
注意: 在這是,你可能會被要求輸入登陸鑰匙串的密碼。 如果是這種情況, 直接輸入你電腦的用戶密碼就足夠了。 Certificates.p12 文件現在包含了 pass 的證書和私鑰。 OpenSSL 需要單獨的兩個文件, 所以現在你需要將他們從 .p12 文件中提取出來。
切換回終端 – 是 OpenSSL 魔術的時候了!
在確保當前目錄是正確的之後 (輸入 “ls -al” 然後點擊 Enter 鍵 – 你應該看到這個目錄的文件列表,並且這個列表應該包含你的 Certificates.p12 文件), 輸入如下命令:
openssl pkcs12 -in Certificates.p12 -clcerts -nokeys -out passcertificate.pem -passin pass:
這將僅將 pass 證書導出為 PEM 格式,並在同一個目錄中把它保存成 “passcertificate.pem”。(如果這個操作成功的話, OpenSSL 將會輸出 “MAC verified OK” 消息。)
接下來, 通過這個命令將私鑰也導出成單獨的文件:
openssl pkcs12 -in Certificates.p12 -nocerts -out passkey.pem -passin pass: -passout pass:12345
注意到這次, 你需要提供一個密碼來導出這個私鑰文件。 在這個例子中, 僅使用 “12345″ – 在生產環境中, 應當使用一個強密碼 – 不能是 “password1” 或者 “passw00t” 這種東西。
為了給你的 pass bundle 簽名, 你需要另外一個證書 –
To sign your pass bundle you will need one more certificate – WWDR Intermediate 證書, 用來驗證發給你證書的發布者 – 蘋果。 你已經將它安裝到鑰匙串中了。 打開鑰匙串訪問, 選擇 “證書” 分類, 並找到一個叫做 “Apple Worldwide Developer Relations Certification Authority” 的證書(是的,這確實是一個很長的名字):
如果萬一你沒有這個證書, 那麼打開你的浏覽器, 訪問這個頁面http://www.apple.com/certificateauthority/。在這裡你可以下載你可能需要的最重要的蘋果證書。 翻到下面,找到 WWDR 證書, 下載 .cer 文件, 並導入到鑰匙串中。
你已經准備好導出這個證書了。 返回到鑰匙串訪問, 右鍵點擊證書名稱並在彈出的菜單中選擇導出選項:
在 “另存為…” 對話框中, 找到 format 下拉框,並選擇 Privacy Enhanced Mail (.pem) 選項:
在對話框頂部的文本框中, 輸入文件的名稱 “WWDR.pem”, 選擇 pass 的工作目錄作為目標, 然後點擊保存按鈕來完成導出。 你已經可以創建簽名了, 輸入這個命令:
openssl smime -binary -sign -certfile WWDR.pem -signer passcertificate.pem -inkey passkey.pem -in manifest.json -out signature -outform DER -passin pass:12345
仔細看一看上面的命令行 – 非常容易理解所有的參數。 signer 參數是你的 pass 證書的文件名; inkey 是用於對 manifest.json 簽名的私鑰文件; in 是輸入文件的文件名; out 是輸出文件的文件名;outform 是輸出的格式(你需要用 “DER“ 來創建一個分離的簽名); 最後, passin 是私鑰的密碼。
現在你有了你的簽名, pass 的創建基本完成了。
還剩下最後一步, 就是將 pass 中的多個文件集中到 .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
通過使用 shell 命令 “zip”, 你創建一個叫做 freehugcoupon.pkpass 的 ZIP 文件, 並且這個檔案包中包含了後面列表中的所有文件。
不管你是否相信。。。 就是這樣! 全部都完成了! 你做到了!
是的, 你最終到達了, 你擁有了一個完整並有效的 pass, 你可以在 iOS 6 的設備上看到它了。
創建一個 email 消息(或者到你在 iOS 6 設備中設置的郵箱賬號) 並附帶一個你剛剛創建的 .pkpass 文件。 發送出去, 打開 Mail.app 並看一看! 你應該在附件中看到這個 pass, 像是這樣:
如果你看到這個 pass 了 – 祝賀你! 你創建好它了!
如果沒有, 不要失望 – 這是一個很長並容易出錯的過程,你要回到開始階段, 然後檢查一些是否執行了所有必須的步驟。 確保你的 JSON 文件是有效的並且正確地導出了你的證書文件和私鑰。
提示:如果你想驗證 JSON 文件的有效性, 使用這個在線工具: http://jsonlint.com/ 來快速的驗證你的代碼。
是時候看看這個 pass 了! 在郵件消息中點擊它, 然後 Passbook 將會彈出來並顯示給你偉大的東西!
這非常棒! 點擊右上角的 Add 按鈕, 你將會看到一個精致的動畫效果, pass 滑了下去(進入 pass 中, 但是你很有可能是空的) 然後你會返回到 Mail 中。
注意: 如果你想在你的 Passbook 中看到更多的 pass,可以用你的移動浏覽器訪問 http://passk.it/samples。 這個網站上面有一系列非常有趣的 pass 的樣本。
現在,退出 Mail, 並打開 Passbook 應用。 這是你的第一個 pass。 祝賀你!
在 Passbook 預覽一下這個 pass, 正面和背面(你可能會感到奇怪, 你可以通過點擊右下角的那個小的斜體 “i” 來訪問 pass 的背面):