Migra la tua app Analizza per iOS su Firebase

Se sei un utente Parse alla ricerca di una soluzione di backend come servizio alternativa, Firebase potrebbe essere la scelta ideale per la tua app iOS.

Questa guida descrive come integrare servizi specifici nella tua app. Per le istruzioni di configurazione di base di Firebase, consulta la guida alla configurazione di iOS+ .

statistiche di Google

Google Analytics è una soluzione di misurazione delle app gratuita che fornisce informazioni dettagliate sull'utilizzo delle app e sul coinvolgimento degli utenti. Analytics si integra tra le funzionalità di Firebase e ti fornisce rapporti illimitati per un massimo di 500 eventi distinti che puoi definire utilizzando l'SDK Firebase.

Consulta i documenti di Google Analytics per saperne di più.

Strategia di migrazione suggerita

L'utilizzo di diversi fornitori di analisi è uno scenario comune che si applica facilmente a Google Analytics. Aggiungilo alla tua app per beneficiare degli eventi e delle proprietà utente che Analytics raccoglie automaticamente, come prima apertura, aggiornamento dell'app, modello del dispositivo, età.

Per gli eventi personalizzati e le proprietà dell'utente, puoi utilizzare una strategia di doppia scrittura utilizzando sia Parse Analytics che Google Analytics per registrare eventi e proprietà, il che ti consente di implementare gradualmente la nuova soluzione.

Confronto di codici

Analisi dell'analisi

// Start collecting data
[PFAnalytics trackAppOpenedWithLaunchOptions:launchOptions];

NSDictionary *dimensions = @{
  // Define ranges to bucket data points into meaningful segments
  @"priceRange": @"1000-1500",
  // Did the user filter the query?
  @"source": @"craigslist",
  // Do searches happen more often on weekdays or weekends?
  @"dayType": @"weekday"
};
// Send the dimensions to Parse along with the 'search' event
[PFAnalytics trackEvent:@"search" dimensions:dimensions];

statistiche di Google

// Obtain the AppMeasurement instance and start collecting data
[FIRApp configure];

// Send the event with your params
[FIRAnalytics logEventWithName:@"search" parameters:@{
  // Define ranges to bucket data points into meaningful segments
  @"priceRange": @"1000-1500",
  // Did the user filter the query?
  @"source": @"craigslist",
  // Do searches happen more often on weekdays or weekends?
  @"dayType": @"weekday"
}];

Database in tempo reale di Firebase

Il database Firebase Realtime è un database in hosting su cloud NoSQL. I dati vengono archiviati come JSON e sincronizzati in tempo reale con ogni client connesso.

Per saperne di più, consulta i documenti del database Firebase Realtime .

Differenze con i dati di analisi

Oggetti

In Parse memorizzi un PFObject , o una sua sottoclasse, che contiene coppie chiave-valore di dati compatibili con JSON. I dati sono senza schema, il che significa che non è necessario specificare quali chiavi esistono su ogni PFObject .

Tutti i dati di Firebase Realtime Database vengono archiviati come oggetti JSON e non esiste un equivalente per PFObject ; scrivi semplicemente nell'albero JSON i valori dei tipi che corrispondono ai tipi JSON disponibili.

Quello che segue è un esempio di come salvare i punteggi più alti di una partita.

Analizza
PFObject *gameScore = [PFObject objectWithClassName:@"GameScore"];
gameScore[@"score"] = @1337;
gameScore[@"playerName"] = @"Sean Plott";
gameScore[@"cheatMode"] = @NO;
[gameScore saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
  if (succeeded) {
    // The object has been saved.
  } else {
    // There was a problem, check error.description
  }
}];
Base di fuoco
// Create a reference to the database
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
NSString *key = [[ref child:@"scores"] childByAutoId].key;
NSDictionary *score = @{@"score": @1337,
                        @"playerName": @"Sean Plott",
                        @"cheatMode": @NO};
[key setValue:score withCompletionBlock:^(NSError *error,  FIRDatabaseReference *ref) {
  if (error) {
    // The object has been saved.
  } else {
    // There was a problem, check error.description
  }
}];
Per maggiori dettagli, consulta la guida Leggi e scrivi dati su piattaforme Apple .

Relazioni tra dati

Un PFObject può avere una relazione con un altro PFObject : qualsiasi oggetto può utilizzare altri oggetti come valori.

Nel database Firebase Realtime, le relazioni vengono espresse meglio utilizzando strutture dati piatte che suddividono i dati in percorsi separati, in modo che possano essere scaricati in modo efficiente in chiamate separate.

Quello che segue è un esempio di come potresti strutturare la relazione tra i post in un'app di blog e i loro autori.

Analizza
// Create the author
PFObject *myAuthor = [PFObject objectWithClassName:@"Author"];
myAuthor[@"name"] = @"Grace Hopper";
myAuthor[@"birthDate"] = @"December 9, 1906";
myAuthor[@"nickname"] = @"Amazing Grace";

// Create the post
PFObject *myPost = [PFObject objectWithClassName:@"Post"];
myPost[@"title"] = @"Announcing COBOL, a New Programming Language";

// Add a relation between the Post and the Author
myPost[@"parent"] = myAuthor;

// This will save both myAuthor and myPost
[myPost saveInBackground];
Base di fuoco
// Create a reference to the database
FIRDatabaseReference *ref = [[FIRDatabase database] reference];

// Create the author
NSString *myAuthorKey = @"ghopper";
NSDictionary *author = @{@"name": @"Grace Hopper",
                         @"birthDate": @"December 9, 1906",
                         @"nickname": @"Amazing Grace"};
// Save the author
[[ref child:myAuthorKey] setValue:author]

// Create and save the post
NSString *key = [[ref child:@"posts"] childByAutoId].key;
NSDictionary *post = @{@"author": myAuthorKey,
                       @"title": @"Announcing COBOL, a New Programming Language"};
[key setValue:post]

Il risultato è il seguente layout dei dati.

{
  // Info about the authors
  "authors": {
    "ghopper": {
      "name": "Grace Hopper",
      "date_of_birth": "December 9, 1906",
      "nickname": "Amazing Grace"
    },
    ...
  },
  // Info about the posts: the "author" fields contains the key for the author
  "posts": {
    "-JRHTHaIs-jNPLXOQivY": {
      "author": "ghopper",
      "title": "Announcing COBOL, a New Programming Language"
    }
    ...
  }
}
Per maggiori dettagli, consultare la guida Struttura del database .

Lettura dei dati

In Parse leggi i dati utilizzando l'ID di un oggetto Parse specifico o eseguendo query utilizzando PFQuery .

In Firebase, recuperi i dati collegando un listener asincrono a un riferimento di database. Il listener viene attivato una volta per lo stato iniziale dei dati e di nuovo quando i dati cambiano, quindi non sarà necessario aggiungere alcun codice per determinare se i dati sono cambiati.

Quello che segue è un esempio di come recuperare i punteggi per un giocatore particolare, basato sull'esempio presentato nella sezione "Oggetti" .

Analizza
PFQuery *query = [PFQuery queryWithClassName:@"GameScore"];
[query whereKey:@"playerName" equalTo:@"Dan Stemkoski"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
  if (!error) {
    for (PFObject *score in objects) {
      NSString *gameScore = score[@"score"];
      NSLog(@"Retrieved: %@", gameScore);
    }
  } else {
    // Log details of the failure
    NSLog(@"Error: %@ %@", error, [error userInfo]);
  }
}];
Base di fuoco
// Create a reference to the database
FIRDatabaseReference *ref = [[FIRDatabase database] reference];

// This type of listener is not one time, and you need to cancel it to stop
// receiving updates.
[[[[ref child:@"scores"] queryOrderedByChild:@"playerName"] queryEqualToValue:@"Dan Stemkoski"]
    observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
  // This will fire for each matching child node.
  NSDictionary *score = snapshot.value;
  NSString gameScore = score[@"score"];
  NSLog(@"Retrieved: %@", gameScore);
}];
Per maggiori dettagli sui tipi disponibili di listener di eventi e su come ordinare e filtrare i dati, consulta la guida Leggi e scrivi dati sulle piattaforme Apple .

Strategia di migrazione suggerita

Ripensa ai tuoi dati

Il database Firebase Realtime è ottimizzato per sincronizzare i dati in millisecondi su tutti i client connessi e la struttura dei dati risultante è diversa dai dati principali di analisi. Ciò significa che il primo passaggio della migrazione consiste nel considerare le modifiche richieste dai dati, tra cui:

  • Come i tuoi oggetti Parse dovrebbero essere mappati ai dati di Firebase
  • Se hai relazioni genitore-figlio, come suddividere i tuoi dati in percorsi diversi in modo che possano essere scaricati in modo efficiente in chiamate separate.

Migra i tuoi dati

Dopo aver deciso come strutturare i dati in Firebase, devi pianificare come gestire il periodo durante il quale la tua app deve scrivere su entrambi i database. Le tue scelte sono:

Sincronizzazione in background

In questo scenario sono disponibili due versioni dell'app: la versione precedente che utilizza Parse e una nuova versione che utilizza Firebase. Le sincronizzazioni tra i due database sono gestite da Parse Cloud Code (Parse to Firebase), con il codice che ascolta le modifiche su Firebase e sincronizza tali modifiche con Parse. Prima di poter iniziare a utilizzare la nuova versione, devi:

  • Converti i tuoi dati di analisi esistenti nella nuova struttura Firebase e scrivili nel database Firebase Realtime.
  • Scrivi le funzioni di analisi del codice cloud che utilizzano l'API REST di Firebase per scrivere nel database in tempo reale di Firebase le modifiche apportate nell'analisi dei dati dai vecchi client.
  • Scrivi e distribuisci codice che ascolti le modifiche su Firebase e le sincronizzi con il database Parse.

Questo scenario garantisce una netta separazione tra codice vecchio e nuovo e mantiene semplici i client. Le sfide di questo scenario sono la gestione di grandi set di dati nell'esportazione iniziale e la garanzia che la sincronizzazione bidirezionale non generi una ricorsione infinita.

Doppia scrittura

In questo scenario, scrivi una nuova versione dell'app che utilizza sia Firebase che Parse, utilizzando Parse Cloud Code per sincronizzare le modifiche apportate dai vecchi client dal Parse Data al database Firebase Realtime. Quando un numero sufficiente di persone è migrato dalla versione di sola analisi dell'app, puoi rimuovere il codice di analisi dalla versione a doppia scrittura.

Questo scenario non richiede alcun codice lato server. I suoi svantaggi sono che i dati a cui non si accede non vengono migrati e che la dimensione della tua app viene aumentata dall'utilizzo di entrambi gli SDK.

Autenticazione Firebase

Firebase Authentication può autenticare gli utenti utilizzando password e provider di identità federati popolari come Google, Facebook e Twitter. Fornisce inoltre librerie dell'interfaccia utente per farti risparmiare l'investimento significativo necessario per implementare e mantenere un'esperienza di autenticazione completa per la tua app su tutte le piattaforme.

Per ulteriori informazioni, consulta i documenti di autenticazione Firebase .

Differenze con Parse Auth

Parse fornisce una classe utente specializzata denominata PFUser che gestisce automaticamente la funzionalità richiesta per la gestione dell'account utente. PFUser è una sottoclasse di PFObject , il che significa che i dati utente sono disponibili in Parse Data e possono essere estesi con campi aggiuntivi come qualsiasi altro PFObject .

Un FIRUser ha un insieme fisso di proprietà di base, un ID univoco, un indirizzo e-mail principale, un nome e un URL di foto, archiviato nel database utente di un progetto separato; tali proprietà possono essere aggiornate dall'utente. Non è possibile aggiungere altre proprietà direttamente all'oggetto FIRUser ; invece, puoi memorizzare le proprietà aggiuntive nel tuo database Firebase Realtime.

Di seguito è riportato un esempio di come è possibile registrare un utente e aggiungere un campo del numero di telefono aggiuntivo.

Analizza
PFUser *user = [PFUser user];
user.username = @"my name";
user.password = @"my pass";
user.email = @"email@example.com";

// other fields can be set just like with PFObject
user[@"phone"] = @"415-392-0202";

[user signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
  if (!error) {
    // Hooray! Let them use the app now.
  } else {
    // Something went wrong
    NSString *errorString = [error userInfo][@"error"];
  }
}];
Base di fuoco
[[FIRAuth auth] createUserWithEmail:@"email@example.com"
                           password:@"my pass"
                         completion:^(FIRUser *_Nullable user, NSError *_Nullable error) {
  if (!error) {
    FIRDatabaseReference *ref = [[FIRDatabase database] reference];
    [[[[ref child:@"users"] child:user.uid] child:@"phone"] setValue:@"415-392-0202"
  } else {
    // Something went wrong
    NSString *errorString = [error userInfo][@"error"];
  }
}];

Strategia di migrazione suggerita

Migrare gli account

Per migrare gli account utente da Parse a Firebase, esporta il database utente in un file JSON o CSV, quindi importa il file nel progetto Firebase utilizzando il comando auth:import della CLI Firebase.

Innanzitutto, esporta il tuo database utente dalla console Parse o dal tuo database self-hosted. Ad esempio, un file JSON esportato dalla console Parse potrebbe essere simile al seguente:

{ // Username/password user
  "bcryptPassword": "$2a$10$OBp2hxB7TaYZgKyTiY48luawlTuYAU6BqzxJfpHoJMdZmjaF4HFh6",
  "email": "user@example.com",
  "username": "testuser",
  "objectId": "abcde1234",
  ...
},
{ // Facebook user
  "authData": {
    "facebook": {
      "access_token": "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
      "expiration_date": "2017-01-02T03:04:05.006Z",
      "id": "1000000000"
    }
  },
  "username": "wXyZ987654321StUv",
  "objectId": "fghij5678",
  ...
}

Quindi, trasforma il file esportato nel formato richiesto dalla CLI di Firebase. Usa l' objectId dei tuoi utenti Parse come localId dei tuoi utenti Firebase. Inoltre, base64 codifica i valori bcryptPassword da Parse e li usa nel campo passwordHash . Per esempio:

{
  "users": [
    {
      "localId": "abcde1234",  // Parse objectId
      "email": "user@example.com",
      "displayName": "testuser",
      "passwordHash": "JDJhJDEwJE9CcDJoeEI3VGFZWmdLeVRpWTQ4bHVhd2xUdVlBVTZCcXp4SmZwSG9KTWRabWphRjRIRmg2",
    },
    {
      "localId": "fghij5678",  // Parse objectId
      "displayName": "wXyZ987654321StUv",
      "providerUserInfo": [
        {
          "providerId": "facebook.com",
          "rawId": "1000000000",  // Facebook ID
        }
      ]
    }
  ]
}

Infine, importa il file trasformato con la CLI di Firebase, specificando bcrypt come algoritmo hash:

firebase auth:import account_file.json --hash-algo=BCRYPT

Migrare i dati dell'utente

Se stai archiviando dati aggiuntivi per i tuoi utenti, puoi migrarli al database Firebase Realtime utilizzando le strategie descritte nella sezione sulla migrazione dei dati . Se esegui la migrazione degli account utilizzando il flusso descritto nella sezione relativa alla migrazione degli account , i tuoi account Firebase hanno gli stessi ID dei tuoi account Analizza, consentendoti di migrare e riprodurre facilmente qualsiasi relazione definita dall'ID utente.

Messaggistica cloud di Firebase

Firebase Cloud Messaging (FCM) è una soluzione di messaggistica multipiattaforma che ti consente di inviare messaggi e notifiche in modo affidabile senza alcun costo. Il compositore di notifiche è un servizio gratuito basato su Firebase Cloud Messaging che consente notifiche utente mirate per gli sviluppatori di app mobili.

Per ulteriori informazioni, consulta i documenti di Firebase Cloud Messaging .

Differenze con le notifiche push di analisi

Ogni applicazione Parse installata su un dispositivo registrato per le notifiche ha un oggetto Installation associato, in cui vengono archiviati tutti i dati necessari per indirizzare le notifiche. L' Installation è una sottoclasse di PFUser , il che significa che puoi aggiungere tutti i dati aggiuntivi che desideri alle tue istanze di Installation .

Il compositore di notifiche fornisce segmenti utente predefiniti basati su informazioni come app, versione dell'app e lingua del dispositivo. Puoi creare segmenti di utenti più complessi utilizzando gli eventi e le proprietà di Google Analytics per creare segmenti di pubblico. Consulta la guida per il pubblico per saperne di più. Queste informazioni sul targeting non sono visibili nel database in tempo reale di Firebase.

Strategia di migrazione suggerita

Migrazione dei token del dispositivo

Mentre Parse utilizza i token del dispositivo APN per indirizzare le installazioni per le notifiche, FCM utilizza i token di registrazione FCM mappati ai token del dispositivo APN. Basta aggiungere l'SDK FCM alla tua app Apple e recupererà automaticamente un token FCM .

Migrazione dei canali verso argomenti FCM

Se utilizzi i canali di analisi per inviare notifiche, puoi migrare agli argomenti FCM, che forniscono lo stesso modello editore-abbonato. Per gestire la transizione da Analisi a FCM, puoi scrivere una nuova versione dell'app che utilizza l'SDK di analisi per annullare l'iscrizione ai canali di analisi e l'SDK di FCM per iscriversi agli argomenti FCM corrispondenti.

Ad esempio, se il tuo utente è iscritto all'argomento "Giganti", faresti qualcosa del tipo:

PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation removeObject:@"Giants" forKey:@"channels"];
[currentInstallation saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
  if (succedeed) {
    [[FIRMessaging messaging] subscribeToTopic:@"/topics/Giants"];
  } else {
    // Something went wrong unsubscribing
  }
}];

Utilizzando questa strategia, puoi inviare messaggi sia al canale Analizza che all'argomento FCM corrispondente, supportando gli utenti sia della vecchia che della nuova versione. Quando un numero sufficiente di utenti è migrato dalla versione di sola analisi dell'app, puoi disattivare tale versione e iniziare a inviare utilizzando solo FCM.

Consulta i documenti sugli argomenti di FCM per saperne di più.

Configurazione remota Firebase

Firebase Remote Config è un servizio cloud che ti consente di modificare il comportamento e l'aspetto della tua app senza richiedere agli utenti di scaricare un aggiornamento dell'app. Quando usi Remote Config, crei valori predefiniti in-app che controllano il comportamento e l'aspetto della tua app. Successivamente, puoi utilizzare la console Firebase per sovrascrivere i valori predefiniti in-app per tutti gli utenti dell'app o per i segmenti della tua base utenti.

Firebase Remote Config può essere molto utile durante le migrazioni nei casi in cui desideri testare soluzioni diverse ed essere in grado di trasferire dinamicamente più client a un provider diverso. Ad esempio, se disponi di una versione della tua app che utilizza sia Firebase che Parse per i dati, puoi utilizzare una regola percentile casuale per determinare quali client leggono da Firebase e aumentare gradualmente la percentuale.

Per ulteriori informazioni su Firebase Remote Config, vedere l' introduzione di Remote Config .

Differenze con Parse Config

Con Parse config puoi aggiungere coppie chiave/valore alla tua app nel dashboard Parse Config, quindi recuperare PFConfig sul client. Ogni istanza PFConfig che ottieni è sempre immutabile. Quando in futuro recuperi un nuovo PFConfig dalla rete, non modificherà alcuna istanza PFConfig esistente, ma ne creerà una nuova e la renderà disponibile tramite currentConfig .

Con Firebase Remote Config crei valori predefiniti in-app per coppie chiave/valore che puoi ignorare dalla console Firebase e puoi utilizzare regole e condizioni per fornire variazioni sull'esperienza utente della tua app a diversi segmenti della tua base utenti. Firebase Remote Config implementa una classe singleton che rende le coppie chiave/valore disponibili per la tua app. Inizialmente il singleton restituisce i valori predefiniti che definisci in-app. Puoi recuperare un nuovo set di valori dal server in qualsiasi momento conveniente per la tua app; dopo che il nuovo set è stato recuperato con successo, puoi scegliere quando attivarlo per rendere disponibili i nuovi valori all'app.

Strategia di migrazione suggerita

Puoi passare a Firebase Remote Config copiando le coppie chiave/valore della tua configurazione Parse nella console Firebase e quindi distribuendo una nuova versione dell'app che utilizza Firebase Remote Config.

Se vuoi sperimentare sia Parse Config che Firebase Remote Config, puoi distribuire una nuova versione dell'app che usa entrambi gli SDK fino a quando un numero sufficiente di utenti non sarà migrato dalla versione Parse only.

Confronto di codici

Analizza

[PFConfig getConfigInBackgroundWithBlock:^(PFConfig *config, NSError *error) {
  if (!error) {
    NSLog(@"Yay! Config was fetched from the server.");
  } else {
    NSLog(@"Failed to fetch. Using Cached Config.");
    config = [PFConfig currentConfig];
  }

  NSString *welcomeMessage = config[@"welcomeMessage"];
  if (!welcomeMessage) {
    NSLog(@"Falling back to default message.");
    welcomeMessage = @"Welcome!";
  }
}];

Base di fuoco

FIRRemoteConfig remoteConfig = [FIRRemoteConfig remoteConfig];
// Set defaults from a plist file
[remoteConfig setDefaultsFromPlistFileName:@"RemoteConfigDefaults"];

[remoteConfig fetchWithCompletionHandler:^(FIRRemoteConfigFetchStatus status, NSError *error) {
  if (status == FIRRemoteConfigFetchStatusSuccess) {
    NSLog(@"Yay! Config was fetched from the server.");
    // Once the config is successfully fetched it must be activated before newly fetched
    // values are returned.
    [self.remoteConfig activateFetched];
  } else {
    NSLog(@"Failed to fetch. Using last fetched or default.");
  }
}];

// ...

// When this is called, the value of the latest fetched and activated config is returned;
// if there's none, the default value is returned.
NSString welcomeMessage = remoteConfig[@"welcomeMessage"].stringValue;