Firebase Summit で発表されたすべての情報をご覧ください。Firebase を使用してアプリ開発を加速し、自信を持ってアプリを実行する方法を紹介しています。詳細

AppleプラットフォームでFirebaseAuthとFunctionsを使用してCloudVisionでランドマークを安全に認識する

アプリから Google Cloud API を呼び出すには、承認を処理し、API キーなどの秘密の値を保護する中間 REST API を作成する必要があります。次に、モバイル アプリでコードを記述して、この中間サービスを認証し、通信する必要があります。

この REST API を作成する 1 つの方法は、Firebase Authentication and Functions を使用することです。これにより、Google Cloud API へのマネージド サーバーレス ゲートウェイが提供されます。このゲートウェイは、認証を処理し、ビルド済みの SDK を使用してモバイル アプリから呼び出すことができます。

このガイドでは、この手法を使用してアプリから Cloud Vision API を呼び出す方法を示します。この方法では、すべての認証済みユーザーが Cloud プロジェクトを介して Cloud Vision の有料サービスにアクセスできるようになるため、先に進む前に、この認証メカニズムがユースケースに十分かどうかを検討してください。

あなたが始める前に

プロジェクトを構成する

アプリに Firebase をまだ追加していない場合は、スタート ガイドの手順に従って追加してください。

Swift Package Manager を使用して、Firebase の依存関係をインストールおよび管理します。

  1. Xcode で、アプリ プロジェクトを開いた状態で、 File > Add Packagesに移動します。
  2. プロンプトが表示されたら、Firebase Apple プラットフォーム SDK リポジトリを追加します。
  3.   https://github.com/firebase/firebase-ios-sdk
  4. Firebase ML ライブラリを選択します。
  5. 完了すると、Xcode はバックグラウンドで依存関係の解決とダウンロードを自動的に開始します。

次に、アプリ内セットアップを実行します。

  1. アプリで、Firebase をインポートします。

    迅速

    import FirebaseMLModelDownloader

    Objective-C

    @import FirebaseMLModelDownloader;

さらにいくつかの構成手順を実行すると、準備が整います。

  1. プロジェクトでクラウドベースの API をまだ有効にしていない場合は、ここで有効にします。

    1. Firebase コンソールのFirebase ML API ページを開きます。
    2. プロジェクトを Blaze 料金プランにまだアップグレードしていない場合は、[アップグレード] をクリックしてアップグレードします。 (プロジェクトが Blaze プランに含まれていない場合にのみ、アップグレードするように求められます。)

      Blaze レベルのプロジェクトのみがクラウドベースの API を使用できます。

    3. クラウドベースの API がまだ有効になっていない場合は、[クラウドベースの API を有効にする] をクリックします。
  2. Cloud Vision API へのアクセスを禁止するように、既存の Firebase API キーを構成します。
    1. Cloud コンソールの資格情報ページを開きます。
    2. リスト内の API キーごとに編集ビューを開き、[キーの制限] セクションで、Cloud Vision API を除く使用可能なすべての API をリストに追加します。

呼び出し可能な関数をデプロイする

次に、アプリと Cloud Vision API をブリッジするために使用する Cloud Function をデプロイします。 functions-samplesリポジトリには、使用できる例が含まれています。

デフォルトでは、この関数を介して Cloud Vision API にアクセスすると、アプリの認証済みユーザーのみが Cloud Vision API にアクセスできます。さまざまな要件に合わせて関数を変更できます。

関数をデプロイするには:

  1. functions-samples リポジトリを複製またはダウンロードし、 vision-annotate-imageディレクトリに変更します:
    git clone https://github.com/firebase/functions-samples
    cd vision-annotate-image
    
  2. 依存関係のインストール:
    cd functions
    npm install
    cd ..
    
  3. Firebase CLI がない場合は、インストールします。
  4. vision-annotate-imageディレクトリで Firebase プロジェクトを初期化します。プロンプトが表示されたら、リストからプロジェクトを選択します。
    firebase init
  5. 関数をデプロイします:
    firebase deploy --only functions:annotateImage

アプリに Firebase Auth を追加する

上記でデプロイされた呼び出し可能関数は、アプリの認証されていないユーザーからのリクエストを拒否します。まだ行っていない場合は、アプリに Firebase Auth を追加する必要があります。

アプリに必要な依存関係を追加する

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()

Objective-C

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

2. callable 関数を呼び出してランドマークを認識する

画像内のランドマークを認識するには、 JSON Cloud Vision リクエストを渡して呼び出し可能な関数を呼び出します。

  1. まず、Cloud Functions のインスタンスを初期化します。

    迅速

    lazy var functions = Functions.functions()
    

    Objective-C

    @property(strong, nonatomic) FIRFunctions *functions;
    
  2. TypeLANDMARK_DETECTIONに設定してリクエストを作成します。

    迅速

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

    Objective-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
    }
    

    Objective-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. 認識されたランドマークに関する情報を取得する

ランドマーク認識操作が成功すると、 BatchAnnotateImagesResponseの JSON 応答がタスクの結果として返されます。 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"]
    }
  }
}

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