Swift 串接 PTX API — 火車動態即時查詢、UISearchController

Anny
11 min readNov 4, 2020

--

前面介紹了 Swift 串接 API 下載資料,以及如何解析JSON 與 XML 資料了。

那這次我們就來製作 火車動態即時查詢 的APP吧!!!

本篇內容包含:

  • 串接 PTX API — 到 PTX 申請 APPID 和 APPKey
  • 如何設定 HTTP header — Authorization 和 x-date 欄位
  • 取得所有站名,顯示在 Table View 中
  • UISearchController 搭配 Table View — 用來搜尋火車站
  • 取得車站的動態即時到站時刻 — 車次是否誤點 (動態前後30分鐘的車次)
  • 最後會附上 Github 連結 (在最下面)

先附上成果~~~

讓我們開始吧~~~

串接 PTX API — 到 PTX 申請 APPID 和 APPKey

公共運輸整合資訊流通服務平台 申請會員!!!

申請一般會員就可以囉!!!將欄位填寫完畢後送出審查,通常不到一天就可以在信箱中收到結果了,通過的話則會收到 APP ID 和 APP Key。

如何設定 HTTP header — Authorization 和 x-date 欄位

詳細授權驗證可以到以下網站查看

首先是取得時間x-date — 發送 request 的時間,定義一個 function getTimeString PTX API要求格式的時間字串。

func getTimeString() -> String {
let dateFormater = DateFormatter()
dateFormater.dateFormat = "EEE, dd MMM yyyy HH:mm:ww zzz"
dateFormater.locale = Locale(identifier: "en_US")
dateFormater.timeZone = TimeZone(secondsFromGMT: 0)
return dateFormater.string(from: Date())
}

接下來設定 HMAC & SHA 加密。import CryptoKit,可以方便寫加密相關程式。官網有提供 swift 的程式範例 ,可以到下列網址參考。

但官網提供的加密方式採用 SHA1,但是 SHA1 比較不安全,我使用的是SHA256,也提供各位不同的加密方式作參考~~~

設定 HTTP header Authorization 和 x-date 欄位的完整程式如下:
APP_ID 和 APP_KEY,要輸入自己申請的 ID 和 KEY 喔~~~

let APP_ID = "自己申請的ID"
let APP_KEY = "自己申請的KEY"
let xdate = getTimeString() // 取得時間字串func
let signDate = "x-date: " + xdate;
let key = SymmetricKey(data: Data(APP_KEY.utf8))
let hmac = HMAC<SHA256>.authenticationCode(for: Data(signDate.utf8), using: key)
let base64HmacString = Data(hmac).base64EncodedString()
let authorization = """
hmac username="\(APP_ID)", algorithm="hmac-sha256", headers="x-date", signature="\(base64HmacString)"
"""

設定完後,就可以產生 URLRequest ,產生 URLSessionDataTask 抓取資料。

// 取得全部車站站名
let
url = URL(string: "https://ptx.transportdata.tw/MOTC/v2/Rail/TRA/Station?$format=JSON")!
var request = URLRequest(url: url)
request.setValue(xdate, forHTTPHeaderField: "x-date")
request.setValue(authorization, forHTTPHeaderField: "Authorization")
request.setValue("gzip", forHTTPHeaderField: "Accept-Encoding")
// URLSessionDataTask 抓取資料
URLSession.shared.dataTask(with: request) { (data, response, error) in
if
let loadedData = data {
do{
// 使用JSONDecoder解析Json格式
let stationData = try JSONDecoder().decode([Station].self, from: loadedData)
self.stations = stationData
//寫入Stations資料 將清單存到手機中
Station.saveToFile(stations: self.stations)
}catch{
print(error.localizedDescription)
}
}
}.resume()

如何解析 JSON 資料 可以看先前發過的這篇文章~~~

我在解析資料的同時,也將全部車站站名 使用 UserDefaults 存起來。

struct Station:Codable {
var StationID: String
var StationName: NameType
static func saveToFile(stations:[Station]){
let saveStations = try? JSONEncoder().encode(stations)
UserDefaults.standard.set(saveStations, forKey: "Stations")
}
static func loadFromFile() -> [Station]?{
guard let loadDate = UserDefaults.standard.data(forKey: "Stations") else {return nil}
return try? JSONDecoder().decode([Station].self, from: loadDate)
}
}
struct NameType:Codable {
var Zh_tw: String
var En: String
}

UISearchController 搭配 Table View — 用來搜尋火車站

上述做完 URLSessionDataTask 解析完 JSON 資料後,將車站站名以及ID 存進 stations 中,接著在 Table View 中顯示。但是車站那麼多,我們慢慢滑的話會很耗時間,這時我們就需要 UISearchController 來搭配 Table View

來做 Table View 的搜尋列喔~~~

  • 先宣告 var searchController: UISearchController?
  • 設置兩個存放的陣列
  • 一個是全部的車站 var stations = [Station]()
  • 一個是輸入文字後,搜尋到的車站 var searchStations = [Station]()

再來 建立設置 UISearchController 的function

  1. 初始化SearchController
searchController = UISearchController(searchResultsController: nil)

2. 增加 UISearchResultsUpdating 的 delegate

class TRAStationTableViewController: UITableViewController, UISearchResultsUpdating {

並將指派屬性

searchController?.searchResultsUpdater = self

3. 在 navigation 中加入 searchController 搜尋列

navigationItem.searchController = searchController

接下來設置 Table View 的 numberOfRowsInSection 和 cellForRowAt

簡單來說就是 偵測 searchController 是否有被執行,如果有就顯示 搜尋到的車站 searchStations 。

最後就是如何 更新搜尋過後的 Table View ,要來比對字串!

使用 .filter

這樣基本搜尋功能就完成囉~~~

取得車站的動態即時到站時刻 — 車次是否誤點 (動態前後30分鐘的車次)

最後就是點選車站,顯示 動態前後30分鐘的車次 是否誤點。

在前一頁面的 Table View 需要傳值到下一頁。

接著車次的資訊 我們資料格式為

  • 車站 ID
  • 車站站名
  • 方向 (北上南下)
  • 火車種類 (區間、自強、莒光)
  • 終點站
  • 表定抵達時間
  • 誤點 (0:準點、≥1 誤點幾分鐘)

下載的方式跟前面一樣,網址部分帶入 stationID

最後就一點~文字顯示格式的部分啦~~~美化一下介面文字

車次時間

車次 準點或誤點的提示

利用 layer.masksToBounds = true

以及 layer.cornerRadius = 10 來設置背景圓角~~~

最後附上完整 Github 連結~~~

--

--

Anny
Anny

Written by Anny

If You Think You Can, You Can!

No responses yet