Fastlane - match

Fastlane 是什麼?

簡單來說,它可以替你解決除了寫程式以外的很多事情;
像是「螢幕截圖」、「打包上傳到 Testflight」、「建立 App Store 的 App 資訊」等等,
尤其是在一個專案(project)擁有多個 target 的時候,
更是只需要一行就可以打包出十幾個 App,並且分別上架到 App Store。
而在這篇文章裡頭,會介紹其中一項功能的部分用法:

Match

Match 主要負責和 Certificate 相關的處理,這邊所要帶給大家的使用情境是,
一個 iOS 專案同時有需要多人同時開發,我們通常會採取的作法有下列幾種:

  • 在 Apple Developer Team 之中加入專案各個開發人員使用自己的 Apple ID
  • 在 Apple Developer Team 之中加入專案各個開發人員的公司 Apple ID
  • 提供給專案各個開發人員相對應的 Provisioning Profile

第一種和第二種的做法差不多,但其壞處就是管理者無法有效地管理 Certificate,
所以有可能會時常出現一些奇怪的 App IDs 或是 iOS Provisioning Profile,
或是誰又不小心把誰的 certificate revoke ⋯⋯

所以我們需要權限劃分清楚

建議的做法是註冊一組公用的開發者帳號,不和任何人產生連結性

e.g dev@apple.com

只放這組帳號在 Apple Developer Team 裡頭,開發相關的處理皆由這組帳號來負責,
而帳號密碼無需流通到僅負責開發的人員手中;
意思是指,讓單純寫 Code 開發的人員,無須註冊特別的 Apple ID 或是加入哪個 Team,
只需要透過 fastlane match 的方式來獲得 Certificate,可以開發就好!

建置流程

首先,先建立一個 private 的 repo 用來準備放置 match 的相關內容,
接著到專案的資料夾下,執行 fastlane match init,接著會在資料夾中看到 Matchfile

照著上述修改後,執行 fastlane match 後,它便會自動幫你建立好 Certificate 和 Provisioning Profile。
第一次執行的時候,會需要填入一組 passphrase。
(之後其他人要匯入 Certificate 的時候也需要填入相同的密碼)
p.s 如果專案原先就有 certificate ,執行 fastlane match nuke 就可以將它清除掉。
另外,需要將 Signing 的 Automatically manage signing 取消勾選,
並將 Provisioning Profile 選擇由 match 所建立的 Provisioning Profile。

這樣便建構完成了!
當之後專案有其他人手需要加入開發的時候,只需要 clone 專案下來,
不用將他的帳號加入到 Apple Developer Team 之中,
只需要執行 fastlane match,便擁有開發的相關憑證和 Provisioning Profile 可以使用~

Socket

最近在接觸即時通訊相關的開發內容,撇除使用第三方服務的串接,
大多數都是建議使用 Socket 來和伺服器端進行連接和溝通。
而研究了一下,在 TCP / IP 架構下,sockets 可以分為兩種

  • Datagram sockets(connectionless)
  • Stream sockets(connection-oriented)

Datagram sockets(connectionless)

Datagram sockets 是使用 UDP 封包來進行傳送,
其主要的特色是速度快但不能保證資料的完整性以及次序有可能會有誤;
所以大多是使用在廣播資訊或是傳送一些較不是那麼重要的內容。

Stream sockets(connection-oriented)

而 Stream sockets 則是使用 TCP 封包來傳遞,
其因為會先需要確認 Server 和 Client 兩者連接狀態後再傳遞,
故速度較慢一些,但至少能確認資料的有序性以及完整度。

簡單的總結

以中華郵政的觀點來看,以結果來區分的話,
我們可以簡略地將 UDP 視為平信、TCP 視為掛號信。
而即時通訊的部分,依照上述的特色來看,就得選擇使用 TCP 的方式來進行溝通。

Server 和 Client 的溝通流程

首先,伺服器端和用戶端兩者必須使用同一類的封包才能互相通訊,
意思便是指 Server 建立了一個 UDP Socket,Client 也必須使用 UDP Socket 才能兩者打通。
而 Socket name 會需要包含 IP、Port、以及使用哪種協定;
當 Client 端的 Socket 成功聯繫上 Server 端的 Socket 時,
這兩者便形成一組 association。

iOS 上的 Socket 實作方式

我這邊是使用第三方套件的方式來協助實作,Github 上有不少相關的開源碼可以使用。

這篇就先以 CocoaAsyncSocket 作為內容主軸來當後面的說明。
比照上方的流程圖,首先我們要先建立一個 socket,再來進行 connect 的動作,
之後相關的 callback,會以 delegate 的方式來做處理。

不過這邊要比較注意到的是,會需要主動的執行 readData 的動作,
來告知底層,目前可以讀取傳輸進來的資料。

在 RxSwift 內的實作方式

讓 socket 的動作和事件是可被訂閱的,參考了一些實作的方式,
讓 CocoaAsyncSocket 和 RxSwift 結合在一塊:

有興趣的人可以參考參考!

多個帳號的 SSH Config 設定

一般的情形下,我們不會太需要去做 config 檔案的設定,
因為其實不太需要建立太多組的 SSH key 來增加管理上的麻煩;
但隨著身份的增加(大多數是因為工作關係),
我們會需要用到其他組 SSH key 來連接 git server。

如果公司使用的 git server,是我原本就沒有使用的呢?

那就沒什麼差了。
就像是我第一份工作,公司所使用的 git server 為 AWS 的 CodeCommit,
而原先我根本就不用使用到那邊的服務,所以建立一組 SSH key 在 AWS 上使用也沒什麼衝突。
且 AWS 上的教學文件,會讓你在 ~/.ssh/config 之中,以 Host 作為區別;
所以它只會在 AWS 上使用你為了 AWS 所建立的 key。

但⋯最容易發生的情形就是:

公司也使用 Github 作為組織的 git server

通常我們會有一組自己私人的 Github 帳號,若公司不反對你使用私人帳號加入組織的話,
其實你也就沒什麼差了;
但大多數的情形是會給你一組(或是請你申請一組)公司信箱的 Github 帳號,
來維護 private git repository。

Public key

我們先來看看 ssh 的 public key 裡頭,帶了哪些資訊:

重點便是最後的 xpopchi@gmail.com
這把 key 會知道是和哪個信箱綁定在一起的,所以在 Github 上,
公司和私人的帳號便無法共用同一組 SSH key。

所以我們得替公司的信箱再建立一組 SSH key

建立的流程可以看 Github 上的文件,不過會需要在建立時,替它取不同的名稱:

e.g Archie_Apple.pub

個人的習慣是在後面加上公司的名稱來做區別。
它都會放置在 ~/.ssh/ 裡頭,我們需要透過編輯 ~/.ssh/config 的方式,
以及 git url 的調整,來做到使用不同的 key 連接同一個 git server。

~/.ssh/config 的設定方式

我們透過不同的 Host 命名方式,來定義裡頭要使用的哪一把 key 去做連結:

這邊可以看到,我在 Host 那邊區隔出 github.com-Applegithub.com
意思便代表著當 SSH 的 url,host 為 github.com-Apple 時,
會使用 Archie_Apple 這把 key;
而其他的 github 就照舊使用私人帳號的那把。

最後,使用的方式

在你原先進行的 url 之中,做一些調整:

git@github.com:ArchieR7/APNsPusher.git

這是使用私人帳號的方式,而若要使用 Archie_Apple的話:

git@github.com-Apple:ArchieR7/APNsPusher.git

這樣就能夠使用另一把 key 來進行動作了。
不過最好是在 ~/.ssh/config 之中補上 user.name 和 user.email,
否則之後再進行 commit 時,都會以預設的名稱和信箱作為 commit 的作者。

print

print

在第一次接觸一個沒學過的程式語言時,我們多半可以看到會以「Hello, world!」作為開頭;
而你第一個所使用的 method,也很有可能就是印出東西相關的。
我在這邊寫的是 print,可能在別的語言並不是這個詞,是 printf 或是 console.log() 之類,
但這邊(或是這整個網站XD)就以 Swift 為主。

NSLog v.s print

有接觸過 iOS 開發的人,你可能也會看過別人使用 NSLog,而這邊就解釋一下兩者的差異:

NSLog

它是屬於 Fundation 的一個 function:

  • 會加上 timestamp
  • 會加上 identifier
  • 會印在 device console
  • 會花較多一些些的效能,所以會比較慢一些(因為前兩者)

print

  • 會印在 debugger console

所以,若你只是需要記錄在 debugger console 的話,則建議就使用 print 就好。

開始使用

為了瞭解程式的執行內容,我們便開始在一些地方加上 print 的功能,像是

這樣就可以在 debugger console 那看到程式目前是進到哪個判斷式裡頭,
不過他大概就很簡略地顯示

a 等於 1

只能透過 print 的訊息來判斷是在哪,發生什麼事;
如果我們只是印出各種 print(error),就會比較難知道是誰發生了什麼事。

在輸出時加上檔案名稱及 function 和列數

在 Swift 裡頭,我們可以寫 #file #function #line 來取得相關資訊,並且簡單地分類:

我個人習慣分成 Debug、Warn、Info、Error,

  • Debug:為了開發需要看到的資訊
  • Warn:不應該執行到的警告,但不會造成 Crash 的程度
  • Info:像是網路回傳的資訊內容
  • Error:就⋯⋯紀錄 Error 的內容XDD

這樣就可以在 debugger console 看到比較詳細的內容。

(我沒有放 function name,有需要的記得要以參數的方式帶上)

Apple Pay

Apple Pay

Apple Pay 已經在台灣流通一段時間,第三方支付的相關業者也相接著推出串接的服務;
而撇除串接第三方支付的 SDK, iOS 開發者本身的流程呢?

Apple developer 相關設定

首先,你需要先到 Apple developer > Identifiers > Merchant IDs 註冊一個 Identifier

新建完之後,點擊裡頭的 edit,需要補上 CSR 檔;
而如果你只是要測試這個流程,沒有要走到金流相關的測試的話,可以先跳過這段。

Xcode 相關設定

接著到你的專案裡頭,打開 Apple Pay 的開關並填入剛剛註冊的 Merchant ID。

以及 import PassKit,便可以在專案中使用 Apple Pay!

流程解釋

使用者按下 Apple Pay 的按鈕後,我們該做的流程為

  1. 建立訂單(PKPaymentRequest)
  2. 填寫訂單相關內容
  3. 建立 Apple Pay 的畫面(PKPaymentAuthorizationViewController)
  4. 設定 PKPaymentAuthorizationViewController 的 delegate
  5. present Apple Pay 的畫面

而訂單相關內容可以填寫寄送相關(ship)以及聯絡人相關(contact)和金額那些基本的。

畫面上就會出現 Apple Pay 的 View

出現之後⋯⋯

我們可以透過 PKPaymentAuthorizationViewControllerDelegate 來做後續的事情:

像是最重要的是,付款完之後的 payment.token 以及 payment 裡頭的相關資訊等,
再來就看專案要做哪些事情了XD

最後,給設計師

Apple Pay 有規範一些它的 style 相關的設計要求,可以看這邊

JSON Web Token

JWT

JWT( JSON Web Token)和 iOS 比較有相關聯的地方,
便是在於 APNs p8 是使用 JWT 格式作為傳遞;
而有關於 JWT 的相關資料,可以參考 [這個網站](https://jwt.io/introduction/)。
以之前所提到的 [APNs](https://www.archie.tw/apns) 來說,是由三個部分所組成:

  1. Header
  2. Payload
  3. Verify signature

Header

在 APNs 裡頭,需要包含這兩者

  • alg:所使用的加密方式(algorithm),p8 是使用 ES256 作為加密方式
  • kid:鑰匙的 ID(key identifier)

例如:
alg: ES256
kid: 12345678

Payload

  • iss:所發送的人(issuer),這邊為開發者的 Team ID
  • iat:所發送的時間(issued at)

Verify signature

這邊便是將上述兩者,分別做 base 64 加密後輸出成字串,再加上 p8 的 key,
一起做 ES256 加密後的結果,所以大概長這樣:
{header base 64 encode}.{payload base 64 encode}.{ES256 hash[(header base 64 encode).(payload base 64 encode),key]}

Swift 版本的 APNs

這幾天便是在研究如何在 Swift 中,實做推播的功能,目前卡在內建的加密方式是 HMAC 的為主,
並沒有 ECDSA p-256 的方式(ES256 = ECDSA p-256 加上 SHA 256),
故加密那段仍未能完成。

徵求

對 ES256 有研究的大大,分享一下如何在 Swift 上實作 ES256 加密!

Bitnami