Se sei un utente di Parse alla ricerca di un backend alternativo come di servizi, Firebase potrebbe essere la scelta ideale per la tua app per iOS.
Questa guida descrive come integrare servizi specifici nella tua app. Per istruzioni di base per la configurazione di Firebase, consulta Configurazione di iOS+ guida.
Google Analytics
Google Analytics è una soluzione di misurazione delle app gratuita che fornisce approfondimenti sull'utilizzo delle app e sul coinvolgimento degli utenti. Analytics si integra con le funzionalità di Firebase e fornisce report illimitati per un massimo di 500 eventi distinti che puoi definire utilizzando l'SDK Firebase.
Per scoprire di più, consulta la documentazione di Google Analytics.
Strategia di migrazione suggerita
L'utilizzo di provider di analisi diversi è uno scenario comune che si applica facilmente Google Analytics. Aggiungilo alla tua app per usufruire degli eventi e delle proprietà utente raccolti automaticamente daAnalytics, ad esempio prima apertura, aggiornamento dell'app, modello di dispositivo, età.
Per gli eventi personalizzati e le proprietà utente, puoi impiegare una strategia di scrittura doppia utilizzando analizzare Analytics e Google Analytics per registrare eventi e proprietà, il che consente di implementare gradualmente la nuova soluzione.
Confronto codice
Analizza 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];
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 è un database ospitato nel cloud NoSQL. I dati vengono archiviati in formato JSON sincronizzati in tempo reale con ogni client connesso.
Per scoprire di più, consulta la documentazione di Firebase Realtime Database.
Differenze con l'analisi dei dati
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
; è sufficiente scrivere nei valori dell'albero JSON dei tipi
ai tipi JSON disponibili.
Di seguito è riportato un esempio di come potresti salvare i punteggi migliori per un gioco.
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
}
}];
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
}
}];
Relazioni tra dati
Un PFObject
può avere una relazione con un altro PFObject
: qualsiasi oggetto può utilizzare altri oggetti come valori.
In Firebase Realtime Database, le relazioni sono espresse meglio utilizzando strutture di dati piatte che suddividono i dati in percorsi distinti, in modo che possano essere scaricati in modo efficiente in chiamate separate.
Di seguito è riportato un esempio di come puoi strutturare la relazione tra i post in una app di blogging e relativi 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];
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]
Il risultato è il seguente layout di 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" } ... } }
Lettura dei dati
In Analizza, leggi i dati utilizzando l'ID di un oggetto Parse specifico oppure
che esegue query utilizzando PFQuery
.
In Firebase, i dati vengono recuperati collegando un ascoltatore asincrono a un riferimento di database. La il listener viene attivato una volta per lo stato iniziale dei dati e di nuovo quando i dati cambiano, In questo modo, non dovrai aggiungere alcun codice per determinare se i dati sono cambiati.
Di seguito è riportato un esempio di come puoi recuperare i punteggi di un determinato giocatore, in base a nell'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]);
}
}];
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);
}];
Strategia di migrazione suggerita
Reinterpreta i tuoi dati
Firebase Realtime Database è ottimizzato per sincronizzare i dati in millisecondi tra tutti i dispositivi connessi e la struttura dei dati risultante è diversa dai dati principali di Parse. Ciò significa che Il primo passaggio della migrazione è valutare quali modifiche sono richieste dai dati, tra cui:
- Come gli oggetti di analisi devono essere mappati ai dati Firebase
- Se hai relazioni genitore-figlio, su come suddividere i dati su percorsi diversi in modo da può essere scaricato in modo efficiente in chiamate separate.
Esegui la migrazione dei 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 in entrambi i database. Le opzioni disponibili sono:
Sincronizzazione in background
In questo scenario, hai due versioni dell'app: quella precedente che utilizza l'analisi e una nuova che utilizza Firebase. Le sincronizzazioni tra i due database sono gestite da Parse Cloud Code (Parse a Firebase), con il codice che ascolta le modifiche su Firebase e le sincronizza con Parse. Prima di poter iniziare a utilizzare la nuova versione, devi:
- Converti i dati di Parse esistenti nella nuova struttura Firebase e scrivili in Firebase Realtime Database.
- Scrivere le funzioni Analizza Cloud Code che utilizzano l'API REST Firebase per scrivere Firebase Realtime Database modifiche apportate in Analizza dati da client precedenti.
- Scrivi ed esegui il deployment del codice che rimane in ascolto delle modifiche su Firebase e le sincronizza con il Parse per configurare un database.
Questo scenario garantisce una separazione netta tra vecchio e nuovo codice e semplifica la gestione dei client. La Le sfide di questo scenario sono la gestione di grandi set di dati nell'esportazione iniziale e la garanzia che la sincronizzazione bidirezionale non genera una ricorsione infinita.
Scrittura doppia
In questo scenario, scriverai una nuova versione dell'app che utilizza sia Firebase che Parse, utilizzando Analizza Cloud Code per sincronizzare le modifiche apportate dai vecchi client dai dati di analisi Firebase Realtime Database. Quando un numero sufficiente di utenti ha eseguito la migrazione dalla versione dell'app solo Parse, puoi rimuovere il codice Parse dalla versione con doppia scrittura.
Questo scenario non richiede codice lato server. I suoi svantaggi sono che i dati che non sono non viene eseguita la migrazione dell'accesso e le dimensioni della tua app vengono aumentate dall'uso di entrambi gli SDK.
Firebase Authentication
Firebase Authentication può autenticare gli utenti utilizzando password e noti provider di identità federati come Google, Facebook e Twitter. Fornisce inoltre librerie UI per consentirti di risparmiare l'investimento necessario per implementare e mantenere un'esperienza di autenticazione completa per la tua app su su tutte le piattaforme.
Per scoprire di più, consulta la documentazione di Firebase Authentication.
Differenze rispetto all'autenticazione di analisi
Parse fornisce una classe utente specializzata chiamata PFUser
che gestisce automaticamente la funzionalità richiesta per la gestione degli account utente. PFUser
è una sottoclasse del
PFObject
, il che significa che i dati utente sono disponibili nell'analisi dei dati 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 email principale
un nome e l'URL di una foto, memorizzati in un database utente separato di un progetto possono essere aggiornate
per l'utente. Non puoi aggiungere altre proprietà direttamente all'oggetto FIRUser
, ma puoi archiviarle in Firebase Realtime Database.
Di seguito è riportato un esempio di come puoi registrare un utente e aggiungere un ulteriore campo per il numero di telefono.
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"];
}
}];
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"];
}
}];
Strategia di migrazione suggerita
Esegui la migrazione degli account
Per eseguire la migrazione degli account utente da Parse a Firebase, esporta il database utenti in
un file JSON o CSV, quindi importa il file nel progetto Firebase utilizzando
auth:import
dell'interfaccia a riga di comando di Firebase
.
Innanzitutto, esporta il database utente dalla console Parse o dal database auto-in hosting. Ad esempio, un file JSON esportato dalla console di analisi potrebbe avere ad esempio:
{ // 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 da Firebase
nell'interfaccia a riga di comando. Utilizza objectId
degli utenti di Parse come
localId
dei tuoi utenti Firebase. Inoltre, in base64 codificano
bcryptPassword
di valori di Analizza e usali nella sezione passwordHash
. Ad 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 l'interfaccia a riga di comando di Firebase, specificando bcrypt come algoritmo hash:
firebase auth:import account_file.json --hash-algo=BCRYPT
Esegui la migrazione dei dati utente
Se stai archiviando dati aggiuntivi per i tuoi utenti, puoi eseguirne la migrazione a Firebase Realtime Database utilizzando le strategie descritte nella sezione sulla migrazione dei dati. Se esegui la migrazione degli account utilizzando il flusso descritto nella sezione Migrazione degli account, i tuoi account Firebase avranno gli stessi ID dei tuoi account Parse, il che ti consente di eseguire facilmente la migrazione e riprodurre qualsiasi relazione basata sull'ID utente.
Firebase Cloud Messaging
Firebase Cloud Messaging (FCM) è una soluzione di messaggistica multipiattaforma che ti consente di per consegnare messaggi e notifiche senza costi. Notifications Composer è un servizio senza costi su Firebase Cloud Messaging che attiva le notifiche utente target per gli sviluppatori di app mobile.
Per scoprire di più, consulta la documentazione di Firebase Cloud Messaging.
Differenze rispetto alle notifiche push di analisi
A ogni applicazione Parse installata su un dispositivo registrato per le notifiche è associata un'etichetta
Installation
, in cui archivi tutti i dati necessari per indirizzare le notifiche.
Installation
è una sottoclasse di PFUser
, il che significa che puoi aggiungere
eventuali dati aggiuntivi da trasferire alle istanze Installation
.
Il generatore di notifiche fornisce segmenti di utenti predefiniti in base a informazioni quali app, versione dell'app e lingua del dispositivo. Puoi creare segmenti utenti più complessi utilizzando gli eventi e le proprietà Google Analytics per creare segmenti di pubblico. Visualizza i segmenti di pubblico guida di assistenza per saperne di più. Queste informazioni sul targeting non sono visibili in Firebase Realtime Database.
Strategia di migrazione suggerita
Migrazione dei token dispositivo
Anche se il comando Parse utilizza i token del dispositivo degli APN per scegliere come target le installazioni per le notifiche, FCM utilizza FCM token di registrazione mappato ai token del dispositivo degli APN. Devi solo aggiungere FCM SDK alla tua app Apple e recupererà automaticamente un token FCM.
Migrazione dei canali agli FCM Argomenti
Se usi Analizza canali per inviare notifiche, puoi eseguire la migrazione agli argomenti FCM, che forniscono lo stesso modello publisher-iscritto. Per gestire la transizione da Analizza a FCM, puoi scrivere una nuova versione dell'app che utilizza l'SDK Parse per annullare l'iscrizione ai canali Parse e l'SDK FCM per l'iscrizione FCM argomenti corrispondenti.
Ad esempio, se un utente è abbonato ai "Giants" argomento, ad esempio:
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
}
}];
Utilizzando questa strategia, puoi inviare messaggi sia al canale di analisi che al canale FCM, che supporta gli utenti di versioni precedenti e nuove. Quando un numero sufficiente di utenti ha eseguito la migrazione Versione di sola analisi dell'app, puoi annullarla e iniziare a inviarla utilizzando solo FCM.
Consulta le FCM documenti relativi agli argomenti per saperne di più.
Firebase Remote Config
Firebase Remote Config è un servizio cloud che ti consente di modificare il comportamento e l'aspetto del tuo senza richiedere agli utenti di scaricare un aggiornamento. Quando usi Remote Config, crei immagini in-app valori predefiniti che controllano il comportamento e l'aspetto della tua app. Successivamente, potrai utilizzare Console Firebase per eseguire l'override dei valori predefiniti in-app per tutti gli utenti dell'app o per segmenti della tua base utenti.
Firebase Remote Config può essere molto utile durante le migrazioni se vuoi testare diverse soluzioni ed essere in grado di spostare dinamicamente più clienti su un altro provider. Ad esempio: Se disponi di una versione dell'app che utilizza sia Firebase che Parse per i dati, puoi utilizzare una con una regola di percentile casuale per determinare quali clienti leggono da Firebase e aumentare gradualmente la percentuale.
Per scoprire di più su Firebase Remote Config, consulta le Introduzione a Remote Config.
Differenze con l'analisi della configurazione
Con Parse Config puoi aggiungere coppie chiave/valore alla tua app nella dashboard Analizza configurazione, quindi
Recupera PFConfig
sul client. Ogni PFConfig
istanza che
get è sempre immutabile. Quando in futuro recupererai un nuovo PFConfig
dalla rete, non verrà modificata alcuna istanza PFConfig
esistente, ma ne verrà creata una nuova e resa disponibile tramite currentConfig
.
Con Firebase Remote Config crei valori predefiniti in-app per coppie chiave/valore che puoi sostituire dalla console Firebase e puoi utilizzare regole e condizioni per fornire varianti dell'app l'esperienza utente ai diversi segmenti della base utenti. Firebase Remote Config implementa un singleton che rende le coppie chiave/valore disponibili per la tua app. Inizialmente il singleton torna i valori predefiniti da te definiti in-app. Puoi recuperare un nuovo insieme di valori dal server in qualsiasi momento conveniente per la tua app; Dopo che il nuovo set è stato recuperato, puoi scegliere quando attivarlo per rendere i nuovi valori disponibili per l'app.
Strategia di migrazione suggerita
Puoi passare a Firebase Remote Config copiando le coppie chiave/valore della configurazione di analisi alla console Firebase per poi eseguire il deployment di una nuova versione dell'app che usa Firebase Remote Config.
Se vuoi fare esperimenti sia con Parse Config sia con Firebase Remote Config, puoi eseguire il deployment di una nuova versione dell'app che utilizzi entrambi gli SDK finché un numero sufficiente di utenti non avrà eseguito la migrazione dalla versione solo Parse.
Confronto codice
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!";
}
}];
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;