Riconoscere i punti di riferimento in modo sicuro con Cloud Vision utilizzando Firebase Auth e Functions sulle piattaforme Apple

Per chiamare un'API Google Cloud dalla tua app, devi creare un'API REST intermedia che gestisca l'autorizzazione e protegga i valori segreti come le chiavi API. Dopodiché, devi scrivere codice nella tua app mobile per autenticarti e comunicare con questo servizio intermedio.

Un modo per creare questa API REST è utilizzare Firebase Authentication e Functions, che ti offre un gateway serverless gestito per le API Google Cloud che gestisce l'autenticazione e può essere chiamato dalla tua app mobile con SDK predefiniti.

Questa guida mostra come utilizzare questa tecnica per chiamare l'API Cloud Vision dalla tua app. Questo metodo consentirà a tutti gli utenti autenticati di accedere ai servizi a pagamento di Cloud Vision tramite il tuo progetto Cloud, quindi valuta se questo meccanismo di autenticazione è sufficiente per il tuo caso d'uso prima di procedere.

Prima di iniziare

Configura il tuo progetto

Se non hai ancora aggiunto Firebase alla tua app, fallo seguendo i passaggi della guida introduttiva.

Utilizza Swift Package Manager per installare e gestire le dipendenze di Firebase.

  1. In Xcode, con il progetto dell'app aperto, vai a File > Add Packages (File > Aggiungi pacchetti).
  2. Quando richiesto, aggiungi il repository dell'SDK delle piattaforme Apple di Firebase:
  3.   https://github.com/firebase/firebase-ios-sdk.git
  4. Scegli la libreria Firebase ML.
  5. Aggiungi il flag -ObjC alla sezione Other Linker Flags (Altri flag del linker) delle impostazioni di compilazione della destinazione.
  6. Al termine, Xcode inizierà automaticamente a risolvere e a scaricare le tue dipendenze in background.

Come passaggio successivo, esegui alcune configurazioni in-app:

  1. Nella tua app, importa Firebase:

    Swift

    import FirebaseMLModelDownloader

    Objective-C

    @import FirebaseMLModelDownloader;

Mancano ancora alcuni passaggi di configurazione e siamo pronti per iniziare:

  1. Se non hai ancora abilitato le API basate sul cloud per il tuo progetto, fallo ora:

    1. Apri la pagina delle Firebase ML API nella console Firebase.
    2. Se non hai ancora eseguito l'upgrade del tuo progetto al piano tariffario Blaze con pagamento a consumo, fai clic su Esegui l'upgrade per farlo. Ti verrà chiesto di eseguire l'upgrade solo se il tuo progetto non è incluso nel piano tariffario Blaze.

      Solo i progetti inclusi nel piano tariffario Blaze possono utilizzare le API basate sul cloud.

    3. Se le API basate sul cloud non sono ancora abilitate, fai clic su Abilita API basate sul cloud.
  2. Configura le chiavi API Firebase esistenti per impedire l'accesso all'API Cloud Vision:
    1. Apri la pagina Credenziali della console Cloud.
    2. Per ogni chiave API nell'elenco, apri la visualizzazione di modifica e, nella sezione Limitazioni della chiave, aggiungi all'elenco tutte le API disponibili tranne l'API Cloud Vision.

Esegui il deployment della funzione richiamabile

Come passaggio successivo, esegui il deployment della funzione Cloud che utilizzerai per collegare la tua app e l'API Cloud Vision. Il repository functions-samples contiene un esempio che puoi utilizzare.

Per impostazione predefinita, l'accesso all'API Cloud Vision tramite questa funzione consentirà solo agli utenti autenticati della tua app di accedere all'API Cloud Vision. Puoi modificare la funzione per requisiti diversi.

Per eseguire il deployment della funzione:

  1. Clona o scarica il repository functions-samples e passa alla directory Node-1st-gen/vision-annotate-image:
    git clone https://github.com/firebase/functions-samples
    cd Node-1st-gen/vision-annotate-image
    
  2. Installa le dipendenze:
    cd functions
    npm install
    cd ..
  3. Se non hai l'interfaccia a riga di comando di Firebase, installala.
  4. Inizializza un progetto Firebase nella vision-annotate-image directory. Quando richiesto, seleziona il tuo progetto nell'elenco.
    firebase init
  5. Esegui il deployment della funzione:
    firebase deploy --only functions:annotateImage

Aggiungi Firebase Authentication alla tua app

La funzione richiamabile di cui è stato eseguito il deployment sopra rifiuterà qualsiasi richiesta da utenti non autenticati della tua app. Se non l'hai ancora fatto, dovrai aggiungere Firebase Authentication alla tua app.

Aggiungi le dipendenze necessarie alla tua app

Utilizza Swift Package Manager per installare la libreria Cloud Functions per Firebase.

1. Prepara l'immagine di input

Per chiamare Cloud Vision, l'immagine deve essere formattata come stringa con codifica base64. Per elaborare un 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. Richiama la funzione richiamabile per riconoscere i punti di riferimento

Per riconoscere i punti di riferimento in un'immagine, richiama la funzione richiamabile passando una richiesta JSON di Cloud Vision.

  1. Innanzitutto, inizializza un'istanza di Cloud Functions:

    Swift

    lazy var functions = Functions.functions()
    

    Objective-C

    @property(strong, nonatomic) FIRFunctions *functions;
    
  2. Crea una richiesta con Type impostato su 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"}
    };
    
  3. Infine, richiama la funzione:

    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. Ricevi informazioni sui punti di riferimento riconosciuti

Se l'operazione di riconoscimento dei punti di riferimento ha esito positivo, nel risultato dell'attività viene restituita una risposta JSON di BatchAnnotateImagesResponse. Ogni oggetto nell'landmarkAnnotations array rappresenta un punto di riferimento riconosciuto nell'immagine. Per ogni punto di riferimento, puoi ottenere le coordinate del riquadro di delimitazione nell'immagine di input, il nome del punto di riferimento, la latitudine e la longitudine, l'ID dell'entità Knowledge Graph (se disponibile) e il punteggio di affidabilità della corrispondenza. Ad esempio:

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