حزمة Driver SDK هي مكتبة تدمجها في تطبيق السائق الخاص بك. وتكون مسؤولة عن تحديث Fleet Engine حسب الموقع الجغرافي للسائق ومساره والمسافة المتبقية والوقت المقدَّر للوصول. كما أنها تتكامل مع SDK للتنقل، والتي توفر إرشادات التنقل خطوة بخطوة للسائق.
الحد الأدنى من متطلبات النظام
المتطلبات الأساسية
يفترض هذا الدليل أنّ تطبيقك يستخدم حزمة تطوير البرامج (SDK) للتنقّل، وأنّ الخلفية Fleet Engine قد تم إعدادها وتوفّرها. ومع ذلك، يوفّر الرمز النموذجي نموذجًا عن كيفية إعداد حزمة تطوير البرامج (SDK) الخاصة بالتنقّل.
عليك أيضًا تفعيل حزمة تطوير البرامج بالاستناد إلى بيانات "خرائط Google" لنظام التشغيل iOS في مشروعك على Google Cloud والحصول على مفتاح واجهة برمجة تطبيقات.
الحصول على إذن بالوصول
إذا كنت أحد عملاء Google Workspace، عليك إنشاء
مجموعة Workspace، مثل
google-maps-platform-sdk-users@workspacedomain.com
أثناء عملية الإعداد،
وتقديم الاسم إلى Google. وهذا هو النهج الموصى به.
ستتم بعد ذلك إضافة مجموعة Workspace إلى قائمة مسموح بها
تمنح إمكانية الوصول إلى مستودعات CocoaPods الصحيحة. تأكد من أن هذه القائمة تتضمن عناوين البريد الإلكتروني للمستخدم
ورسائل البريد الإلكتروني لحساب الخدمة التي تحتاج إلى الوصول.
إذا لم تتمكّن مؤسستك من إنشاء "مجموعات Workspace"، يمكنك إرسال قائمة بعناوين البريد الإلكتروني لحساب المستخدم والخدمة التي تحتاج إلى الوصول إلى هذه العناصر إلى Google.
التنمية المحلية
يكفي تسجيل الدخول باستخدام حزمة تطوير البرامج (SDK) للسحابة الإلكترونية لأغراض التطوير المحلي.
gcloud
gcloud auth login
يجب أن يكون عنوان البريد الإلكتروني المُستخدَم لتسجيل الدخول عضوًا في مجموعة Workspace.
التشغيل الآلي (أنظمة بناء أو دمج مستمر)
عليك إعداد مضيفي التشغيل الآلي من خلال اتّباع أفضل الممارسات:
في حال إجراء العملية داخل بيئة Google Cloud، يمكنك استخدام الرصد التلقائي لبيانات الاعتماد.
بخلاف ذلك، عليك تخزين ملف مفتاح حساب الخدمة في موقع آمن على نظام ملفات المضيف وضبط متغيّر بيئة GOOGLE_APPLICATION_CREDENTIALS بشكل مناسب.
يجب أن يكون عنوان البريد الإلكتروني لحساب الخدمة المرتبط ببيانات الاعتماد عضوًا في Workspace Goup.
تكوين المشروع
يمكنك ضبط حزمة تطوير البرامج (SDK) للسائق باستخدام CocoaPods.
استخدام CocoaPods
لإعداد "حزمة تطوير البرامج (SDK) للسائق" باستخدام CocoaPods، ستحتاج إلى العناصر التالية:
- أداة CocoaPods: لتثبيت هذه الأداة، افتح المحطة الطرفية وشغِّل الأمر التالي.
shell sudo gem install cocoapods
يمكنك الرجوع إلى دليل بدء استخدام CocoaPods للحصول على مزيد من التفاصيل.
أنشئ Podfile لحزمة Driver SDK واستخدمه لتثبيت واجهة برمجة التطبيقات وتبعياتها: أنشئ ملفًا باسم Podfile في دليل المشروع. يحدد هذا الملف تبعيات مشروعك. قم بتحرير Podfile وأضف تبعياتك. فيما يلي مثال يتضمن التبعيات:
source "https://github.com/CocoaPods/Specs.git" target 'YOUR_APPLICATION_TARGET_NAME_HERE' do pod 'GoogleRidesharingDriver' end
احفظ Podfile. افتح الوحدة الطرفية وانتقل إلى الدليل الذي يحتوي على Podfile:
cd <path-to-project>
شغِّل أمر pod install. سيؤدي هذا إلى تثبيت واجهات برمجة التطبيقات المحددة في Podfile، بالإضافة إلى أي تبعيات قد تكون لديهم.
pod install
أغلق Xcode، ثم افتح (انقر نقرًا مزدوجًا) ملف .xcworkspace الخاص بمشروعك لتشغيل Xcode. من هذا الوقت فصاعدًا، يجب عليك استخدام ملف .xcworkspace لفتح المشروع.
إصدارات الإصدار الأولي أو التجريبي من حزمة تطوير البرامج (SDK)
لإعداد الإصدارات "ألفا" أو "الإصدار التجريبي" من "حزمة تطوير البرامج (SDK) لبرنامج التشغيل" لنظام التشغيل iOS، ستحتاج إلى العناصر التالية:
أداة CocoaPods: لتثبيت هذه الأداة، افتح المحطة الطرفية وشغِّل الأمر التالي.
sudo gem install cocoapods
للحصول على مزيد من التفاصيل، يمكنك الاطّلاع على دليل البدء في CocoaPods.
حساب التطوير الخاص بك في قائمة الوصول على Google. مستودع مجموعات الإعلانات المتسلسلة من الإصدار الأولي والإصدار التجريبي من حزمة تطوير البرامج (SDK) ليس مصدرًا عامًا. وللوصول إلى هذه الإصدارات، اتصل بمهندس عملاء Google. يضيف المهندس حساب التطوير الخاص بك إلى قائمة الوصول، ثم يضبط ملف تعريف ارتباط للمصادقة.
بعد أن يصبح مشروعك في قائمة الوصول، يمكنك الوصول إلى المجموعة.
أنشئ Podfile لحزمة Driver SDK لنظام التشغيل iOS واستخدمه لتثبيت واجهة برمجة التطبيقات وتبعياتها: أنشئ ملفًا باسم 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
احفظ Podfile. افتح الوحدة الطرفية وانتقل إلى الدليل الذي يحتوي على Podfile:
cd <path-to-project>
شغِّل أمر pod install. سيؤدي هذا إلى تثبيت واجهات برمجة التطبيقات المحددة في Podfile، بالإضافة إلى أي تبعيات قد تكون لديهم.
pod install
أغلق Xcode، ثم افتح (انقر نقرًا مزدوجًا) ملف .xcworkspace الخاص بمشروعك لتشغيل Xcode. من هذا الوقت فصاعدًا، يجب عليك استخدام ملف .xcworkspace لفتح المشروع.
تثبيت XCFramework
XCFramework هي حزمة ثنائية تستخدمها لتثبيت Driver SDK. يمكنك استخدام هذه الحزمة على أنظمة أساسية متعددة، بما في ذلك الأجهزة التي تستخدم شرائح M1. يوضِّح هذا الدليل كيفية إضافة XCFramework الذي يحتوي على حزمة Driver SDK يدويًا إلى مشروعك وضبط إعدادات الإصدار في Xcode.
تنزيل البرنامج الثنائي لحزمة SDK ومواردها:
فُكَّ ضغط الملفات المضغوطة للوصول إلى XCFramework والموارد.
شغِّل Xcode وافتح مشروعًا حاليًا أو أنشئ مشروعًا جديدًا. إذا كنت مستخدمًا جديدًا لنظام التشغيل iOS، أنشئ مشروعًا جديدًا واختَر نموذج تطبيق iOS.
أنشئ مجموعة أطر العمل ضمن مجموعة المشاريع إذا لم تكن موجودة بالفعل.
اسحب ملف
gRPCCertificates.bundle
الذي تم تنزيله إلى دليل المستوى الأعلى لمشروع Xcode. عندما يُطلب منك، حدد "نسخ العناصر" إذا لزم الأمر.لتثبيت Driver SDK، اسحب الملف
GoogleRidesharingDriver.xcframework
إلى مشروعك ضمن الأطر والمكتبات والمحتوى المضمّن. عندما يُطلب منك، حدد "نسخ العناصر" إذا لزم الأمر.اسحب ملف
GoogleRidesharingDriver.bundle
الذي تم تنزيله إلى دليل المستوى الأعلى لمشروع Xcode. اختَر "Copy items if needed
" عندما يُطلب منك ذلك.حدد مشروعك من Project Navigator (أداة استكشاف المشروع)، واختر هدف تطبيقك.
افتح علامة التبويب "مراحل الإنشاء"، وفي "ربط النظام الثنائي مع المكتبات"، أضف أطر العمل والمكتبات التالية إذا لم تكن موجودة بالفعل:
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
اختَر مشروعك بدلاً من هدف محدّد، وافتح علامة التبويب إعدادات الإنشاء. في القسم علامات رابط أخرى، أضِف
‑ObjC
لكل من تصحيح الأخطاء والإصدار. إذا لم تظهر هذه الإعدادات، عليك تغيير الفلتر في شريط "إعدادات الإصدار" من أساسي إلى الكل.
تنفيذ التفويض والمصادقة
عندما ينشئ تطبيق Drive تحديثات لخلفية Fleet Engine ويرسلها، يجب أن تتضمّن الطلبات رموز دخول صالحة. ولتفويض هذه الطلبات ومصادقتها، تستدعي Driver SDK العنصر الخاص بك بما يتوافق مع
بروتوكول GMTDAuthorization
. الكائن مسؤول عن توفير رمز الدخول المطلوب.
بصفتك مطوِّر التطبيق، يمكنك اختيار طريقة إنشاء الرموز المميّزة. ينبغي أن يوفر التنفيذ لديك إمكانية القيام بما يلي:
- استرجع رمز الدخول من خادم 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 وvehicleID وdriverContext وaccessTokenProvider. ويكون معرِّف الخدمة مماثلاً لرقم تعريف
مشروع Google Cloud. ويمكنك الوصول إلى النسخة الافتراضية GMTDDeliveryVehicleReporter
من واجهة برمجة تطبيقات برنامج التشغيل مباشرةً.
ينشئ المثال التالي مثيل 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];
}
يمكنك الاستماع اختياريًا إلى أحداث AutomotiveReporter.
يتم تعديل المركبة بشكل دوري من خلال "GMTDDeliveryVehicleReporter
" عندما
تكون قيمة "locationTrackingEnabled
" "نعم". للاستجابة لهذه التحديثات الدورية، يمكن لأي كائن الاشتراك في أحداث GMTDDeliveryVehicleReporter
من خلال التوافق مع
بروتوكول GMTDVehicleReporterListener
.
يمكنك معالجة الأحداث التالية:
vehicleReporter:didSucceedVehicleUpdate
يخبر تطبيق Driver تطبيق 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