1. 事前準備
本程式碼研究室將說明如何建立簡單的 iOS 應用程式,使用 Google 地圖平台導航 SDK 前往預先設定的目的地。
完成後,應用程式會如下所示。
必要條件
- 瞭解 Swift 的基本 iOS 應用程式開發知識。
- 對基本 Google 地圖 SDK 概念略知一二,例如以特定位置為中心建立地圖。
課程內容
- 如何建立使用 Navigation SDK 導覽至目的地的簡易 iOS Swift 應用程式。
- 如何從遠端 Cocoapods 存放區整合 Navigation SDK。
- 如何根據 Navigation SDK 使用者條款,管理位置存取權和使用者協議。
- 如何初始化 SDK。
- 如何設定目的地並開始導航。
軟硬體需求
- XCode 的最新穩定版。
- 已啟用結帳功能的 Google 帳戶和專案。
- 在 XCode 模擬器中執行的 iOS 裝置或模擬裝置。無論選擇哪個選項,其都必須符合 Navigation SDK 的最低需求。
2. 做好準備
如果您還沒有 Google Cloud Platform 帳戶和已啟用計費功能的專案,請按照Google 地圖平台的操作說明設定 Google Cloud 專案。
在控制台中選取 Google Cloud 專案
在 Cloud 控制台中,按一下專案下拉式選單,然後選取要用於這個程式碼研究室的專案。
在專案中啟用 Navigation SDK
在 Google Cloud Marketplace 中啟用本程式碼研究室所需的 Google 地圖平台 API 和 SDK。
前往 Google Cloud 控制台的「API 和服務」>「程式庫」,然後搜尋「Navigation SDK」。
系統應該會顯示一筆搜尋結果。
按一下「Navigation SDK」,開啟「產品詳細資料」頁面。按一下「啟用」,即可在專案中啟用 SDK。
針對 Google Maps SDK for iOS 重複這個程序。
建立 API 金鑰
在 Cloud 控制台的「憑證」頁面中產生 API 金鑰。所有 Google 地圖平台要求都需要 API 金鑰。在控制台的「憑證」頁面。按一下「+建立憑證」並選取頁面頂端的「API 金鑰」。
如要用於正式環境,最佳做法是為 API 金鑰設定應用程式限制,但在本程式碼研究室中,這並非必要。
3. 取得範例專案檔案
本節說明如何從這個程式碼研究室的 GitHub 存放區中複製檔案,以設定基本的空白 XCode 應用程式專案。GitHub 存放區中有程式碼研究室程式碼前後的版本,程式碼研究室會從空白專案範本開始,並建構至完成狀態。如果遇到問題,可以參考存放區中已完成的專案做為參考。
複製存放區或下載程式碼
前往要儲存程式碼研究室的目錄。
接著複製存放區或下載程式碼:
git clone https://github.com/googlemaps-samples/codelab-navigation-101-ios-swift
如果您沒有安裝 Git,請點選這個按鈕取得程式碼:
為了讓您盡快開始學習,這個存放區在 Starter
資料夾中提供了一些範例程式碼,方便您跟著本程式碼研究室學習。您也可以完成已完成的 Solution
專案,以便繼續操作或隨時查看進度。如要使用解決方案專案,您必須按照下方的「使用 Cocoapods 進行安裝」操作說明操作,然後從 solution/Navigation SDK Codelab
資料夾執行「pod update」指令。
在本機複製存放區後,請使用 XCode 將 Starter
資料夾當做現有專案開啟。確認專案可順利建構並執行。
連結裝置或設定 XCode 模擬工具
4. 在應用程式中加入 Navigation SDK
您可以透過三種方式將 Navigation SDK 整合至 XCode 專案:本程式碼研究室會使用 CocoaPods。如要進一步瞭解如何使用 Swift Package Manager 進行整合,或是要透過下載 SDK 手動安裝,請參閱 Navigation SDK 說明文件中的「建立 Xcode 專案並安裝 Navigation SDK」。
使用 Cocoapods 安裝
如果您還沒有 CocoaPods 工具,請在終端機上執行下列指令,即可在 macOS 中安裝這項工具。詳情請參閱 CocoaPods 入門指南。
sudo gem install cocoapods
在專案資料夾 (starter/Navigation SDK Codelab 資料夾內) 中,建立名為 Podfile 的新檔案 (在 XCode 中,依序前往「File」>「New」>「File」>「Other」>「Empty」,然後儲存為「Podfile」)
請將以下內容新增到 Podfile
:
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '15.0'
target 'Navigation SDK Codelab' do
pod 'GoogleNavigation', '9.1.1'
end
現省 Podfile
。
開啟終端機,並將目錄變更為 Podfile 的儲存位置 (這應該是程式碼研究室存放區中的「starter/Navigation SDK Codelab」資料夾)
cd "<path-to-starter-project-folder>/Navigation SDK Codelab"
執行 pod install
指令。此動作會安裝 Podfile
中指定的 API 及其所有依附元件
pod install
關閉 Xcode,接著開啟專案的 .xcworkspace 檔案來啟動 Xcode。從現在起,您必須使用 .xcworkspace 檔案來開啟專案。
檢查是否已新增 Pod 目錄,且該目錄包含「GoogleMaps」以及「GoogleNavigation」Pod
新增 API 金鑰
將 API 金鑰新增到您的 AppDelegate.swift
中,如下所示:
- 新增下列匯入陳述式:
import GoogleMaps
import GoogleNavigation
- 請將以下內容新增至
application(_:didFinishLaunchingWithOptions:)
方法:
GMSServices.provideAPIKey("YOUR_API_KEY")
取代「YOUR_API_KEY」也就是您在上一個步驟建立的 API 金鑰
建立專案並修正所有錯誤。
5. 設定應用程式權限
Navigation SDK 仰賴 GPS 訊號來提供道路背景的位置資訊和即時路線指引,因此應用程式必須要求使用者授予精確位置資料的存取權。
為此,您需要在 Xcode 中為應用程式的 Info.plist 新增一些屬性,並在應用程式中加入一些程式碼,以便在執行階段向使用者要求權限,以及處理任何錯誤,例如未授予權限或無法取得位置資訊。
在 Xcode 中開啟 Info.plist。看起來應該會像這樣
要求精確位置存取權
如要新增值,請將滑鼠游標懸停在「資訊資源清單」列上,直到出現「+」圖示。按一下「+」即可查看含有建議資源名稱的對話方塊,但請注意,您也可以手動新增資源。
將以下屬性和值新增至 Info.plist:
屬性 | 值 |
隱私權 - 位置資訊:一律允許、使用時允許 用途說明 | 「這個應用程式需要存取裝置位置資訊,才能提供即時路線導航服務」 |
隱私權 - 使用中位置資訊使用說明 | 「這個應用程式需要存取裝置位置資訊,才能提供即時路線導航功能」 |
allowsBackgroundLocationUpdates | 是 |
要求背景位置資訊存取權
在 Info.plist 中新增下列屬性和值:
UIBackgroundModes
> 新增資料列 > Item 0: App registers for location updates
(從建議的下拉式清單中選取這個值)
完成後,Info.plist 看起來會像這樣。
在執行階段要求位置存取權
將下列匯入陳述式新增至 ViewController.swift
:
import GoogleNavigation
將以下宣告新增至 ViewController 類別:
var locationManager: CLLocationManager!
為 loadView()
新增方法覆寫設定並呼叫 locationManager.requestAlwaysAuthorization()
:
override func loadView() {
locationManager = CLLocationManager()
locationManager.requestAlwaysAuthorization()
您的應用程式現在會向使用者要求位置資訊,並在使用者授予權限後提供給應用程式。
要求顯示通知的權限
請將下列程式碼新增至 loadView(),向使用者要求顯示通知的權限,因為您需要這項權限才能顯示導覽操作說明。
UNUserNotificationCenter.current().requestAuthorization(options: [.alert]) {
granted, error in
// Handle denied authorization to display notifications.
if !granted || error != nil {
print("User rejected request to display notifications.")
}
}
建構並執行應用程式,確認系統會提示您分享位置資訊並啟用通知。
6. 新增導覽使用者介面
在這個步驟中,您必須加入地圖,並設定成顯示地點。接著,系統會向使用者顯示對話方塊,列出 Navigation SDK 使用條款。
在應用程式中新增地圖檢視畫面
添加這行程式碼以宣告 ViewController 中的 GMSMapView 變數。
var mapView: GMSMapView!
將下列程式碼加進 Viewcontroller.swift
中的 loadView()
,即可初始化地圖。
let camera = GMSCameraPosition.camera(withLatitude: 51.483174, longitude: -0.177369, zoom: 14)
let options = GMSMapViewOptions()
options.camera = camera
options.frame = .zero
mapView = GMSMapView(options: options)
view = mapView
建構並執行應用程式,應該會看到以倫敦西南部為中心的地圖。
顯示 Navigation SDK 產品使用條款對話方塊
在與前一個程式碼相同的 loadView()
方法中,將下列程式碼新增至 ViewController.swift
。這會顯示 Navigation SDK 的使用者條款。如果未接受,系統就不會啟用導覽功能。
// Show the terms and conditions.
let companyName = "Navigation SDK Codelab"
GMSNavigationServices.showTermsAndConditionsDialogIfNeeded(withCompanyName: companyName) { termsAccepted in
if termsAccepted {
// Enable navigation if the user accepts the terms.
self.mapView.isNavigationEnabled = true
// Request authorization for alert notifications which deliver guidance instructions
// in the background.
} else {
// Handle the case when the user rejects the terms and conditions.
}
}
建構並執行應用程式,查看對話方塊。
7. 新增主要導覽事件的監聽器
這個步驟將說明如何設定重要事件的事件監聽器,例如抵達目的地,或是駕駛路線重新規劃路線。
如要監聽這些事件,您必須讓 View Controller 採用 GMSNavigatorListener
通訊協定。
將這個通訊協定新增至 ViewController.swift
中的類別定義。
class ViewController: UIViewController,
GMSNavigatorListener {
現在,請新增一行程式碼,在 loadView():
中設定事件監聽器
// Add a listener for GMSNavigator.
mapView.navigator?.add(self)
最後,在類別中新增兩個方法,以便處理要觸發的事件。
// Listener to handle arrival events.
func navigator(_ navigator: GMSNavigator, didArriveAt waypoint: GMSNavigationWaypoint) {
print("You have arrived at: \(waypoint.title)")
}
// Listener for route change events.
func navigatorDidChangeRoute(_ navigator: GMSNavigator) {
print("The route has changed.")
}
8. 設定目的地並開始導覽
本節將說明如何設定目的地,並開始導航指引。
為導覽邏輯建立新函式。
首先,請在 ViewController
中新增名為 startNav()
的函式。其中包含用來設定目的地並開始導航的邏輯。
// Create a route and start guidance.
@objc func startNav() {
}
為目的地建立 Waypoint
。
接下來,建立包含單一路線控點的目的地陣列。
// Create a route and start guidance.
@objc func startNav() {
var destinations = [GMSNavigationWaypoint]()
destinations.append(
GMSNavigationWaypoint.init(
placeID: "ChIJH-tBOc4EdkgRJ8aJ8P1CUxo",
title: "Trafalgar Square")!)
}
呼叫 setDestinations()
並處理回應。
接下來,請呼叫 setDestinations
並處理傳回的 GMSRouteStatus
。
如果 GMSRouteStatus
為「OK」,請先在 mapView
的 navigator
物件上設定 isGuidanceActive=true
,開始進行指引。否則,請輸出陳述式,指出發生錯誤。
如果傳回的 GMSRouteStatus
值為「OK」,請呼叫 mapView.locationSimulator.simulateLocationsAlongExistingRoute()
開始沿著路線模擬行駛。
// Create a route and start guidance.
@objc func startNav() {
var destinations = [GMSNavigationWaypoint]()
destinations.append(
GMSNavigationWaypoint.init(
placeID: "ChIJH-tBOc4EdkgRJ8aJ8P1CUxo",
title: "Trafalgar Square")!)
mapView.navigator?.setDestinations(
destinations
) { routeStatus in
guard routeStatus == .OK else {
print("Handle route statuses that are not OK.")
return
}
//If routeStatus is OK, start guidance.
self.mapView.navigator?.isGuidanceActive = true
//start simulating driving along the route. self.mapView.locationSimulator?.simulateLocationsAlongExistingRoute()
self.mapView.cameraMode = .following
}
}
處理常見的錯誤狀態
明確處理 GMSRouteStatus
錯誤很有幫助,尤其是在對新應用程式進行初步偵錯時。舉例來說,您可能會發現,由於偵錯設定,一開始會經常收到位置權限、API 金鑰或「找不到路線」錯誤,因此處理這些錯誤狀態很有幫助。
新增處理這些特定情況的程式碼,並將陳述式輸出至控制台。
mapView.navigator?.setDestinations(
destinations
) { routeStatus in
guard routeStatus == .OK else {
print("Handle route statuses that are not OK.")
switch routeStatus {
case .locationUnavailable:
print("Location unavailable.") //check permissions
case .noRouteFound:
print("No route found.") //check start location and destination
case .waypointError:
print("Waypoint error") //check Place ID
default:
print("Not sure what happened")
}
return
}
新增按鈕以開始導航指引
最後,請在 UI 中新增按鈕,並將其連結至 startNav 方法。使用以下程式碼建立名為 makeButton()
的方法。從 loadView()
呼叫 makeButton()
函式。
// Add a button to the view.
func makeButton() {
// A button to start navigation.
let navButton = UIButton(frame: CGRect(x: 5, y: 150, width: 200, height: 35))
navButton.backgroundColor = .blue
navButton.alpha = 0.5
navButton.setTitle("Start navigation", for: .normal)
navButton.addTarget(self, action: #selector(startNav), for: .touchUpInside)
self.mapView.addSubview(navButton)
}
建構並執行應用程式。
注意:請在
startNav()
呼叫
setDestinations()
方法,在使用的前 1,000 個目的地後產生費用。詳情請參閱「用量與計費」一文。
9. 恭喜!
你已抵達目的地,做得好!
您已建立了一個簡單的應用程式,使用 Google 地圖平台 Navigation SDK,提供前往目的地的即時路線導航指引。
您已設定應用程式權限和 Navigation SDK 使用者條款對話方塊,並使用地點 ID 指定目的地。您已在應用程式中處理各種成功和錯誤狀態。
10. 進一步瞭解
如果您想進一步開發應用程式,歡迎參考下列主題,從中汲取靈感。