Driver SDK הוא ספרייה שאפשר לשלב באפליקציה לנהגים. זה כן באחריות לעדכן את Fleet Engine במיקום של הנהג, במסלול שלו המרחק שנותר וזמן ההגעה המשוער. הוא גם משתלב עם Navigation SDK, שמספק לנהג הוראות ניווט מפורטות.
דרישות מערכת מינימליות
דרישות מוקדמות
המדריך הזה מניח שהאפליקציה כבר מטמיעה Navigation SDK, Fleet Engine הקצה העורפי מוגדר וזמין. אבל הקוד לדוגמה מספק דוגמה לאופן שבו מגדירים Navigation SDK.
יש להפעיל גם את ה-SDK של מפות ל-iOS בפרויקט ב-Google Cloud וקבלת מפתח API.
פיתוח מקומי
לפיתוח מקומי, מספיק להתחבר באמצעות Cloud SDK.
gcloud
gcloud auth login
כתובת האימייל שמשמשת להתחברות חייבת להיות חברה בקבוצה ב-Workspace.
אוטומציה (פיתוח מערכות או אינטגרציה רציפה (CI)
מגדירים את מארחי האוטומציה בהתאם שיטות מומלצות:
אם התהליך פועל בסביבת Google Cloud, צריך להשתמש אוטומטית זיהוי של פרטי כניסה.
לחלופין, יש לאחסן את קובץ המפתח של חשבון השירות במיקום מאובטח את מערכת הקבצים של המארח ולהגדיר GOOGLE_APPLICATION_CREDENTIALS בהתאם למשתנה הסביבה.
כתובת האימייל של חשבון השירות המשויכת לפרטי הכניסה חייבת להיות חברה ב- קבוצת Workspace.
הגדרות אישיות של פרויקט
מנהל חבילות SWIFT
ניתן להתקין את ה-SDK של מנהל ההתקן דרך SWIFT Package Manager. כדי להוסיף את ה-SDK, צריך לוודא שיש לך הוסרו כל יחסי התלות הקיימים של Driver SDK.
כדי להוסיף את ה-SDK לפרויקט חדש או קיים:
-
פותחים את ה-Xcode
project
אוworkspace
, ועוברים אל File > (קובץ >) הוספת יחסי תלות של חבילה. - מזינים את כתובת ה-URL https://github.com/googlemaps/ios-driver-sdk ומקישים על Enter. כדי למשוך את החבילה, וללחוץ על "הוספת חבילה".
-
כדי להתקין
version
ספציפי, צריך להגדיר את השדה כלל תלות לאחד אפשרויות שמבוססות על גרסאות. בפרויקטים חדשים, מומלץ לציין את הגרסה האחרונה באמצעות "גרסה מדויקת" כאפשרות. בסיום, לוחצים על 'הוספת חבילה'. -
בחלון Choose Package Products, מוודאים שהתוסף
GoogleRidesharingDriver
יתווסף אל היעד שהגדרת ל-main
. בסיום, לוחצים על 'הוספת חבילה'. -
כדי לבדוק את ההתקנה, צריך לעבור לחלונית
General
של היעד. ב-Frameworks, ספריות ותוכן מוטמע אתם אמורים לראות את החבילות המותקנות. אפשר גם לראות את העמודה 'יחסי תלות של חבילה' הקטע של Project Navigator כדי לאמת את החבילה והגרסה שלה.
כדי לעדכן את package
בפרויקט קיים:
אם אתה משדרג מגרסה קודמת מ-9.0.0, עליך להסיר את יחסי התלות האלה:
GoogleMapsBase
,GoogleMapsCore
,GoogleMapsM4B
אחרי השדרוג. אל תסירו את התלות שלGoogleMaps
מידע נוסף זמין במאמר נתוני גרסה 9.0.0.בהגדרות האישיות של פרויקט Xcode, מחפשים את Frameworks, ספריות, ותוכן מוטמע. משתמשים בסימן המינוס(-) כדי להסיר את המסגרת הבאה:
GoogleMapsBase
(רק לשדרוגים מגרסאות מוקדמות יותר מ-9.0.0)GoogleMapsCore
(רק לשדרוגים מגרסאות מוקדמות יותר מ-9.0.0)GoogleMapsM4B
(רק לשדרוגים מגרסאות מוקדמות יותר מ-9.0.0)
- מ-Xcode, עוברים אל 'File >' חבילות > יש לעדכן לגרסאות האחרונות של החבילה".
- כדי לאמת את ההתקנה, עוברים לקטע Package Dependencies של Project Navigator כדי לאמת את החבילה והגרסה שלה.
כדי להסיר יחסי תלות קיימים של Driver SDK שנוספו באמצעות
CocoaPods
, יש לבצע את השלבים הבאים:
- סוגרים את סביבת העבודה של Xcode. פותחים את הטרמינל ומריצים את הפקודה הבאה:
sudo gem install cocoapods-deintegrate cocoapods-clean pod deintegrate pod cache clean --all
-
מסירים את
Podfile
,Podfile.resolved
ואת Xcodeworkspace
אם אתם לא משתמשים בהם לאף מטרה אחרת מלבד CocoaPods.
כדי להסיר את Driver SDK הקיים שהותקן ידנית, בצעו את השלבים הבאים:
בהגדרות האישיות של פרויקט Xcode, מחפשים את Frameworks, ספריות ותוכן מוטמע. משתמשים בסמל המינוס
(-)
כדי להסיר את המסגרת הבאה:GoogleRidesharingDriver.xcframework
מהספרייה ברמה העליונה של פרויקט Xcode, מסירים את חבילה של
GoogleRidesharingDriver
.
CocoaPods
כדי להגדיר את Driver SDK באמצעות CocoaPods, צריך את הפריטים הבאים:
- הכלי CocoaPods: כדי להתקין את הכלי הזה, פותחים את Terminal ומפעילים את הפקודה הבאה.
sudo gem install cocoapods
ליצור Podfile ל-Driver SDK ולהשתמש בו כדי להתקין את ה-API. יחסי התלות שלו: יוצרים קובץ בשם Podfile בספריית הפרויקט. הקובץ הזה מגדיר את יחסי התלות של הפרויקט. יש לערוך את ה-Podfile ולהוסיף אותו של יחסי התלות שלכם. לפניכם דוגמה שכוללת את יחסי התלות:
source "https://github.com/CocoaPods/Specs.git" target 'YOUR_APPLICATION_TARGET_NAME_HERE' do pod 'GoogleRidesharingDriver' end
כאן יש דוגמה שכוללת את רצפי האלפא והבטא של ה-SDK של מנהל ההתקן כיחסי תלות:
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
שומרים את ה-Podfile. פותחים טרמינל ועוברים לספרייה שמכילה את הפקודה Podfile:
cd <path-to-project>
מריצים את פקודת ההתקנה של pod. הפעולה הזו תתקין את ממשקי ה-API שצוינו Podfile, יחד עם כל יחסי התלות שיש להם.
pod install
סוגרים את Xcode ואז פותחים (לחיצה כפולה) את קובץ .xcworkspace של הפרויקט כדי להפעיל Xcode. מהשלב הזה ואילך צריך להשתמש כדי לפתוח את הפרויקט, לוחצים על קובץ .xcworkspace
קראו את המאמר תחילת העבודה של CocoaPods מדריך פרטים.
התקנה ידנית
XCFramework היא חבילה בינארית שבה משתמשים כדי להתקין את SDK של מנהל התקן. ניתן להשתמש בחבילה הזו בכמה פלטפורמות שונות, כולל מכונות שמשתמשות ב-Apple silicon. במדריך הזה נסביר להוסיף באופן ידני את ה-XCFramework שמכיל את ה-SDK של Drive לפרויקט והגדרת ה-build ב-Xcode.
מורידים את הקובץ הבינארי ומשאבים של ה-SDK:
מחלצים את הקבצים כדי לגשת ל-XCFramework ולמשאבים.
אפשר להתחיל ב-Xcode ולפתוח פרויקט קיים, או ליצור פרויקט חדש פרויקט. אם זו הפעם הראשונה שאתם משתמשים ב-iOS, יוצרים פרויקט חדש ובוחרים ב-iOS תבנית לאפליקציה.
יוצרים קבוצת Frameworks בקבוצת הפרויקט אם היא לא קיימת כבר.
כדי להתקין את Driver SDK, גוררים את הסמל קובץ אחד (
GoogleRidesharingDriver.xcframework
) בפרויקט בקטע Frameworks, ספריות ותוכן מוטמע. כשמופיעה בקשה, בוחרים באפשרות מעתיקים פריטים לפי הצורך.גוררים את
GoogleRidesharingDriver.bundle
שהורדתם לרמה העליונה של פרויקט ה-Xcode שלכם. כשמופיעה בקשה, בוחרים באפשרותCopy items if needed
.בוחרים את הפרויקט מ-Project Navigator ואז בוחרים היעד של האפליקציה.
פותחים את הכרטיסייה 'שלבי build', ובקטע Link Binary (קישור בינארי עם ספריות) מוסיפים את של הספריות והמסגרות הבאות, אם הן עדיין לא קיימות:
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
בוחרים בפרויקט שלכם (ולא ביעד ספציפי) ופותחים את Build בכרטיסייה 'הגדרות'. בקטע סימוני מקשר אחרים, מוסיפים
-ObjC
בשביל גם לניפוי באגים וגם להשקה. אם ההגדרות האלה לא מוצגות, שנו את בסרגל 'הגדרות Build', מבסיסי להכול.
בדיקת קובץ מניפסט הפרטיות של Apple
Apple דורשת פרטים לגבי הפרטיות של אפליקציות ב-App Store. עדכונים ומידע נוסף זמינים בדף פרטי הפרטיות של Apple App Store.
קובץ מניפסט הפרטיות של Apple כלול בחבילת המשאבים של ה-SDK. כדי לוודא שקובץ מניפסט הפרטיות נכלל וכדי לבדוק את התוכן שלו, יש ליצור ארכיון של האפליקציה ולהפיק דוח פרטיות מהארכיון.
הטמעת הרשאה ואימות
כשאפליקציית Drive יוצרת ושולחת עדכונים לקצה העורפי של Fleet Engine,
הבקשות חייבות לכלול אסימוני גישה תקפים. כדי לאשר
לאמת את הבקשות האלה, ה-SDK של מנהל התקן קורא לאובייקט שעומד בדרישות של
GMTDAuthorization
של Google. האובייקט אחראי לספק את אסימון הגישה הנדרש.
כמפתחי האפליקציה, אתם בוחרים איך האסימונים נוצרים. ההטמעה שלך צריכה להיות יכולת לבצע את הפעולות הבאות:
- מאחזרים אסימון גישה משרת HTTPS, כנראה בפורמט JSON.
- ניתוח האסימון ושמירה שלו במטמון.
- צריך לרענן את האסימון כשהתוקף שלו יפוג.
ניתן למצוא פרטים על האסימונים שנדרשים על ידי שרת Fleet Engine בכתובת יצירת אסימון רשת מבוסס JSON (JWT) להרשאה.
מזהה הספק זהה למזהה הפרויקט ב-Google Cloud. המדריך למשתמש ב-Fleet 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,
carID, 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
היא כן. כדי להגיב לעדכונים התקופתיים האלה,
האובייקט יכול להירשם לאירועי GMTDDeliveryVehicleReporter
על ידי תאימות ל
בפרוטוקול GMTDVehicleReporterListener
.
אתם יכולים לטפל באירועים הבאים:
vehicleReporter:didSucceedVehicleUpdate
מודיעה לאפליקציית הנהג על כך שהשירותים לקצה העורפי קיבלו בהצלחה עדכון המצב והמיקום של הרכבים.
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