כדי לקרוא ל-Google Cloud API מהאפליקציה, צריך ליצור REST API ביניים שמטפל בהרשאות ומגן על ערכים סודיים כמו מפתחות API. לאחר מכן, צריך לכתוב קוד באפליקציה לנייד כדי לבצע אימות מול שירות הביניים הזה ולתקשר איתו.
אחת הדרכים ליצור את REST API הזה היא באמצעות Firebase Authentication ו-Functions. כך מקבלים שער מנוהל ללא שרת (serverless) ל-Google Cloud APIs שמטפל באימות, ואפשר להפעיל אותו מאפליקציית המובייל באמצעות ערכות SDK מוכנות מראש.
במדריך הזה מוסבר איך להשתמש בטכניקה הזו כדי לבצע קריאה ל-Cloud Vision API מהאפליקציה שלכם. השיטה הזו מאפשרת לכל המשתמשים המאומתים לגשת לשירותים בתשלום של Cloud Vision דרך פרויקט Cloud שלכם, לכן כדאי לשקול אם מנגנון ההרשאה הזה מספיק לתרחיש השימוש שלכם לפני שממשיכים.
לפני שמתחילים
הגדרת הפרויקט
אם עדיין לא הוספתם את Firebase לאפליקציה, אתם צריכים לעשות זאת לפי השלבים במדריך לתחילת העבודה.משתמשים ב-Swift Package Manager כדי להתקין ולנהל יחסי תלות ב-Firebase.
- ב-Xcode, כשהפרויקט של האפליקציה פתוח, עוברים אל File > Add Packages (קובץ > הוספת חבילות).
- כשמוצגת בקשה, מוסיפים את מאגר Firebase Apple platforms SDK:
- בוחרים את הספרייה Firebase ML.
- מוסיפים את הדגל
-ObjC
לקטע Other Linker Flags בהגדרות הבנייה של יעד הקישור. - אחרי שתסיימו, פלטפורמת Xcode תתחיל באופן אוטומטי לטפל ביחסי התלות ולהוריד אותם ברקע.
https://github.com/firebase/firebase-ios-sdk.git
עכשיו מבצעים הגדרה באפליקציה:
- באפליקציה, מייבאים את Firebase:
Swift
import FirebaseMLModelDownloader
Objective-C
@import FirebaseMLModelDownloader;
צריך לבצע עוד כמה שלבי הגדרה, ואז אפשר להתחיל:
-
אם עדיין לא הפעלתם ממשקי API מבוססי-Cloud בפרויקט, עכשיו הזמן לעשות זאת:
- פותחים את Firebase ML הדף APIs במסוף Firebase.
-
אם עדיין לא שדרגתם את הפרויקט לתוכנית התמחור Blaze עם תשלום לפי שימוש, לוחצים על שדרוג כדי לעשות זאת. (ההצעה לשדרוג תוצג רק אם הפרויקט לא נמצא בתוכנית התמחור Blaze).
רק פרויקטים בתוכנית התמחור Blaze יכולים להשתמש בממשקי API מבוססי-Cloud.
- אם ממשקי API מבוססי-ענן לא מופעלים כבר, לוחצים על הפעלת ממשקי API מבוססי-ענן.
- מגדירים את מפתחות ה-API הקיימים ב-Firebase כך שלא תהיה להם גישה ל-Cloud Vision API:
- פותחים את הדף Credentials במסוף Cloud.
- לכל מפתח API ברשימה, פותחים את תצוגת העריכה, ובקטע Key Restrictions (הגבלות על מפתח), מוסיפים לרשימה את כל ממשקי ה-API הזמינים חוץ מ-Cloud Vision API.
פריסת הפונקציה שאפשר לקרוא לה
בשלב הבא, פורסים את הפונקציה של Cloud Functions שבה ישתמשו כדי לגשר בין האפליקציה לבין Cloud Vision API. מאגר functions-samples
מכיל דוגמה שאפשר להשתמש בה.
כברירת מחדל, גישה ל-Cloud Vision API דרך הפונקציה הזו תאפשר רק למשתמשים מאומתים של האפליקציה שלכם לגשת ל-Cloud Vision API. אפשר לשנות את הפונקציה בהתאם לדרישות שונות.
כדי לפרוס את הפונקציה:
- משכפלים או מורידים את מאגר הדוגמאות של הפונקציות
ועוברים אל הספרייה
Node-1st-gen/vision-annotate-image
:git clone https://github.com/firebase/functions-samples
cd Node-1st-gen/vision-annotate-image
- יחסי תלות של התקנות:
cd functions
npm install
cd ..
- אם לא מותקן Firebase CLI, מתקינים אותו.
- מאתחלים פרויקט Firebase בספרייה
vision-annotate-image
. כשמוצגת בקשה, בוחרים את הפרויקט מהרשימה.firebase init
- פורסים את הפונקציה:
firebase deploy --only functions:annotateImage
הוספת Firebase Auth לאפליקציה
הפונקציה שאפשר להפעיל מרחוק שפרסנו למעלה תדחה כל בקשה ממשתמשים לא מאומתים באפליקציה. אם עדיין לא עשיתם זאת, תצטרכו להוסיף את Firebase Auth לאפליקציה.
הוספת יחסי תלות נדרשים לאפליקציה
משתמשים ב-Swift Package Manager כדי להתקין את ספריית Cloud Functions for Firebase.
1. הכנת תמונת הקלט
כדי להתקשר אל Cloud Vision, התמונה צריכה להיות בפורמט של מחרוזת בקידוד Base64. כדי לעבדUIImage
:
Swift
guard let imageData = uiImage.jpegData(compressionQuality: 1.0) else { return } let base64encodedImage = imageData.base64EncodedString()
Objective-C
NSData *imageData = UIImageJPEGRepresentation(uiImage, 1.0f); NSString *base64encodedImage = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength];
2. הפעלת הפונקציה שניתן להפעיל כדי לזהות ציוני דרך
כדי לזהות ציוני דרך בתמונה, מפעילים את הפונקציה שאפשר להפעיל באמצעות העברת בקשת JSON Cloud Vision.קודם, מאתחלים מופע של Cloud Functions:
Swift
lazy var functions = Functions.functions()
Objective-C
@property(strong, nonatomic) FIRFunctions *functions;
יוצרים בקשה עם סוג שהוגדר לערך
LANDMARK_DETECTION
:Swift
let requestData = [ "image": ["content": base64encodedImage], "features": ["maxResults": 5, "type": "LANDMARK_DETECTION"] ]
Objective-C
NSDictionary *requestData = @{ @"image": @{@"content": base64encodedImage}, @"features": @{@"maxResults": @5, @"type": @"LANDMARK_DETECTION"} };
לבסוף, מפעילים את הפונקציה:
Swift
do { let result = try await functions.httpsCallable("annotateImage").call(requestData) print(result) } catch { if let error = error as NSError? { if error.domain == FunctionsErrorDomain { let code = FunctionsErrorCode(rawValue: error.code) let message = error.localizedDescription let details = error.userInfo[FunctionsErrorDetailsKey] } // ... } }
Objective-C
[[_functions HTTPSCallableWithName:@"annotateImage"] callWithObject:requestData completion:^(FIRHTTPSCallableResult * _Nullable result, NSError * _Nullable error) { if (error) { if ([error.domain isEqualToString:@"com.firebase.functions"]) { FIRFunctionsErrorCode code = error.code; NSString *message = error.localizedDescription; NSObject *details = error.userInfo[@"details"]; } // ... } // Function completed succesfully // Get information about labeled objects }];
3. קבלת מידע על ציוני הדרך שזוהו
אם פעולת הזיהוי של נקודת הציון תצליח, תוחזר תוצאה של המשימה בתגובת JSON של BatchAnnotateImagesResponse. כל אובייקט במערך landmarkAnnotations
מייצג ציון דרך שזוהה בתמונה. לכל נקודת ציון, אפשר לקבל את קואורדינטות התיחום שלה בתמונת הקלט, את השם של נקודת הציון, את קו הרוחב וקו האורך שלה, את מזהה הישות שלה בתרשים הידע (אם זמין) ואת ציון מהימנות ההתאמה. לדוגמה:
Swift
if let labelArray = (result?.data as? [String: Any])?["landmarkAnnotations"] as? [[String:Any]] {
for labelObj in labelArray {
let landmarkName = labelObj["description"]
let entityId = labelObj["mid"]
let score = labelObj["score"]
let bounds = labelObj["boundingPoly"]
// Multiple locations are possible, e.g., the location of the depicted
// landmark and the location the picture was taken.
guard let locations = labelObj["locations"] as? [[String: [String: Any]]] else { continue }
for location in locations {
let latitude = location["latLng"]?["latitude"]
let longitude = location["latLng"]?["longitude"]
}
}
}
Objective-C
NSArray *labelArray = result.data[@"landmarkAnnotations"];
for (NSDictionary *labelObj in labelArray) {
NSString *landmarkName = labelObj[@"description"];
NSString *entityId = labelObj[@"mid"];
NSNumber *score = labelObj[@"score"];
NSArray *bounds = labelObj[@"boundingPoly"];
// Multiple locations are possible, e.g., the location of the depicted
// landmark and the location the picture was taken.
NSArray *locations = labelObj[@"locations"];
for (NSDictionary *location in locations) {
NSNumber *latitude = location[@"latLng"][@"latitude"];
NSNumber *longitude = location[@"latLng"][@"longitude"];
}
}