Przenieś swoją aplikację Parse iOS do Firebase

Jeśli jesteś użytkownikiem Parse i szukasz alternatywnego rozwiązania Backend as a Service, Firebase może być idealnym wyborem dla Twojej aplikacji na iOS.

W tym przewodniku opisano, jak zintegrować określone usługi z aplikacją. Podstawowe instrukcje konfiguracji Firebase znajdziesz w przewodniku konfiguracji iOS+ .

Google Analytics

Google Analytics to bezpłatne rozwiązanie do pomiaru aplikacji, które zapewnia wgląd w wykorzystanie aplikacji i zaangażowanie użytkowników. Analytics integruje się z funkcjami Firebase i zapewnia nieograniczone raportowanie dla maksymalnie 500 różnych zdarzeń, które możesz zdefiniować za pomocą pakietu Firebase SDK.

Zapoznaj się z dokumentacją Google Analytics , aby dowiedzieć się więcej.

Sugerowana strategia migracji

Korzystanie z różnych dostawców usług analitycznych to typowy scenariusz, który można łatwo zastosować w Google Analytics. Po prostu dodaj go do swojej aplikacji, aby korzystać ze zdarzeń i właściwości użytkowników, które Analytics zbiera automatycznie, takich jak pierwsze uruchomienie, aktualizacja aplikacji, model urządzenia, wiek.

W przypadku niestandardowych zdarzeń i właściwości użytkownika możesz zastosować strategię podwójnego zapisu, używając zarówno Parse Analytics, jak i Google Analytics do rejestrowania zdarzeń i właściwości, co pozwala na stopniowe wdrażanie nowego rozwiązania.

Porównanie kodu

Analiza analizy

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

Baza danych czasu rzeczywistego Firebase

Baza danych czasu rzeczywistego Firebase to baza danych NoSQL hostowana w chmurze. Dane są przechowywane w formacie JSON i synchronizowane w czasie rzeczywistym z każdym podłączonym klientem.

Więcej informacji znajdziesz w dokumentacji bazy danych czasu rzeczywistego Firebase .

Różnice z danymi analizy

Obiekty

W Parse przechowujesz PFObject lub jego podklasę, która zawiera pary klucz-wartość danych zgodnych z JSON. Dane są bez schematu, co oznacza, że ​​nie musisz określać, jakie klucze istnieją w każdym PFObject .

Wszystkie dane bazy danych czasu rzeczywistego Firebase są przechowywane jako obiekty JSON i nie ma odpowiednika dla PFObject ; po prostu piszesz do wartości drzewa JSON typów, które odpowiadają dostępnym typom JSON.

Poniżej znajduje się przykład, w jaki sposób możesz zapisać najlepsze wyniki w grze.

Analizować
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
  }
}];
Firebase
// 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
  }
}];
Aby uzyskać więcej informacji, zapoznaj się z przewodnikiem dotyczącym odczytu i zapisu danych na platformach Apple .

Relacje między danymi

PFObject może mieć związek z innym PFObject : każdy obiekt może używać innych obiektów jako wartości.

W Bazie danych czasu rzeczywistego Firebase relacje są lepiej wyrażane za pomocą płaskich struktur danych, które dzielą dane na oddzielne ścieżki, dzięki czemu można je skutecznie pobierać w osobnych wywołaniach.

Poniżej znajduje się przykład struktury relacji między postami w aplikacji do blogowania a ich autorami.

Analizować
// 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];
Firebase
// 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]

Wynikiem jest następujący układ danych.

{
  // 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"
    }
    ...
  }
}
Więcej informacji znajdziesz w przewodniku Structure Your Database .

Czytanie danych

W Parse odczytujesz dane za pomocą identyfikatora określonego obiektu Parse lub wykonując zapytania za pomocą PFQuery .

W Firebase pobierasz dane, dołączając asynchroniczny detektor do odwołania do bazy danych. Odbiornik jest wyzwalany raz dla początkowego stanu danych i ponownie, gdy dane się zmieniają, więc nie trzeba dodawać żadnego kodu w celu ustalenia, czy dane uległy zmianie.

Poniżej znajduje się przykład, w jaki sposób można pobrać wyniki dla konkretnego gracza, na podstawie przykładu przedstawionego w sekcji „Obiekty” .

Analizować
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]);
  }
}];
Firebase
// 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);
}];
Więcej informacji na temat dostępnych typów detektorów zdarzeń oraz sposobu porządkowania i filtrowania danych można znaleźć w przewodniku Odczyt i zapis danych na platformach Apple .

Sugerowana strategia migracji

Przemyśl swoje dane

Baza danych czasu rzeczywistego Firebase jest zoptymalizowana pod kątem synchronizowania danych w milisekundach na wszystkich podłączonych klientach, a wynikowa struktura danych różni się od danych podstawowych Parse. Oznacza to, że pierwszym krokiem migracji jest rozważenie, jakich zmian wymagają Twoje dane, w tym:

  • Jak obiekty Parse powinny być mapowane na dane Firebase
  • Jeśli masz relacje rodzic-dziecko, jak podzielić dane na różne ścieżki, aby można je było skutecznie pobierać w osobnych wywołaniach.

Przenieś swoje dane

Gdy zdecydujesz, jak uporządkować dane w Firebase, musisz zaplanować, jak obsłużyć okres, w którym aplikacja musi zapisywać dane w obu bazach danych. Twoje wybory to:

Synchronizacja w tle

W tym scenariuszu masz dwie wersje aplikacji: starą wersję korzystającą z funkcji Parse i nową wersję korzystającą z Firebase. Synchronizacje między dwiema bazami danych są obsługiwane przez Parse Cloud Code (Parse to Firebase), a Twój kod nasłuchuje zmian w Firebase i synchronizuje te zmiany z Parse. Zanim zaczniesz korzystać z nowej wersji, musisz:

  • Przekształć istniejące dane analizy do nowej struktury Firebase i zapisz je w bazie danych czasu rzeczywistego Firebase.
  • Napisz funkcje Parse Cloud Code, które używają interfejsu Firebase REST API do zapisywania w bazie danych czasu rzeczywistego Firebase zmian wprowadzonych w Parse Data przez starych klientów.
  • Napisz i wdróż kod, który nasłuchuje zmian w Firebase i synchronizuje je z bazą danych Parse.

Ten scenariusz zapewnia czyste oddzielenie starego i nowego kodu oraz zapewnia prostotę klientów. Wyzwania tego scenariusza to obsługa dużych zestawów danych w początkowym eksporcie i zapewnienie, że synchronizacja dwukierunkowa nie generuje nieskończonej rekursji.

Podwójny zapis

W tym scenariuszu piszesz nową wersję aplikacji, która korzysta zarówno z Firebase, jak i Parse, używając Parse Cloud Code do synchronizowania zmian wprowadzonych przez starych klientów z Parse Data do Firebase Realtime Database. Gdy wystarczająca liczba osób przeniesie się z wersji aplikacji tylko do analizy, możesz usunąć kod analizy z wersji z podwójnym zapisem.

Ten scenariusz nie wymaga żadnego kodu po stronie serwera. Jego wadą jest to, że dane, do których nie uzyskuje się dostępu, nie są migrowane, a rozmiar aplikacji jest zwiększany przez użycie obu zestawów SDK.

Uwierzytelnianie Firebase

Uwierzytelnianie Firebase może uwierzytelniać użytkowników za pomocą haseł i popularnych dostawców tożsamości sfederowanych, takich jak Google, Facebook i Twitter. Zapewnia również biblioteki interfejsu użytkownika, aby zaoszczędzić znaczne inwestycje wymagane do wdrożenia i utrzymania pełnego środowiska uwierzytelniania dla Twojej aplikacji na wszystkich platformach.

Więcej informacji znajdziesz w dokumentach Uwierzytelnianie Firebase .

Różnice z Parse Auth

Parse udostępnia wyspecjalizowaną klasę użytkownika o nazwie PFUser , która automatycznie obsługuje funkcje wymagane do zarządzania kontami użytkowników. PFUser jest podklasą PFObject , co oznacza, że ​​dane użytkownika są dostępne w Parse Data i mogą być rozszerzone o dodatkowe pola, jak każdy inny PFObject .

FIRUser ma ustalony zestaw podstawowych właściwości — unikalny identyfikator, podstawowy adres e-mail, nazwę i adres URL zdjęcia — przechowywany w oddzielnej bazie danych użytkowników projektu; te właściwości mogą być aktualizowane przez użytkownika. Nie można bezpośrednio dodawać innych właściwości do obiektu FIRUser ; zamiast tego możesz przechowywać dodatkowe właściwości w Bazie danych czasu rzeczywistego Firebase.

Poniżej znajduje się przykład, w jaki sposób możesz zarejestrować użytkownika i dodać dodatkowe pole numeru telefonu.

Analizować
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"];
  }
}];
Firebase
[[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"];
  }
}];

Sugerowana strategia migracji

Przenieś konta

Aby przeprowadzić migrację kont użytkowników z Parse do Firebase, wyeksportuj bazę danych użytkowników do pliku JSON lub CSV, a następnie zaimportuj plik do projektu Firebase za pomocą polecenia auth:import interfejsu wiersza polecenia Firebase.

Najpierw wyeksportuj bazę danych użytkowników z konsoli Parse lub własnej bazy danych. Na przykład plik JSON wyeksportowany z konsoli Parse może wyglądać tak:

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

Następnie przekształć wyeksportowany plik do formatu wymaganego przez interfejs Firebase CLI. Użyj identyfikatora obiektu swoich użytkowników Parse jako identyfikatora localId użytkowników objectId . Ponadto zakoduj base64 wartości bcryptPassword z Parse i użyj ich w polu passwordHash . Na przykład:

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

Na koniec zaimportuj przekształcony plik za pomocą interfejsu Firebase CLI, określając bcrypt jako algorytm skrótu:

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

Przenieś dane użytkownika

Jeśli przechowujesz dodatkowe dane dla użytkowników, możesz przenieść je do Bazy danych czasu rzeczywistego Firebase, korzystając ze strategii opisanych w sekcji migracji danych . Jeśli przeprowadzasz migrację kont przy użyciu procedury opisanej w sekcji migracji kont , Twoje konta Firebase mają te same identyfikatory, co konta Parse, co pozwala na łatwą migrację i odtworzenie wszelkich relacji, których kluczem jest identyfikator użytkownika.

Wiadomości w chmurze Firebase

Firebase Cloud Messaging (FCM) to wieloplatformowe rozwiązanie do przesyłania wiadomości, które umożliwia niezawodne dostarczanie wiadomości i powiadomień bez żadnych kosztów. Kreator powiadomień to bezpłatna usługa oparta na Firebase Cloud Messaging, która umożliwia twórcom aplikacji mobilnych ukierunkowane powiadomienia użytkowników.

Więcej informacji znajdziesz w dokumentacji Firebase Cloud Messaging .

Różnice w parsowaniu powiadomień push

Każda aplikacja Parse zainstalowana na urządzeniu zarejestrowanym jako powiadomienia ma skojarzony obiekt Installation , w którym przechowujesz wszystkie dane potrzebne do kierowania powiadomień. Installation jest podklasą PFUser , co oznacza, że ​​możesz dodać dowolne dodatkowe dane do swoich instancji Installation .

Kreator powiadomień udostępnia predefiniowane segmenty użytkowników na podstawie informacji, takich jak aplikacja, wersja aplikacji i język urządzenia. Możesz tworzyć bardziej złożone segmenty użytkowników, korzystając ze zdarzeń i usług Google Analytics do tworzenia grup odbiorców. Zobacz przewodnik pomocy dla odbiorców , aby dowiedzieć się więcej. Te informacje o kierowaniu nie są widoczne w Bazie danych czasu rzeczywistego Firebase.

Sugerowana strategia migracji

Migracja tokenów urządzeń

Podczas gdy Parse używa tokenów urządzeń APNs do kierowania instalacji na potrzeby powiadomień, FCM używa tokenów rejestracji FCM zamapowanych na tokeny urządzeń APNs. Wystarczy dodać pakiet SDK FCM do aplikacji Apple, a automatycznie pobierze on token FCM .

Migracja kanałów do tematów FCM

Jeśli używasz kanałów analizy do wysyłania powiadomień, możesz przeprowadzić migrację do tematów FCM, które zapewniają ten sam model wydawca-subskrybent. Aby obsłużyć przejście z Parse do FCM, możesz napisać nową wersję aplikacji, która używa pakietu Parse SDK do anulowania subskrypcji kanałów analizy i FCM SDK do subskrybowania odpowiednich tematów FCM.

Na przykład, jeśli Twój użytkownik subskrybuje temat „Giants”, możesz zrobić coś takiego:

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

Korzystając z tej strategii, możesz wysyłać wiadomości zarówno do kanału Parse, jak i odpowiedniego tematu FCM, wspierając użytkowników zarówno starych, jak i nowych wersji. Gdy wystarczająca liczba użytkowników przeniesie się z wersji aplikacji tylko do analizy, możesz wyłączyć tę wersję i rozpocząć wysyłanie przy użyciu tylko FCM.

Zapoznaj się z dokumentacją dotyczącą tematów FCM, aby dowiedzieć się więcej.

Zdalna konfiguracja Firebase

Zdalna konfiguracja Firebase to usługa w chmurze, która umożliwia zmianę zachowania i wyglądu aplikacji bez konieczności pobierania aktualizacji aplikacji przez użytkowników. Korzystając ze zdalnej konfiguracji, tworzysz wartości domyślne w aplikacji, które kontrolują zachowanie i wygląd aplikacji. Następnie możesz później użyć konsoli Firebase, aby zastąpić domyślne wartości w aplikacji dla wszystkich użytkowników aplikacji lub dla segmentów swojej bazy użytkowników.

Zdalna konfiguracja Firebase może być bardzo przydatna podczas migracji w przypadkach, gdy chcesz przetestować różne rozwiązania i mieć możliwość dynamicznego przeniesienia większej liczby klientów do innego dostawcy. Na przykład, jeśli masz wersję aplikacji, która korzysta z danych zarówno Firebase, jak i Parse, możesz użyć losowej reguły centylowej, aby określić, którzy klienci czytają z Firebase, i stopniowo zwiększać odsetek.

Aby dowiedzieć się więcej o zdalnej konfiguracji Firebase, zobacz wprowadzenie do zdalnej konfiguracji .

Różnice z konfiguracją analizy

Dzięki Parse config możesz dodać pary klucz/wartość do swojej aplikacji na pulpicie nawigacyjnym Parse Config Dashboard, a następnie pobrać PFConfig na kliencie. Każda otrzymana instancja PFConfig jest zawsze niezmienna. Gdy w przyszłości pobierzesz nową PFConfig z sieci, nie zmodyfikuje ona żadnej istniejącej instancji PFConfig , ale zamiast tego utworzy nową i udostępni ją za pośrednictwem currentConfig .

Dzięki zdalnej konfiguracji Firebase tworzysz wartości domyślne w aplikacji dla par klucz/wartość, które możesz zastąpić z poziomu konsoli Firebase, a także możesz używać reguł i warunków, aby udostępniać różne warianty doświadczenia użytkownika aplikacji w różnych segmentach bazy użytkowników. Zdalna konfiguracja Firebase implementuje pojedynczą klasę, która udostępnia pary klucz/wartość w Twojej aplikacji. Początkowo singleton zwraca wartości domyślne, które definiujesz w aplikacji. Możesz pobrać nowy zestaw wartości z serwera w dowolnym momencie dogodnym dla Twojej aplikacji; po pomyślnym pobraniu nowego zestawu możesz wybrać, kiedy go aktywować, aby nowe wartości były dostępne dla aplikacji.

Sugerowana strategia migracji

Możesz przejść do zdalnej konfiguracji Firebase, kopiując pary klucz/wartość konfiguracji analizowania do konsoli Firebase, a następnie wdrażając nową wersję aplikacji, która korzysta ze zdalnej konfiguracji Firebase.

Jeśli chcesz poeksperymentować zarówno z konfiguracją analizy, jak i zdalną konfiguracją Firebase, możesz wdrożyć nową wersję aplikacji, która korzysta z obu pakietów SDK, dopóki wystarczająca liczba użytkowników nie przejdzie migracji z wersji tylko do analizy.

Porównanie kodu

Analizować

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

Firebase

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;