Przenoszenie aplikacji „Analizuj” na iOS do Firebase

Jeśli używasz analizy i szukasz alternatywnego backendu jako Usługa Firebase może być idealnym wyborem dla Twojej aplikacji na iOS.

Z tego przewodnika dowiesz się, jak zintegrować określone usługi z aplikacją. Dla: podstawowych instrukcji konfigurowania Firebase znajdziesz w artykule Konfiguracja iOS+. Google.

Google Analytics

Google Analytics to bezpłatne rozwiązanie analityczne, które zapewnia statystyki użytkowania aplikacji zaangażowanie użytkowników. Analytics integruje się z funkcjami Firebase i daje nieograniczone możliwości Może generować raporty obejmujące do 500 różnych zdarzeń, które można zdefiniować za pomocą pakietu SDK Firebase.

Aby dowiedzieć się więcej, zapoznaj się z dokumentacją usługi Google Analytics.

Sugerowana strategia migracji

Korzystanie z usług różnych dostawców usług analitycznych to typowy scenariusz, który można z łatwością zastosować Google Analytics Dodaj je do swojej aplikacji, by korzystać ze zdarzeń i właściwości użytkownika, które Aplikacja Analytics zbiera automatycznie dane takie jak pierwsze uruchomienie, aktualizacja aplikacji, model urządzenia czy wiek.

W przypadku zdarzeń niestandardowych i właściwości użytkownika możesz zastosować strategię podwójnego zapisu za pomocą funkcji Analizuj Analytics i Google Analytics, aby rejestrować zdarzenia i właściwości, co umożliwia stopniowo wdrażać nowe rozwiązanie.

Porównanie kodu

Analizuj statystyki

// 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 Realtime Database

Firebase Realtime Database to baza danych NoSQL hostowana w chmurze. Dane są przechowywane w formacie JSON oraz synchronizowane w czasie rzeczywistym z każdym połączonym klientem.

Aby dowiedzieć się więcej, zapoznaj się z dokumentacją usługi Firebase Realtime Database.

Różnice w danych analizy

Obiekty

Funkcja Analiza przechowuje klasę PFObject (lub jej podklasę), która zawiera pary klucz-wartość danych zgodnych z formatem JSON. Dane są nieschematyczne, co oznacza, że nie musisz określać, które klucze istnieje w każdym PFObject.

Wszystkie dane Firebase Realtime Database są przechowywane jako obiekty JSON i nie ma ich odpowiednika PFObject możesz po prostu zapisać w formacie JSON wartości typów, które odpowiadają na dostępne typy JSON.

Oto przykład zapisywania najlepszych wyników w grze.

Analizuj
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 dowiedzieć się więcej, zapoznaj się z Przewodnik na temat odczytu i zapisu danych na platformach Apple.

Relacje między danymi

Element PFObject może być powiązany z innym elementem PFObject: dowolny może używać innych obiektów jako wartości.

W tabeli Firebase Realtime Database relacje lepiej wyraża się przy użyciu płaskich struktur danych, które podzielić dane na osobne ścieżki, aby można było wydajnie pobierać je w ramach osobnych wywołań.

Poniższy przykład pokazuje, jak można uporządkować relacje między postami w aplikacji do blogowania i ich autorów.

Analizuj
// 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 poniższy 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"
    }
    ...
  }
}
Aby dowiedzieć się więcej, zapoznaj się z Utwórz strukturę bazy danych Google.

Odczytywanie danych

W sekcji Analizuj dane odczytujesz za pomocą identyfikatora konkretnego obiektu Parse lub wykonywania zapytań za pomocą funkcji PFQuery.

W Firebase pobierasz dane, dołączając detektor asynchroniczny do odwołania do bazy danych. jest aktywowany raz dla początkowego stanu danych i ponownie po zmianie, więc nie trzeba dodawać żadnego kodu w celu określenia, czy dane się zmieniły.

Poniżej znajdziesz przykład pobierania wyników dla konkretnego gracza, który zależy od tego, co pokazujemy w sekcji "Obiekty".

Analizuj
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 o dostępnych typach detektorów zdarzeń oraz o porządku i filtrowaniu danych, Odczyt i zapis danych na platformach Apple Google.

Sugerowana strategia migracji

Przemyśl swoje dane

Urządzenie Firebase Realtime Database jest zoptymalizowane pod kątem synchronizacji danych w milisekundach na wszystkich połączonych urządzeniach klientów, a powstała struktura danych różni się od struktury podstawowych danych analizy. Oznacza to, że Pierwszym krokiem w migracji jest zastanowienie się, jakie zmiany wymagają danych. Oto niektóre z nich:

  • Jak obiekty Parse powinny być mapowane na dane Firebase
  • Jak podzielić dane na różne ścieżki w przypadku relacji nadrzędny-podrzędny można efektywnie pobierać w ramach osobnych wywołań.

Migracja danych

Po wybraniu struktury danych w Firebase musisz zaplanować sposób obsługi okresu, w którym aplikacja musi zapisywać dane w obu bazach danych. Opcje do wyboru:

Synchronizacja w tle

Masz 2 wersje aplikacji: starą, która korzysta z funkcji Analizuj i nowa wersji korzystającej z Firebase. Synchronizacja między 2 bazami danych jest obsługiwana przez narzędzie Parse Cloud Code do Firebase), a Twój kod będzie nasłuchiwać zmian w Firebase i synchronizować je za pomocą Parse. Zanim zaczniesz korzystać z nowej wersji, musisz:

  • Przekonwertuj istniejące dane analizy na nową strukturę Firebase i zapisz je w Firebase Realtime Database
  • Napisz funkcje analizy Cloud Code korzystające z interfejsu API REST Firebase do zapisywania w Zmiany wprowadzone w analizie danych przez starych klientów (Firebase Realtime Database).
  • Napisz i wdróż kod, który nasłuchuje zmian w Firebase i synchronizuje je z analizą w bazie danych.

Ten scenariusz zapewnia wyraźne oddzielenie starego od nowego kodu oraz upraszcza obsługę klientów. Wyzwania w tym scenariuszu to obsługa dużych zbiorów danych podczas początkowego eksportu i zapewnienie, że synchronizacja dwukierunkowa nie generuje nieskończonej rekurencji.

Podwójny zapis

Tworzysz nową wersję aplikacji, która korzysta zarówno z Firebase, jak i Analizuj Analizuj Cloud Code, aby zsynchronizować zmiany wprowadzone przez stare klienty z analizy danych do Firebase Realtime Database Gdy wystarczająca liczba osób przemieści się z wersji tylko do analizy, może usunąć kod analizy z wersji z podwójnym zapisem.

W tym scenariuszu nie jest wymagany żaden kod po stronie serwera. Wadą tej metody jest to, że dane, które nie są dane nie są przenoszone, a rozmiar aplikacji zwiększa się przez użycie obu pakietów SDK.

Firebase Authentication

Firebase Authentication może uwierzytelniać użytkowników przy użyciu haseł i popularnych dostawców tożsamości sfederowanej takich jak Google, Facebook czy Twitter. Udostępnia także biblioteki interfejsu, dzięki którym można zaoszczędzić inwestycji w wdrożenie i utrzymywanie pełnego uwierzytelniania aplikacji na wszystkich platformach.

Aby dowiedzieć się więcej, zapoznaj się z dokumentacją usługi Firebase Authentication.

Różnice związane z uwierzytelnianiem analizy

Analiza udostępnia specjalną klasę użytkownika o nazwie PFUser, która automatycznie obsługuje funkcje wymagane do zarządzania kontem użytkownika. PFUser jest podklasą klasy PFObject, co oznacza, że dane użytkownika są dostępne w ramach analizy danych i można je rozszerzyć za pomocą takich jak wszystkie pozostałe pola PFObject.

FIRUser ma stały zestaw właściwości podstawowych – unikalny identyfikator, podstawowy adres e-mail, nazwę i adres URL zdjęcia – są przechowywane w bazie danych użytkowników osobnego projektu; te właściwości można zaktualizować przez użytkownika. Nie możesz dodać innych właściwości bezpośrednio do obiektu FIRUser. możesz przechowywać dodatkowe usługi w Firebase Realtime Database.

Poniżej pokazujemy, jak zarejestrować użytkownika i dodać kolejne pole numeru telefonu.

Analizuj
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 przenieść konta użytkowników z funkcji Analizuj do Firebase, wyeksportuj bazę danych użytkowników do JSON lub CSV, a potem zaimportuj go do projektu Firebase za pomocą auth:import interfejsu wiersza poleceń Firebase .

Najpierw wyeksportuj bazę danych użytkowników za pomocą konsoli analizy lub własnego serwera w bazie danych. Na przykład plik JSON wyeksportowany z konsoli analizy może wyglądać tak: np.:

{ // 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 Firebase interfejs wiersza poleceń. Użyj sekcji objectId użytkowników analizy jako localId użytkowników Firebase. Dodatkowo w base64 koduj Wartości bcryptPassword z analizy i użyj ich w passwordHash . 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 wiersza poleceń Firebase, określając bcrypt. jako algorytm szyfrowania:

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

Migracja danych użytkownika

Jeśli przechowujesz dodatkowe dane użytkowników, możesz je przenieść do usługi Firebase Realtime Database korzystając ze strategii opisanych w sekcji na temat migracji danych. Migracja kont przy użyciu procesu opisanego w sekcji Migracja kont, Konta Firebase mają te same identyfikatory co konta analizy, co pozwala na łatwą migrację i odtwarzanie we wszystkich relacjach, których kluczem jest identyfikator użytkownika.

Firebase Cloud Messaging

Firebase Cloud Messaging (FCM) to wieloplatformowe rozwiązanie do przesyłania wiadomości, które dostarczać wiadomości i powiadomienia bez opłat. Edytor powiadomień to bezpłatna usługa w Firebase Cloud Messaging, która włącza kierowane powiadomienia dla deweloperów aplikacji mobilnych.

Aby dowiedzieć się więcej, zapoznaj się z dokumentacją usługi Firebase Cloud Messaging .

Różnice w sposobie analizowania powiadomień push

Każda aplikacja do analizy danych zainstalowana na urządzeniu zarejestrowanym na potrzeby powiadomień ma powiązane Installation, w którym przechowujesz wszystkie dane potrzebne do kierowania powiadomień. Installation jest podklasą klasy PFUser, co oznacza, że możesz dodawać wszelkie dodatkowe dane do instancji Installation.

Edytor powiadomień zapewnia wstępnie zdefiniowane segmenty użytkowników na podstawie takich informacji jak aplikacja, wersja aplikacji i urządzenie język. Możesz tworzyć bardziej złożone segmenty użytkowników za pomocą zdarzeń i właściwości Google Analytics do tworzenia list odbiorców. Zobacz odbiorców aby dowiedzieć się więcej. Te informacje dotyczące kierowania nie są widoczne w Firebase Realtime Database.

Sugerowana strategia migracji

Migracja tokenów urządzeń

Analiza używa tokenów urządzeń APNs do kierowania instalacji powiadomień, FCM używa tokenów rejestracji FCM zmapowanych na tokeny urządzenia APNs. Wystarczy, że dodasz FCM pakietu SDK do aplikacji Apple, co automatycznie pobierze token FCM.

Przenosimy kanały do FCM tematów

Jeśli używasz kanałów „Analizuj kanały” do wysyłania powiadomień, możesz przeprowadzić migrację do FCM tematów, które zapewniają taki sam model wydawcy i subskrybent. Aby obsłużyć przejście z analizy na FCM, możesz napisać nową wersję aplikacji, która korzysta z pakietu SDK Parse do anulowania subskrypcji kanałów Parse, oraz pakietu SDK FCM do subskrybowania powiązanych FCM tematów.

Na przykład, jeśli użytkownik subskrybuje kanał „Giganci” , wpisz coś takiego:

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

Dzięki tej strategii możesz wysyłać wiadomości zarówno do kanału Analizuj, jak i do odpowiedniego kanału FCM, który obsługuje użytkowników zarówno starej, jak i nowej wersji. Gdy wystarczająca liczba użytkowników przeniosła się ze Wersja aplikacji tylko do analizy. Możesz ją wycofać i zacząć wysyłać tylko za pomocą FCM.

Zobacz dokumenty dotyczące tematów (FCM) aby dowiedzieć się więcej.

Firebase Remote Config

Firebase Remote Config to usługa w chmurze, która umożliwia zmianę działania i wyglądu bez konieczności pobierania aktualizacji przez użytkowników. Korzystając ze Zdalnej konfiguracji, tworzysz w aplikacji wartości domyślne, które określają działanie i wygląd aplikacji. Później możesz użyć atrybutu w konsoli Firebase, aby zastąpić domyślne wartości w aplikacji dla wszystkich użytkowników aplikacji lub ich segmentów.

Narzędzie Firebase Remote Config może być bardzo przydatne podczas migracji, jeśli chcesz ją przetestować. różnych rozwiązań i możliwość dynamicznego przekierowywania kolejnych klientów do innego dostawcy. Przykład: Jeśli masz wersję swojej aplikacji, która korzysta z danych Firebase i Analizuj, możesz użyć funkcji losowego centyla, aby określić, którzy klienci odczytują dane z Firebase, i stopniowo zwiększać tę wartość.

Więcej informacji o funkcji Firebase Remote Config znajdziesz tutaj: Remote Config wprowadzenie.

Różnice z konfiguracją analizy

Dzięki konfiguracji analizy możesz dodać pary klucz/wartość do swojej aplikacji w panelu konfiguracji analizy, pobierze PFConfig na klienta. Każde PFConfig wystąpienie Parametr get jest zawsze niezmienny. Jeśli w przyszłości pobierzesz nowy plik PFConfig z usługi nie zmodyfikuje żadnej z istniejących instancji PFConfig, ale w przeciwieństwie do tego utwórz nowy i udostępnij go za pośrednictwem usługi currentConfig.

Funkcja Firebase Remote Config pozwala tworzyć w aplikacji domyślne ustawienia dla par klucz-wartość, które możesz zastąpić w konsoli Firebase. Możesz używać reguł i warunków, by generować odmiany do różnych grup odbiorców. Firebase Remote Config stosuje klasa singleton, która udostępnia pary klucz-wartość aplikacji. Początkowo singleton zwraca domyślnych wartości zdefiniowanych w aplikacji. Nowy zbiór wartości możesz pobrać z serwera w dowolnym momencie dogodne dla Twojej aplikacji, po pomyślnym pobraniu nowego zestawu możesz wybrać, kiedy aktywować aby udostępnić nowe wartości aplikacji.

Sugerowana strategia migracji

Możesz przejść do Firebase Remote Config, kopiując pary klucz/wartość z konfiguracji analizy za pomocą konsoli Firebase, a następnie wdróż nową wersję aplikacji, która korzysta z narzędzia Firebase Remote Config.

Jeśli chcesz eksperymentować z konfiguracją analizy i Firebase Remote Config, 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 z wersji „Tylko analiza”.

Porównanie kodu

Analizuj

[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;