Migrieren Sie Ihre Parse-iOS-App zu Firebase

Wenn Sie ein Parse-Benutzer sind und nach einer alternativen Backend-as-a-Service-Lösung suchen, ist Firebase möglicherweise die ideale Wahl für Ihre iOS-App.

In dieser Anleitung wird beschrieben, wie Sie bestimmte Dienste in Ihre App integrieren. Grundlegende Anleitungen zur Firebase-Einrichtung finden Sie in der iOS+-Einrichtungsanleitung .

Google Analytics

Google Analytics ist eine kostenlose App-Messlösung, die Einblicke in die App-Nutzung und das Nutzerengagement bietet. Analytics lässt sich in alle Firebase-Funktionen integrieren und bietet Ihnen unbegrenzte Berichte für bis zu 500 verschiedene Ereignisse, die Sie mit dem Firebase SDK definieren können.

Weitere Informationen finden Sie in den Google Analytics-Dokumenten .

Vorgeschlagene Migrationsstrategie

Die Verwendung verschiedener Analyseanbieter ist ein häufiges Szenario, das problemlos auf Google Analytics anwendbar ist. Fügen Sie es einfach zu Ihrer App hinzu, um von Ereignissen und Benutzereigenschaften zu profitieren, die Analytics automatisch erfasst, wie z. B. erstes Öffnen, App-Update, Gerätemodell, Alter.

Für benutzerdefinierte Ereignisse und Benutzereigenschaften können Sie eine Double-Write-Strategie anwenden, indem Sie sowohl Parse Analytics als auch Google Analytics verwenden, um Ereignisse und Eigenschaften zu protokollieren, was Ihnen die schrittweise Einführung der neuen Lösung ermöglicht.

Code-Vergleich

Analysen analysieren

// 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];

Google Analytics

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

Firebase-Echtzeitdatenbank

Die Firebase Realtime Database ist eine in der NoSQL-Cloud gehostete Datenbank. Die Daten werden als JSON gespeichert und in Echtzeit mit jedem verbundenen Client synchronisiert.

Weitere Informationen finden Sie in der Dokumentation zur Firebase-Echtzeitdatenbank .

Unterschiede zu Parse-Daten

Objekte

In Parse speichern Sie ein PFObject oder eine Unterklasse davon, die Schlüssel-Wert-Paare JSON-kompatibler Daten enthält. Die Daten sind schemalos, was bedeutet, dass Sie nicht angeben müssen, welche Schlüssel auf jedem PFObject vorhanden sind.

Alle Daten der Firebase-Echtzeitdatenbank werden als JSON-Objekte gespeichert und es gibt kein Äquivalent für PFObject ; Sie schreiben einfach Werte von Typen in den JSON-Baum, die den verfügbaren JSON-Typen entsprechen.

Im Folgenden finden Sie ein Beispiel dafür, wie Sie die Highscores für ein Spiel speichern können.

Analysieren
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
  }
}];
Feuerbasis
// 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
  }
}];
Weitere Informationen finden Sie im Leitfaden zum Lesen und Schreiben von Daten auf Apple-Plattformen .

Beziehungen zwischen Daten

Ein PFObject kann eine Beziehung zu einem anderen PFObject haben: Jedes Objekt kann andere Objekte als Werte verwenden.

In der Firebase-Echtzeitdatenbank werden Beziehungen besser mithilfe flacher Datenstrukturen ausgedrückt, die die Daten in separate Pfade aufteilen, sodass sie in separaten Aufrufen effizient heruntergeladen werden können.

Im Folgenden finden Sie ein Beispiel dafür, wie Sie die Beziehung zwischen Beiträgen in einer Blogging-App und ihren Autoren strukturieren könnten.

Analysieren
// 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];
Feuerbasis
// 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]

Das folgende Datenlayout ist das Ergebnis.

{
  // 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"
    }
    ...
  }
}
Weitere Informationen finden Sie im Leitfaden „Strukturieren Sie Ihre Datenbank“ .

Daten lesen

In Parse lesen Sie Daten entweder mithilfe der ID eines bestimmten Parse-Objekts oder indem Sie Abfragen mit PFQuery ausführen.

In Firebase rufen Sie Daten ab, indem Sie einen asynchronen Listener an eine Datenbankreferenz anhängen. Der Listener wird einmal für den Anfangszustand der Daten und dann noch einmal ausgelöst, wenn sich die Daten ändern. Sie müssen also keinen Code hinzufügen, um festzustellen, ob sich die Daten geändert haben.

Im Folgenden finden Sie ein Beispiel dafür, wie Sie Punktestände für einen bestimmten Spieler abrufen können, basierend auf dem Beispiel im Abschnitt „Objekte“ .

Analysieren
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]);
  }
}];
Feuerbasis
// 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);
}];
Weitere Informationen zu den verfügbaren Arten von Ereignis-Listenern und zum Sortieren und Filtern von Daten finden Sie im Leitfaden zum Lesen und Schreiben von Daten auf Apple-Plattformen .

Vorgeschlagene Migrationsstrategie

Überdenken Sie Ihre Daten

Die Firebase-Echtzeitdatenbank ist für die Synchronisierung von Daten in Millisekunden auf allen verbundenen Clients optimiert. Die resultierende Datenstruktur unterscheidet sich von den Parse-Kerndaten. Das bedeutet, dass der erste Schritt Ihrer Migration darin besteht, zu überlegen, welche Änderungen Ihre Daten erfordern, einschließlich:

  • Wie Ihre Parse-Objekte Firebase-Daten zugeordnet werden sollen
  • Wenn Sie über Eltern-Kind-Beziehungen verfügen, erfahren Sie, wie Sie Ihre Daten auf verschiedene Pfade aufteilen, damit sie in separaten Aufrufen effizient heruntergeladen werden können.

Migrieren Sie Ihre Daten

Nachdem Sie entschieden haben, wie Sie Ihre Daten in Firebase strukturieren möchten, müssen Sie planen, wie Sie mit dem Zeitraum umgehen, in dem Ihre App in beide Datenbanken schreiben muss. Ihre Auswahl ist:

Hintergrundsynchronisierung

In diesem Szenario haben Sie zwei Versionen der App: die alte Version, die Parse verwendet, und eine neue Version, die Firebase verwendet. Synchronisierungen zwischen den beiden Datenbanken werden von Parse Cloud Code (Parse to Firebase) durchgeführt, wobei Ihr Code auf Änderungen in Firebase lauscht und diese Änderungen mit Parse synchronisiert. Bevor Sie die neue Version nutzen können, müssen Sie:

  • Konvertieren Sie Ihre vorhandenen Parse-Daten in die neue Firebase-Struktur und schreiben Sie sie in die Firebase-Echtzeitdatenbank.
  • Schreiben Sie Parse-Cloud-Code-Funktionen, die die Firebase-REST-API verwenden, um von alten Clients in den Parse-Daten vorgenommene Änderungen in die Firebase-Echtzeitdatenbank zu schreiben.
  • Schreiben und implementieren Sie Code, der auf Änderungen in Firebase lauscht und diese mit der Parse-Datenbank synchronisiert.

Dieses Szenario gewährleistet eine saubere Trennung von altem und neuem Code und hält die Clients einfach. Die Herausforderungen dieses Szenarios bestehen darin, große Datensätze beim ersten Export zu verarbeiten und sicherzustellen, dass die bidirektionale Synchronisierung keine unendliche Rekursion erzeugt.

Doppeltes Schreiben

In diesem Szenario schreiben Sie eine neue Version der App, die sowohl Firebase als auch Parse verwendet, und verwenden Parse Cloud Code, um von alten Clients vorgenommene Änderungen aus den Parse-Daten mit der Firebase-Echtzeitdatenbank zu synchronisieren. Wenn genügend Personen von der Nur-Parse-Version der App migriert sind, können Sie den Parse-Code aus der Double-Write-Version entfernen.

Für dieses Szenario ist kein serverseitiger Code erforderlich. Die Nachteile bestehen darin, dass Daten, auf die nicht zugegriffen wird, nicht migriert werden und dass die Größe Ihrer App durch die Verwendung beider SDKs zunimmt.

Firebase-Authentifizierung

Firebase Authentication kann Benutzer mithilfe von Passwörtern und beliebten Verbundidentitätsanbietern wie Google, Facebook und Twitter authentifizieren. Es stellt außerdem UI-Bibliotheken bereit, um Ihnen die erheblichen Investitionen zu ersparen, die für die Implementierung und Aufrechterhaltung einer vollständigen Authentifizierungserfahrung für Ihre App auf allen Plattformen erforderlich sind.

Weitere Informationen finden Sie in den Dokumenten zur Firebase-Authentifizierung .

Unterschiede zu Parse Auth

Parse stellt eine spezielle Benutzerklasse namens PFUser bereit, die automatisch die für die Benutzerkontenverwaltung erforderlichen Funktionen übernimmt. PFUser ist eine Unterklasse von PFObject , was bedeutet, dass Benutzerdaten in Parse Data verfügbar sind und wie jedes andere PFObject um zusätzliche Felder erweitert werden können.

Ein FIRUser verfügt über einen festen Satz grundlegender Eigenschaften – eine eindeutige ID, eine primäre E-Mail-Adresse, einen Namen und eine Foto-URL – die in der Benutzerdatenbank eines separaten Projekts gespeichert sind. Diese Eigenschaften können vom Benutzer aktualisiert werden. Sie können dem FIRUser Objekt keine anderen Eigenschaften direkt hinzufügen; Stattdessen können Sie die zusätzlichen Eigenschaften in Ihrer Firebase-Echtzeitdatenbank speichern.

Im Folgenden finden Sie ein Beispiel dafür, wie Sie einen Benutzer registrieren und ein zusätzliches Telefonnummernfeld hinzufügen können.

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

Vorgeschlagene Migrationsstrategie

Konten migrieren

Um Benutzerkonten von Parse zu Firebase zu migrieren, exportieren Sie Ihre Benutzerdatenbank in eine JSON- oder CSV-Datei und importieren Sie die Datei dann mit dem Befehl auth:import der Firebase-CLI in Ihr Firebase-Projekt.

Exportieren Sie zunächst Ihre Benutzerdatenbank aus der Parse-Konsole oder Ihrer selbst gehosteten Datenbank. Eine aus der Parse-Konsole exportierte JSON-Datei könnte beispielsweise wie folgt aussehen:

{ // 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",
  ...
}

Anschließend wandeln Sie die exportierte Datei in das von der Firebase-CLI benötigte Format um. Verwenden Sie die objectId Ihrer Parse-Benutzer als localId Ihrer Firebase-Benutzer. Außerdem kodiert Base64 die bcryptPassword Werte von Parse und verwendet sie im Feld passwordHash . Zum Beispiel:

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

Importieren Sie abschließend die transformierte Datei mit der Firebase-CLI und geben Sie dabei bcrypt als Hash-Algorithmus an:

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

Benutzerdaten migrieren

Wenn Sie zusätzliche Daten für Ihre Benutzer speichern, können Sie diese mithilfe der im Abschnitt zur Datenmigration beschriebenen Strategien zur Firebase Realtime Database migrieren. Wenn Sie Konten mit dem im Abschnitt „Kontenmigration“ beschriebenen Ablauf migrieren, haben Ihre Firebase-Konten dieselben IDs wie Ihre Parse-Konten, sodass Sie alle durch die Benutzer-ID verschlüsselten Beziehungen einfach migrieren und reproduzieren können.

Firebase Cloud-Messaging

Firebase Cloud Messaging (FCM) ist eine plattformübergreifende Messaging-Lösung, mit der Sie Nachrichten und Benachrichtigungen zuverlässig und kostenlos übermitteln können. Der Notifications Composer ist ein kostenloser Dienst, der auf Firebase Cloud Messaging basiert und gezielte Benutzerbenachrichtigungen für Entwickler mobiler Apps ermöglicht.

Weitere Informationen finden Sie in den Firebase Cloud Messaging-Dokumenten .

Unterschiede zu Parse-Push-Benachrichtigungen

Jede Parse-Anwendung, die auf einem für Benachrichtigungen registrierten Gerät installiert ist, verfügt über ein zugehöriges Installation , in dem Sie alle Daten speichern, die für gezielte Benachrichtigungen erforderlich sind. Installation ist eine Unterklasse von PFUser , was bedeutet, dass Sie Ihren Installation beliebige zusätzliche Daten hinzufügen können.

Der Notifications Composer stellt vordefinierte Benutzersegmente basierend auf Informationen wie App, App-Version und Gerätesprache bereit. Mithilfe von Google Analytics-Ereignissen und -Eigenschaften können Sie komplexere Benutzersegmente erstellen, um Zielgruppen aufzubauen. Weitere Informationen finden Sie im Hilfeleitfaden für Zielgruppen . Diese Targeting-Informationen sind in der Firebase-Echtzeitdatenbank nicht sichtbar.

Vorgeschlagene Migrationsstrategie

Gerätetoken migrieren

Während Parse APNs-Gerätetokens verwendet, um Installationen für Benachrichtigungen anzusprechen, verwendet FCM FCM-Registrierungstokens, die den APNs-Gerätetokens zugeordnet sind. Fügen Sie einfach das FCM SDK zu Ihrer Apple-App hinzu und es ruft automatisch ein FCM-Token ab .

Kanäle zu FCM-Themen migrieren

Wenn Sie Parse-Kanäle zum Senden von Benachrichtigungen verwenden, können Sie zu FCM-Themen migrieren, die dasselbe Herausgeber-Abonnenten-Modell bieten. Um den Übergang von Parse zu FCM zu bewältigen, können Sie eine neue Version der App schreiben, die das Parse SDK zum Abbestellen von Parse-Kanälen und das FCM SDK zum Abonnieren entsprechender FCM-Themen verwendet.

Wenn Ihr Benutzer beispielsweise das Thema „Riesen“ abonniert hat, würden Sie Folgendes tun:

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

Mit dieser Strategie können Sie Nachrichten sowohl an den Parse-Kanal als auch an das entsprechende FCM-Thema senden und so Benutzer sowohl alter als auch neuer Versionen unterstützen. Wenn genügend Benutzer von der Nur-Parse-Version der App migriert sind, können Sie diese Version beenden und mit dem Senden nur über FCM beginnen.

Weitere Informationen finden Sie in den FCM-Themendokumenten .

Firebase-Remote-Konfiguration

Firebase Remote Config ist ein Cloud-Dienst, mit dem Sie das Verhalten und Erscheinungsbild Ihrer App ändern können, ohne dass Benutzer ein App-Update herunterladen müssen. Wenn Sie Remote Config verwenden, erstellen Sie In-App-Standardwerte, die das Verhalten und Erscheinungsbild Ihrer App steuern. Anschließend können Sie die Firebase-Konsole später verwenden, um In-App-Standardwerte für alle App-Benutzer oder für Segmente Ihrer Benutzerbasis zu überschreiben.

Firebase Remote Config kann bei Ihren Migrationen sehr nützlich sein, wenn Sie verschiedene Lösungen testen und mehr Clients dynamisch zu einem anderen Anbieter verlagern möchten. Wenn Sie beispielsweise über eine Version Ihrer App verfügen, die sowohl Firebase als auch Parse für die Daten verwendet, können Sie eine zufällige Perzentilregel verwenden, um zu bestimmen, welche Clients aus Firebase lesen, und den Prozentsatz schrittweise erhöhen.

Weitere Informationen zu Firebase Remote Config finden Sie in der Einführung zu Remote Config .

Unterschiede zur Parse-Konfiguration

Mit Parse config können Sie Ihrer App im Parse Config Dashboard Schlüssel/Wert-Paare hinzufügen und dann die PFConfig auf dem Client abrufen. Jede PFConfig Instanz, die Sie erhalten, ist immer unveränderlich. Wenn Sie in Zukunft eine neue PFConfig aus dem Netzwerk abrufen, wird dadurch keine vorhandene PFConfig Instanz geändert, sondern stattdessen eine neue erstellt und über currentConfig verfügbar gemacht.

Mit Firebase Remote Config erstellen Sie In-App-Standardeinstellungen für Schlüssel/Wert-Paare, die Sie über die Firebase-Konsole überschreiben können, und Sie können Regeln und Bedingungen verwenden, um verschiedenen Segmenten Ihrer Benutzerbasis Variationen der Benutzererfahrung Ihrer App bereitzustellen. Firebase Remote Config implementiert eine Singleton-Klasse, die die Schlüssel/Wert-Paare für Ihre App verfügbar macht. Zunächst gibt der Singleton die Standardwerte zurück, die Sie in der App definieren. Sie können zu jedem für Ihre App geeigneten Zeitpunkt einen neuen Satz Werte vom Server abrufen. Nachdem der neue Satz erfolgreich abgerufen wurde, können Sie auswählen, wann er aktiviert werden soll, um die neuen Werte für die App verfügbar zu machen.

Vorgeschlagene Migrationsstrategie

Sie können zu Firebase Remote Config wechseln, indem Sie die Schlüssel/Wert-Paare Ihrer Parse-Konfiguration in die Firebase-Konsole kopieren und dann eine neue Version der App bereitstellen, die Firebase Remote Config verwendet.

Wenn Sie sowohl mit Parse Config als auch mit Firebase Remote Config experimentieren möchten, können Sie eine neue Version der App bereitstellen, die beide SDKs verwendet, bis genügend Benutzer von der reinen Parse-Version migriert sind.

Code-Vergleich

Analysieren

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

Feuerbasis

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;