תחילת העבודה עם ה-SDK של Drive ל-iOS

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

דרישות מערכת מינימליות

  • במכשיר הנייד צריכה לפעול מערכת iOS מגרסה 14 ואילך.
  • Xcode מגרסה 14 ואילך.
  • דרישות מוקדמות

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

    בנוסף, עליכם להפעיל את Maps SDK for iOS בפרויקט ב-Google Cloud ולקבל מפתח API.

    קבלת גישה

    אם אתם לקוחות Google Workspace, במהלך תהליך ההצטרפות כדאי ליצור קבוצת Workspace, כמו google-maps-platform-sdk-users@workspacedomain.com, ולתת ל-Google את השם. זו הגישה המומלצת. לאחר מכן הקבוצה ב-Workspace תתווסף לרשימת היתרים שמעניקה גישה למאגרים הנכונים של CocoaPods. מוודאים שכתובות האימייל של המשתמשים וכתובות האימייל של חשבונות השירות שזקוקים לגישה נכללות ברשימה הזו.

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

    פיתוח מקומי

    לפיתוח מקומי מספיק להתחבר באמצעות Cloud SDK.

    gcloud

    gcloud auth login
    

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

    אוטומציה (בניית מערכות או אינטגרציה רציפה (CI)

    מגדירים את המארחים לפעולות אוטומטיות בהתאם לשיטות המומלצות:

    • אם התהליך פועל בסביבה של Google Cloud, צריך להשתמש בזיהוי אוטומטי של פרטי כניסה.

    • אם לא, מאחסנים את קובץ המפתח של חשבון השירות במיקום מאובטח במערכת הקבצים של המארח ומגדירים את משתנה הסביבה GOOGLE_APPLICATION_CREDENTIALS בהתאם.

    כתובת האימייל של חשבון השירות שמשויך לפרטי הכניסה חייבת להיות חלק מ-Workspace Goup.

    הגדרת הפרויקט

    אתם יכולים להגדיר את ה-SDK של Drive באמצעות CocoaPods.

    שימוש ב-CocoaPods

    כדי להגדיר את Driver SDK באמצעות CocoaPods, אתם צריכים את הפריטים הבאים:

    • הכלי CocoaPods: כדי להתקין את הכלי הזה, פותחים את Terminal ומריצים את הפקודה הבאה. shell sudo gem install cocoapods למידע נוסף תוכלו להיעזר במדריך לתחילת העבודה של CocoaPods.
    1. יוצרים קובץ Podfile ל-Driver SDK ומשתמשים בו כדי להתקין את ה-API ואת יחסי התלות שלו: יוצרים קובץ בשם Podfile בספריית הפרויקט. הקובץ הזה מגדיר את יחסי התלות של הפרויקט שלכם. עורכים את ה-Podfile ומוסיפים את יחסי התלות. הדוגמה הבאה כוללת את יחסי התלות:

      source "https://github.com/CocoaPods/Specs.git"
      
      target 'YOUR_APPLICATION_TARGET_NAME_HERE' do
        pod 'GoogleRidesharingDriver'
      end
      
    2. שומרים את קובץ ה-Podfile. פותחים טרמינל ועוברים לספרייה שמכילה את ה-Podfile:

      cd <path-to-project>
      
    3. מריצים את הפקודה להתקנת pod. הפעולה הזו תתקין את ממשקי ה-API שצוינו ב-Podfile, יחד עם כל יחסי התלות שלהם.

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

    גרסאות אלפא/בטא של SDK

    כדי להגדיר גרסאות אלפא או בטא של Driver SDK ל-iOS, צריך את הפריטים הבאים:

    • הכלי CocoaPods: כדי להתקין את הכלי הזה, פותחים את Terminal ומריצים את הפקודה הבאה.

      sudo gem install cocoapods
      

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

    • חשבון הפיתוח שלך ברשימת הגישה ב-Google. מאגר הפודים של גרסאות האלפא והבטא של ה-SDK הוא לא מקור ציבורי. כדי לקבל גישה לגרסאות האלה, צריך לפנות למהנדס הלקוחות של Google. מהנדס התוכנה מוסיף את חשבון הפיתוח שלכם לרשימת הגישה ואז מגדיר קובץ cookie לצורך אימות.

    כשהפרויקט נמצא ברשימת הגישה, אפשר לגשת ל-pod.

    1. יוצרים Podfile ל-Driver SDK ל-iOS, ומשתמשים בו כדי להתקין את ה-API ואת יחסי התלות שלו: יוצרים קובץ בשם Podfile בספריית הפרויקט. הקובץ הזה מגדיר את יחסי התלות של הפרויקט שלכם. עורכים את ה-Podfile ומוסיפים את יחסי התלות. הדוגמה הבאה כוללת את יחסי התלות:

      source "https://cpdc-eap.googlesource.com/ridesharing-driver-sdk.git"
      source "https://github.com/CocoaPods/Specs.git"
      
      target 'YOUR_APPLICATION_TARGET_NAME_HERE' do
        pod 'GoogleRidesharingDriver'
      end
      
    2. שומרים את קובץ ה-Podfile. פותחים טרמינל ועוברים לספרייה שמכילה את ה-Podfile:

      cd <path-to-project>
      
    3. מריצים את הפקודה להתקנת pod. הפעולה הזו תתקין את ממשקי ה-API שצוינו ב-Podfile, יחד עם כל יחסי התלות שלהם.

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

    התקנת ה-XCFramework

    XCFramework הוא חבילה בינארית שבה משתמשים כדי להתקין את Driver SDK. אפשר להשתמש בחבילה הזו בכמה פלטפורמות, כולל מכונות שמשתמשות בערכת שבבים M1. במדריך הזה מוסבר איך להוסיף לפרויקט באופן ידני את ה-XCFramework שמכיל את Driver SDK, ולקבוע את הגדרות ה-build ב-Xcode.

    צריך להוריד את הקובץ הבינארי ואת המשאבים של ה-SDK:

    1. מחלצים את הקבצים הדחוסים כדי לגשת ל-XCFramework ולמשאבים.

    2. מפעילים את Xcode ופותחים פרויקט קיים או יוצרים פרויקט חדש. אם זו הפעם הראשונה שאתם משתמשים ב-iOS, תוכלו ליצור פרויקט חדש ולבחור את התבנית של האפליקציה ל-iOS.

    3. אם עדיין לא קיימת קבוצת פרויקטים, יוצרים קבוצת מסגרות בקבוצת הפרויקטים.

    4. גוררים את קובץ gRPCCertificates.bundle שהורד לספרייה ברמה העליונה של פרויקט ה-Xcode. כשתתבקשו, בחרו באפשרות 'העתקת פריטים' לפי הצורך.

    5. כדי להתקין את Driver SDK, גוררים את הקובץ GoogleRidesharingDriver.xcframework לפרויקט בקטע Frameworks, ספריות ותוכן מוטמע. כשתתבקשו, בחרו באפשרות 'העתקת פריטים' לפי הצורך.

    6. גוררים את הקובץ GoogleRidesharingDriver.bundle שהורדתם לספרייה ברמה העליונה של פרויקט ה-Xcode. כשמופיעה בקשה, בוחרים Copy items if needed.

    7. בוחרים את הפרויקט מתוך Project Navigator, ובוחרים את יעד האפליקציה.

    8. פותחים את הכרטיסייה Build Phases וב-Link Binary with Libraries מוסיפים את ה-frameworks והספריות הבאים אם הם עדיין לא קיימים:

      • Accelerate.framework
      • AudioToolbox.framework
      • AVFoundation.framework
      • CoreData.framework
      • CoreGraphics.framework
      • CoreLocation.framework
      • CoreTelephony.framework
      • CoreText.framework
      • GLKit.framework
      • ImageIO.framework
      • libc++.tbd
      • libxml2.tbd
      • libz.tbd
      • LocalAuthentication.framework
      • OpenGLES.framework
      • QuartzCore.framework
      • SystemConfiguration.framework
      • UIKit.framework
      • WebKit.framework
    9. בוחרים את הפרויקט במקום ביעד ספציפי, ופותחים את הכרטיסייה Build Settings (הגדרות build). בקטע Other Linker flags מוסיפים את ‑ObjC לניפוי הבאגים ולשחרור הנתונים. אם ההגדרות האלה לא גלויות, משנים את המסנן בסרגל ההגדרות של Build מ-Basic (בסיסי) ל-All (הכול).

    יישום הרשאה ואימות

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

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

    • מאחזרים אסימון גישה, כנראה בפורמט JSON, משרת HTTPS.
    • ניתוח ושמירה של האסימון במטמון.
    • מרעננים את האסימון כשהתוקף שלו פג.

    לפרטים על האסימונים הצפויים על ידי שרת Fleet Engine, ראו יצירת JSON Web Token (JWT) להרשאה.

    מזהה הספק זהה למזהה הפרויקט ב-Google Cloud. מידע נוסף זמין במדריך למשתמש של Flet Engine Deliveries API.

    בדוגמה הבאה מוטמע ספק של אסימון גישה:

    #import "SampleAccessTokenProvider.h"
    #import <GoogleRidesharingDriver/GoogleRidesharingDriver.h>
    
    // SampleAccessTokenProvider.h
    @interface SampleAccessTokenProvider : NSObject<GMTDAuthorization>
    @end
    
    static NSString *const PROVIDER_URL = @"INSERT_YOUR_TOKEN_PROVIDER_URL";
    
    // SampleAccessTokenProvider.m
    @implementation SampleAccessTokenProvider{
      // The cached vehicle token.
      NSString *_cachedVehicleToken;
      // Keep track of the vehicle ID the cached token is for.
      NSString *_lastKnownVehicleID;
      // Keep track of when tokens expire for caching.
      NSTimeInterval _tokenExpiration;
    }
    
    - (void)fetchTokenWithContext:(nullable GMTDAuthorizationContext *)authorizationContext
                       completion:(nonnull GMTDAuthTokenFetchCompletionHandler)completion {
      if (!completion) {
        NSAssert(NO, @"%s encountered an unexpected nil completion.", __PRETTY_FUNCTION__);
        return;
      }
    
      // Get the vehicle ID from the authorizationContext. This is set by the Driver SDK.
      NSString *vehicleID = authorizationContext.vehicleID;
      if (!vehicleID) {
        NSAssert(NO, @"Vehicle ID is missing from authorizationContext.");
        return;
      }
    
    // Clear cached vehicle token if vehicle ID has changed.
      if (![_lastKnownVehicleID isEqual:vehicleID]) {
        _tokenExpiration = 0.0;
        _cachedVehicleToken = nil;
      }
      _lastKnownVehicleID = vehicleID;
    
      // Clear cached vehicle token if it has expired.
      if ([[NSDate date] timeIntervalSince1970] > _tokenExpiration) {
        _cachedVehicleToken = nil;
      }
    
      // If appropriate, use the cached token.
      if (_cachedVehicleToken) {
        completion(_cachedVehicleToken, nil);
        return;
      }
      // Otherwise, try to fetch a new token from your server.
      NSURL *requestURL = [NSURL URLWithString:PROVIDER_URL];
      NSMutableURLRequest *request = 
                              [[NSMutableURLRequest alloc] initWithURL:requestURL];
      request.HTTPMethod = @"GET";
      // Replace the following key values with the appropriate keys based on your
      // server's expected response.
      NSString *vehicleTokenKey = @"VEHICLE_TOKEN_KEY";
      NSString *tokenExpirationKey = @"TOKEN_EXPIRATION";
      __weak typeof(self) weakSelf = self;
      void (^handler)(NSData *_Nullable data, NSURLResponse *_Nullable response,
                      NSError *_Nullable error) =
          ^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
            typeof(self) strongSelf = weakSelf;
            if (error) {
              completion(nil, error);
              return;
            }
    
            NSError *JSONError;
            NSMutableDictionary *JSONResponse =
                [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&JSONError];
    
            if (JSONError) {
              completion(nil, JSONError);
              return;
            } else {
              // Sample code only. No validation logic.
              id expirationData = JSONResponse[tokenExpirationKey];
              if ([expirationData isKindOfClass:[NSNumber class]]) {
                NSTimeInterval expirationTime = ((NSNumber *)expirationData).doubleValue;
                strongSelf->_tokenExpiration = [[NSDate date] timeIntervalSince1970] + expirationTime;
              }
              strongSelf->_cachedVehicleToken = JSONResponse[vehicleTokenKey];
              completion(JSONResponse[vehicleTokenKey], nil);
            }
        };
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *mainQueueURLSession =  
           [NSURLSession  sessionWithConfiguration:config delegate:nil
    delegateQueue:[NSOperationQueue mainQueue]];
    NSURLSessionDataTask *task = [mainQueueURLSession dataTaskWithRequest:request completionHandler:handler];
    [task resume];
    }
    
    @end
    

    יצירת מכונת DeliveryDriverAPI

    כדי לקבל את המכונה GMTDDeliveryVehicleReporter, קודם צריך ליצור מכונה של GMTDDeliveryDriverAPI באמצעות ה-providerID, ה-vehicleID, ה-driveContext ו-accessTokenProvider. ה-providerID זהה למזהה הפרויקט ב-Google Cloud. ואפשר לגשת למכונה GMTDDeliveryVehicleReporter ישירות מה-API של מנהל ההתקן.

    הדוגמה הבאה יוצרת מופע של GMTDDeliveryDriverAPI:

    #import “SampleViewController.h”
    #import “SampleAccessTokenProvider.h”
    #import <GoogleRidesharingDriver/GoogleRidesharingDriver.h>
    
    static NSString *const PROVIDER_ID = @"INSERT_YOUR_PROVIDER_ID";
    
    @implementation SampleViewController {
     GMSMapView *_mapView;
    }
    
    - (void)viewDidLoad {
      NSString *vehicleID = @"INSERT_CREATED_VEHICLE_ID";
      SampleAccessTokenProvider *accessTokenProvider = 
                                    [[SampleAccessTokenProvider alloc] init];
      GMTDDriverContext *driverContext = 
         [[GMTDDriverContext alloc] initWithAccessTokenProvider:accessTokenProvider
                                                     providerID:PROVIDER_ID 
                                                  vehicleID:vehicleID 
          navigator:_mapView.navigator];
    
      GMTDDeliveryDriverAPI *deliveryDriverAPI = [[GMTDDeliveryDriverAPI alloc] initWithDriverContext:driverContext];
    }
    

    אופציונלי: אפשר להאזין לאירועים של VehicleReporter

    המערכת מעדכנת את הרכב מדי פעם על ידי GMTDDeliveryVehicleReporter אם הערך של locationTrackingEnabled הוא YES. כדי להגיב לעדכונים התקופתיים האלה, כל אובייקט יכול להירשם לאירועי GMTDDeliveryVehicleReporter בהתאם לפרוטוקול GMTDVehicleReporterListener.

    אפשר לטפל באירועים הבאים:

    • vehicleReporter:didSucceedVehicleUpdate

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

    • vehicleReporter:didFailVehicleUpdate:withError

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

    הדוגמה הבאה מטפלת באירועים האלה:

    SampleViewController.h
    @interface SampleViewController : UIViewController<GMTDVehicleReporterListener>
    @end
    
    SampleViewController.m
    #import “SampleViewController.h”
    #import “SampleAccessTokenProvider.h”
    #import <GoogleRidesharingDriver/GoogleRidesharingDriver.h>
    
    static NSString *const PROVIDER_ID = @"INSERT_YOUR_PROVIDER_ID";
    
    @implementation SampleViewController {
     GMSMapView *_mapView;
    }
    
    
    - (void)viewDidLoad {
      // ASSUMES YOU IMPLEMENTED HAVE THE SAMPLE CODE UP TO THIS STEP.
      [ridesharingDriverAPI.vehicleReporter addListener:self];
    }
    
    - (void)vehicleReporter:(GMTDDeliveryVehicleReporter *)vehicleReporter didSucceedVehicleUpdate:(GMTDVehicleUpdate *)vehicleUpdate {
      // Handle update succeeded.
    }
    
    - (void)vehicleReporter:(GMTDDeliveryVehicleReporter *)vehicleReporter didFailVehicleUpdate:(GMTDVehicleUpdate *)vehicleUpdate withError:(NSError *)error {
      // Handle update failed.
    }
    
    @end
    

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

    כדי להפעיל מעקב אחר מיקום, האפליקציה יכולה להגדיר את locationTrackingEnabled לערך YES ב-GMTDDeliveryVehicleReporter. לאחר מכן GMTDDeliveryVehicleReporter = ישלח באופן אוטומטי עדכוני מיקום. כשהיעד GMSNavigator במצב ניווט (כשיעד מוגדר דרך setDestinations) ומוגדר ל-locationTrackingEnabled לערך YES, יישלחו באופן אוטומטי גם עדכוני מסלול וזמן הגעה משוער על ידי GMTDDeliveryVehicleReporter.

    המסלול שנקבע במהלך העדכונים האלה יהיה זהה למסלול שאליו הנהג ננווט במהלך סשן הניווט. לכן, כדי שהמעקב אחרי משלוחים יפעל בצורה תקינה, ציון הדרך שמוגדר דרך -setDestinations:callback: צריך להיות תואם ליעד שהוגדר בקצה העורפי של Fleet Engine.

    הדוגמה הבאה מפעילה מעקב אחר מיקום:

    SampleViewController.m
    #import “SampleViewController.h”
    #import “SampleAccessTokenProvider.h”
    #import <GoogleRidesharingDriver/GoogleRidesharingDriver.h>
    
    static NSString *const PROVIDER_ID = @"INSERT_YOUR_PROVIDER_ID";
    
    @implementation SampleViewController {
     GMSMapView *_mapView; 
    }
    
    - (void)viewDidLoad {
      // ASSUMES YOU IMPLEMENTED HAVE THE SAMPLE CODE UP TO THIS STEP.
      deliveryDriverAPI.vehicleReporter.locationTrackingEnabled = YES;
    }
    
    @end
    

    כברירת מחדל, מרווח הדיווח הוא 10 שניות, אבל אפשר לשנות את מרווח הדיווח באמצעות locationUpdateInterval. מרווח העדכון המינימלי הנתמך הוא 5 שניות. מרווח העדכון המקסימלי הנתמך הוא 60 שניות. עדכונים תכופים יותר עלולים לגרום לשגיאות ולבקשות איטיות יותר.

    השבתה של עדכוני מיקום

    האפליקציה יכולה להשבית את עדכוני המיקום של הרכב. לדוגמה, כשמשמרת נהג/ת מסתיימת, האפליקציה יכולה להגדיר את locationTrackingEnabled לערך NO.

      _vehicleReporter.locationTrackingEnabled = NO
    

    טיפול בשגיאות update_mask

    כש-GMTDDeliveryVehicleReporter שולח עדכון רכב, יכולה להופיע השגיאה update_mask כשהמסכה ריקה, ובדרך כלל היא מתרחשת בעדכון הראשון אחרי ההפעלה. הדוגמה הבאה מראה איך לטפל בשגיאה הזו:

    Swift

    import GoogleRidesharingDriver
    
    class VehicleReporterListener: NSObject, GMTDVehicleReporterListener {
      func vehicleReporter(
        _ vehicleReporter: GMTDVehicleReporter,
        didFail vehicleUpdate: GMTDVehicleUpdate,
        withError error: Error
      ) {
        let fullError = error as NSError
        if let innerError = fullError.userInfo[NSUnderlyingErrorKey] as? NSError {
          let innerFullError = innerError as NSError
          if innerFullError.localizedDescription.contains("update_mask cannot be empty") {
            emptyMaskUpdates += 1
            return
          }
        }
        failedUpdates += 1
      }
    
      override init() {
        emptyMaskUpdates = 0
        failedUpdates = 0
      }
    }
    
    

    Objective-C

    #import "VehicleReporterListener.h"
    #import <GoogleRidesharingDriver/GoogleRidesharingDriver.h>
    
    @implementation VehicleReporterListener {
      NSInteger emptyMaskUpdates = 0;
      NSInteger failedUpdates = 0;
    }
    
    - (void)vehicleReporter:(GMTDVehicleReporter *)vehicleReporter
      didFailVehicleUpdate:(GMTDVehicleUpdate *)vehicleUpdate
                 withError:(NSError *)error {
      for (NSError *underlyingError in error.underlyingErrors) {
        if ([underlyingError.localizedDescription containsString:@"update_mask cannot be empty"]) {
          emptyMaskUpdates += 1;
          return;
        }
      }
      failedUpdates += 1
    }
    
    @end