פיתוח אפליקציית ניווט פשוטה ל-iOS ב-Swift באמצעות Google Maps Platform Navigation SDK

1. לפני שמתחילים

בשיעור הזה תלמדו איך ליצור אפליקציה פשוטה ל-iOS, שמשתמשת ב-SDK לניווט בפלטפורמה של מפות Google כדי לנווט ליעד מוגדר מראש.

כך ייראה האפליקציה אחרי שמסיימים.

7e7c194a98d6dfa4.png

דרישות מוקדמות

מה תלמדו

  • איך יוצרים אפליקציית iOS Swift פשוטה שמשתמשת ב-Navigation SDK כדי לנווט ליעד.
  • איך משלבים את Navigation SDK מהמאגר המרוחק של Cocoapods.
  • איך מנהלים את הרשאות המיקום ואת הסכמת המשתמש באמצעות התנאים של Navigation SDK למשתמש קצה.
  • איך לאתחל את ה-SDK.
  • איך מגדירים יעד ומתחילים את הוראות הניווט

מה צריך להכין

  • הגרסה היציבה האחרונה של XCode.
  • יש לכם חשבון Google ופרויקט שהופעלה בו חיוב.
  • מכשיר iOS או מכשיר אמולציה שפועלים בסימולטור XCode. בכל מקרה, היא חייבת לעמוד בדרישות המינימליות ל-Navigation SDK.

2. להגדרה

אם עדיין אין לכם חשבון Google Cloud Platform ופרויקט שהחיוב מופעל בו, מגדירים את הפרויקט ב-Google Cloud לפי ההוראות לתחילת העבודה עם הפלטפורמה של מפות Google.

בחירת פרויקט ב-Google Cloud במסוף

ב-Cloud Console, לוחצים על התפריט הנפתח של הפרויקט ובוחרים את הפרויקט שבו רוצים להשתמש ב-codelab הזה.

התפריט הנפתח של בורר הפרויקטים במסוף Google Cloud.

מפעילים את Navigation SDK בפרויקט

מפעילים את ממשקי ה-API וערכות ה-SDK של הפלטפורמה של מפות Google הנדרשים לסדנת הקוד הזו ב-Google Cloud Marketplace.

עוברים אל APIs & Services‏ > Library במסוף Google Cloud ומחפשים את Navigation SDK.

אמורה להופיע תוצאת חיפוש אחת.

המסך של API Library במסוף Google Cloud, שבו מוצג הדף של Navigation SDK.

לוחצים על Navigation SDK כדי לפתוח את הדף Product Details. לוחצים על Enable כדי להפעיל את ה-SDK בפרויקט.

חוזרים על התהליך הזה ב-Google Maps SDK ל-iOS.

יצירה של מפתח API

יוצרים מפתח API בדף Credentials במסוף Cloud. לכל הבקשות לפלטפורמה של מפות Google נדרש מפתח API. בדף Credentials במסוף. לוחצים על '+Create Credentials' (יצירת פרטי כניסה) בחלק העליון של הדף ובוחרים באפשרות 'API Key' (מפתח API).

לשימוש בסביבת ייצור, מומלץ להגדיר הגבלת אפליקציה למפתח ה-API, אבל זה לא חובה בקודלאב הזה.

3. הורדת קבצים של פרויקטים לדוגמה

בקטע הזה מוסבר איך להגדיר פרויקט בסיסי ריק של אפליקציית XCode על ידי שכפול קבצים ממאגר GitHub בשביל ה-Codelab הזה. המאגר ב-GitHub מכיל גרסאות לפני ואחרי של הקוד ב-codelab. בקודלאב נתחיל מתבנית פרויקט ריקה ונמשיך עד למצב הסופי. אם תיתקלו בבעיה, תוכלו להיעזר בפרויקט המוגמר במאגר.

שכפול המאגר או הורדה של הקוד

נכנסים לספרייה שבה רוצים לאחסן את ה-Codelab.

לאחר מכן, מעתיקים את המאגר או מורידים את הקוד:

git clone https://github.com/googlemaps-samples/codelab-navigation-101-ios-swift

אם עדיין לא התקנת את Git, לוחצים על הלחצן הזה כדי לקבל את הקוד:

כדי לעזור לכם להתחיל במהירות האפשרית, המאגר מכיל קוד להתחלה בתיקייה Starter שיעזור לכם לעקוב אחרי הקוד ב-Codelab הזה. יש גם פרויקט Solution שהושלם, למקרה שתרצו לדלג קדימה או לבדוק את ההתקדמות שלכם בכל שלב. כדי להשתמש בפרויקט הפתרון, עליכם לפעול לפי השלבים בקטע 'התקנה באמצעות Cocoapods' לאחר מכן, מריצים את 'עדכון pod' מהפקודה solution/Navigation SDK Codelab.

אחרי שכפול המאגר באופן מקומי, משתמשים ב-XCode כדי לפתוח את התיקייה Starter כפרויקט קיים. בודקים אם הפרויקט נוצר ופועל.

חיבור מכשיר או הגדרת סימולטור XCode

4. הוספת Navigation SDK לאפליקציה

יש שלוש דרכים לשלב את Navigation SDK בפרויקט XCode: בשיעור הזה נעשה שימוש ב-CocoaPods. מידע נוסף על שילוב באמצעות Swift Package Manager, או על התקנה ידנית באמצעות הורדת ה-SDK, זמין במאמר יצירת פרויקט Xcode והתקנת Navigation SDK במסמכי התיעוד של Navigation SDK.

התקנה באמצעות Cocoapods

אם עדיין לא התקנתם את הכלי CocoaPods, מריצים את הפקודה הבאה בטרמינל כדי להתקין אותו ב-macOS. לפרטים נוספים, אפשר לעיין במדריך לתחילת העבודה של CocoaPods.

sudo gem install cocoapods

יוצרים קובץ חדש בשם Podfile בתיקיית הפרויקט, בתוך התיקייה starter/Navigation SDK Codelab (ב-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/ניווט SDK Codelab' במאגר Codelab)

cd "<path-to-starter-project-folder>/Navigation SDK Codelab"

מריצים את הפקודה pod install. הפעולה הזו מתקינה את ממשקי ה-API שצוינו ב-Podfile, יחד עם יחסי התלות

pod install

סוגרים את Xcode ופותחים את קובץ ה-‎.xcworkspace של הפרויקט כדי להפעיל את Xcode. מהשלב הזה ואילך, צריך להשתמש בקובץ .xcworkspace כדי לפתוח את הפרויקט.

מוודאים שנוספה ספריית Pods למבנה הפרויקט ושהיא מכילה את 'GoogleMaps' ו-GoogleNavigation Pods.

6e81772ee067d452.png

הוספה של מפתח API

מוסיפים את מפתח ה-API ל-AppDelegate.swift באופן הבא:

  1. הוסף את הצהרות הייבוא הבאות:
import GoogleMaps
import GoogleNavigation
  1. מוסיפים את הקוד הבא לשיטה application(_:didFinishLaunchingWithOptions:):
GMSServices.provideAPIKey("YOUR_API_KEY")

מחליפים את YOUR_API_KEY במפתח ה-API שיצרתם בשלב הקודם.

מריצים את הפרויקט ומתקנים שגיאות.

5. הגדרת ההרשאות שניתנות לאפליקציה

ערכת ה-SDK של הניווט מסתמכת על אותות GPS כדי לספק מיקום מדויק בכביש והנחיות מפורטות, לכן האפליקציה תצטרך לבקש מהמשתמש להעניק גישה לנתוני המיקום המדויקים.

לשם כך, צריך להוסיף מאפיינים מסוימים ל-Info.plist של האפליקציות ב-Xcode, להוסיף קוד לאפליקציה כדי לבקש הרשאה מהמשתמש בזמן הריצה ולטפל בשגיאות כמו אי מתן הרשאה או אי-זמינות של המיקום.

פותחים את Info.plist ב-Xcode. הוא אמור להיראות כך.

6532a85bd9ac8fb4.png

בקשת הרשאה למיקום מדויק

כדי להוסיף ערכים חדשים, מעבירים את סמן העכבר מעל השורה 'רשימת נכסי המידע' עד שמופיע סמל הפלוס '+'. לוחצים על הסמל '+' כדי להציג תיבת דו-שיח עם הצעות לשמות של נכסים. עם זאת, חשוב לזכור שאפשר גם להוסיף נכסים באופן ידני.

מוסיפים את המאפיינים והערכים הבאים ל-Info.plist:

נכס

ערך

Privacy - Location Always And When In Use Usage Description

"לאפליקציה הזו נדרשת גישה למיקום של המכשיר כדי לספק ניווט לפי מסלול מפורט"

Privacy - Location When In Use Usage Description

"לאפליקציה הזו נדרשת גישה למיקום של המכשיר כדי לספק ניווט לפי מסלול מפורט"

allowsBackgroundLocationUpdates

כן

שליחת בקשה להרשאת מיקום ברקע

מוסיפים את המאפיינים והערכים הבאים ל-Info.plist:

UIBackgroundModes > הוספת שורה > Item 0: App registers for location updates (בוחרים את הערך הזה מהרשימה הנפתחת של ההצעות)

קובץ Info.plist אמור להיראות בערך כך בסיום.

3b0c49018451d0ff.png

בקשת גישה למיקום בזמן ריצה

הוסף את הצהרות הייבוא הבאות ל-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.")
          }
        }

מפתחים ומפעילים את האפליקציה ובודקים אם מופיעה בקשה לשתף את המיקום ולהפעיל התראות.

ad5f665a21170c49.png

6. הוספת ממשק משתמש לניווט

בשלב הזה מוסיפים מפה ומגדירים אותה כך שתציג מיקום. לאחר מכן תוצג למשתמש תיבת דו-שיח עם התנאים וההגבלות של Navigation SDK.

הוספת תצוגת מפה לאפליקציה

מוסיפים את השורה הזו כדי להצהיר על משתנה GMSMapView ב-ViewController.

var mapView: GMSMapView!

צריך להוסיף את הקוד הבא אל loadView() ב-Viewcontroller.swift כדי לאתחל את המפה.

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

מפתחים ומריצים את האפליקציה. אמורה להופיע מפה שממוקדת בדרום-מערב לונדון.

1d46ce5c0851cae3.png

הצגת התנאים וההגבלות של המוצר Navigation SDK

מוסיפים את הקוד הבא ל-ViewController.swift באותה שיטת loadView() כמו הקוד הקודם. כאן יוצגו התנאים וההגבלות של משתמשי הקצה של 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.
  }
}

יוצרים ומפעילים את האפליקציה כדי לראות את תיבת הדו-שיח.

29f17ae5b4c07c9f.png

7. הוספת מאזינים לאירועי ניווט מרכזיים

בשלב הזה מוסבר איך להגדיר מאזינים לאירועים מרכזיים, כמו הגעה ליעד או שינוי המסלול של הנהג.

כדי להאזין לאירועים האלה, בקרן התצוגה צריך לאמץ את פרוטוקול GMSNavigatorListener.

מוסיפים את הפרוטוקול הזה להגדרת הכיתה ב-ViewController.swift.

class ViewController: UIViewController,
                      GMSNavigatorListener {

עכשיו צריך להוסיף שורת קוד כדי להגדיר את ה-listener ב-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. הגדרת יעד והתחלת ההנחיות

בקטע הזה נסביר איך להגדיר יעד ולהתחיל בהנחיות ניווט.

יוצרים פונקציה חדשה ללוגיקה של הניווט.

קודם כול, מוסיפים פונקציה חדשה בשם startNav() ל-ViewController. הקוד הזה יכיל את הלוגיקה להגדרת יעד ולהפעלת הניווט.

// 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', מתחילים את ההדרכה על ידי הגדרת isGuidanceActive=true באובייקט navigator של mapView. אחרת, הדפס הצהרה כדי להראות שהייתה שגיאה.

אם הערך של 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
  }

להוספת לחצן כדי להתחיל בהנחיית הניווט

לסיום, מוסיפים לחצן לממשק המשתמש ומקשרים אותו ל-method‏ startNav. יוצרים method בשם makeButton() באמצעות הקוד הבא. קוראים לפונקציה makeButton() מתוך loadView().

// 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. מעולה!

כל הכבוד – הגעת ליעד!

7a69dcb75c904d7.png

יצרת אפליקציה פשוטה שמספקת מסלול ניווט מפורט ליעד באמצעות ערכת ה-SDK לניווט בפלטפורמה של מפות Google.

הגדרתם את הרשאות האפליקציה ואת תיבת הדו-שיח של התנאים של משתמשי הקצה של Navigation SDK, וציינתם יעד באמצעות מזהה מקום. טיפלת במצבים שונים של הצלחה ושגיאות באפליקציה שלך.

10. עוד צעד אחד קדימה

אם אתם רוצים להמשיך לפתח אפליקציות, כדאי לעיין בנושאים הבאים כדי לקבל השראה.

  • האזנה לאירועי ניווט נוספים. צריך להוסיף קוד להצגת הודעה אם הזמן שנשאר או המרחק חורגים מסף מסוים.
  • להתאים אישית את ממשק הניווט.
  • אם אתם רוצים להתנסות באתגר גדול יותר, תוכלו לנסות להוסיף בורר מקומות של Places API כדי לאפשר למשתמש להגדיר את היעד. טיפ: באפליקציות הדגמה של Navigation SDK יש הטמעה לדוגמה. כדי לראות את הקוד, מריצים את הפקודה pod try GoogleNavigation בתיקיית הפרויקט.