Catch up on everthing we announced at this year's Firebase Summit. Learn more

在 Apple 平台上使用 Firebase 身份驗證和函數通過 Cloud Vision 安全識別地標

為了從您的應用程序調用 Google Cloud API,您需要創建一個中間 REST API 來處理授權並保護 API 密鑰等秘密值。然後,您需要在您的移動應用程序中編寫代碼來驗證此中間服務並與之通信。

創建此 REST API 的一種方法是使用 Firebase 身份驗證和函數,它為您提供了一個託管的、無服務器的 Google Cloud API 網關,該網關處理身份驗證並可從您的移動應用程序中使用預構建的 SDK 進行調用。

本指南演示瞭如何使用此技術從您的應用程序調用 Cloud Vision API。此方法將允許所有經過身份驗證的用戶通過您的 Cloud 項目訪問 Cloud Vision 計費服務,因此在繼續之前請考慮此身份驗證機制是否足以滿足您的用例。

在你開始之前

配置您的項目

如果您尚未添加火力地堡到您的應用程序,通過遵循的步驟做這樣的入門指南

使用 Swift Package Manager 安裝和管理 Firebase 依賴項。

  1. 在Xcode中,您的應用項目打開,導航到File>斯威夫特包>添加包的依賴
  2. 出現提示時,添加 Firebase Apple 平台 SDK 存儲庫:
  3.   https://github.com/firebase/firebase-ios-sdk
      
  4. 選擇 Firebase ML 庫。
  5. 完成後,Xcode 將在後台自動開始解析和下載您的依賴項。

接下來,執行一些應用程序內設置:

  1. 在您的應用中,導入 Firebase:

    迅速

    import Firebase

    目標-C

    @import Firebase;

再執行幾個配置步驟,我們就可以開始了:

  1. 如果您尚未為您的項目啟用基於雲的 API,請立即啟用:

    1. 打開火力地堡ML API頁面的火力地堡控制台。
    2. 如果您尚未升級您的項目以大火定價計劃,單擊升級到這樣做。 (僅當您的項目不在 Blaze 計劃中時,系統才會提示您升級。)

      只有 Blaze 級別的項目可以使用基於雲的 API。

    3. 如果基於雲的API尚未啟用,單擊啟用基於雲的API。
  2. 配置您現有的 Firebase API 密鑰以禁止訪問 Cloud Vision API:
    1. 打開證書雲控制台的頁面。
    2. 對於列表中的每個API密鑰,打開編輯視圖,並在重點限制部分,加入所有可用的API,除了雲願景API到列表中。

部署可調用函數

接下來,部署您將用於橋接應用程序和 Cloud Vision API 的 Cloud Functions。該functions-samples庫包含你可以用一個例子。

默認情況下,通過此函數訪問 Cloud Vision API 將僅允許您的應用程序的經過身份驗證的用戶訪問 Cloud Vision API。您可以根據不同的要求修改該功能。

部署函數:

  1. 克隆或下載的功能樣本回購並切換到vision-annotate-image目錄:
    git clone https://github.com/firebase/functions-samples
    cd vision-annotate-image
    
  2. 安裝依賴:
    cd functions
    npm install
    cd ..
    
  3. 如果你不具備火力地堡CLI,安裝它
  4. 初始化在一個火力地堡項目vision-annotate-image目錄。出現提示時,在列表中選擇您的項目。
    firebase init
  5. 部署功能:
    firebase deploy --only functions:annotateImage

將 Firebase 身份驗證添加到您的應用

上面部署的可調用函數將拒絕來自您的應用程序的未經身份驗證的用戶的任何請求。如果你還沒有這樣做的話,你將需要火力地堡驗證添加到您的應用程序。

向您的應用程序添加必要的依賴項

使用 Swift Package Manager 安裝 Cloud Functions for Firebase 庫。

1.準備輸入圖像

為了調用 Cloud Vision,圖像必須格式化為 base64 編碼的字符串。要處理UIImage

迅速

guard let imageData = uiImage.jpegData(compressionQuality: 1.0f) else { return }
let base64encodedImage = imageData.base64EncodedString()

目標-C

NSData *imageData = UIImageJPEGRepresentation(uiImage, 1.0f);
NSString *base64encodedImage =
  [imageData base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength];

2.調用可調用函數來識別地標

識別圖像中的地標,調用可調用函數傳遞JSON雲視覺請求

  1. 首先,初始化 Cloud Functions 的一個實例:

    迅速

    lazy var functions = Functions.functions()
    

    目標-C

    @property(strong, nonatomic) FIRFunctions *functions;
    
  2. 創建一個請求類型設置為LANDMARK_DETECTION

    迅速

    let requestData = [
      "image": ["content": base64encodedImage],
      "features": ["maxResults": 5, "type": "LANDMARK_DETECTION"]
    ]
    

    目標-C

    NSDictionary *requestData = @{
      @"image": @{@"content": base64encodedImage},
      @"features": @{@"maxResults": @5, @"type": @"LANDMARK_DETECTION"}
    };
    
  3. 最後,調用函數:

    迅速

    functions.httpsCallable("annotateImage").call(requestData) { (result, error) in
      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]
        }
        // ...
      }
      // Function completed succesfully
    }
    

    目標-C

    [[_functions HTTPSCallableWithName:@"annotateImage"]
                              callWithObject:requestData
                                  completion:^(FIRHTTPSCallableResult * _Nullable result, NSError * _Nullable error) {
            if (error) {
              if (error.domain == FIRFunctionsErrorDomain) {
                FIRFunctionsErrorCode code = error.code;
                NSString *message = error.localizedDescription;
                NSObject *details = error.userInfo[FIRFunctionsErrorDetailsKey];
              }
              // ...
            }
            // Function completed succesfully
            // Get information about labeled objects
    
          }];
    

3. 獲取已識別地標的信息

如果里程碑識別操作成功,一個JSON響應BatchAnnotateImagesResponse將在任務的結果返回。中的每個對象landmarkAnnotations陣列代表這是在圖像中識別的界標。對於每個地標,您可以獲取其在輸入圖像中的邊界坐標、地標名稱、緯度和經度、其知識圖實體 ID(如果可用)以及匹配的置信度分數。例如:

迅速

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"]
    }
  }
}

目標-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"];
  }
}