Esegui la migrazione dell'app Parse Android a Firebase

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 Android.

Questa guida descrive come integrare servizi specifici nella tua app. Per istruzioni per la configurazione di base di Firebase, consulta la configurazione di Android 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 nelle funzionalità di Firebase e ti offre un numero per un massimo di 500 eventi distinti che puoi definire con 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. Aggiungila alla tua app per usufruire di eventi e proprietà utente che Analytics raccoglie automaticamente i dati, ad esempio prima apertura, aggiornamento dell'app, modello del 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
ParseAnalytics.trackAppOpenedInBackground(getIntent());

Map<String, String> dimensions = new HashMap<String, String>();
// Define ranges to bucket data points into meaningful segments
dimensions.put("priceRange", "1000-1500");
// Did the user filter the query?
dimensions.put("source", "craigslist");
// Do searches happen more often on weekdays or weekends?
dimensions.put("dayType", "weekday");

// Send the dimensions to Parse along with the 'search' event
ParseAnalytics.trackEvent("search", dimensions);

Google Analytics

// Obtain the FirebaseAnalytics instance and start collecting data
mFirebaseAnalytics = FirebaseAnalytics.getInstance(this);

Bundle params = new Bundle();
// Define ranges to bucket data points into meaningful segments
params.putString("priceRange", "1000-1500");
// Did the user filter the query?
params.putString("source", "craigslist");
// Do searches happen more often on weekdays or weekends?
params.putString("dayType", "weekday");

// Send the event
mFirebaseAnalytics.logEvent("search", params);

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 ParseObject, 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 esiste su ogni ParseObject.

Tutti i dati di Firebase Realtime Database vengono archiviati come oggetti JSON e non esiste un equivalente per ParseObject; è sufficiente scrivere nei valori dell'albero JSON dei tipi ai tipi JSON disponibili. Puoi utilizzare gli oggetti Java per semplificare la lettura e la scrittura dal per configurare un database.

Di seguito è riportato un esempio di come salvare i migliori punteggi di un gioco.

Analizza
@ParseClassName("GameScore")
public class GameScore {
        public GameScore() {}
        public GameScore(Long score, String playerName, Boolean cheatMode) {
            setScore(score);
            setPlayerName(playerName);
            setCheatMode(cheatMode);
        }

        public void setScore(Long score) {
            set("score", score);
        }

        public Long getScore() {
            return getLong("score");
        }

        public void setPlayerName(String playerName) {
            set("playerName", playerName);
        }

        public String getPlayerName() {
            return getString("playerName");
        }

        public void setCheatMode(Boolean cheatMode) {
            return set("cheatMode", cheatMode);
        }

        public Boolean getCheatMode() {
            return getBoolean("cheatMode");
        }
}

// Must call Parse.registerSubclass(GameScore.class) in Application.onCreate
GameScore gameScore = new GameScore(1337, "Sean Plott", false);
gameScore.saveInBackground();
Firebase
// Assuming we defined the GameScore class as:
public class GameScore {
        private Long score;
        private String playerName;
        private Boolean cheatMode;

        public GameScore() {}
        public GameScore(Long score, String playerName, Boolean cheatMode) {
            this.score = score;
            this.playerName = playerName;
            this.cheatMode = cheatMode;
        }

        public Long getScore() {
            return score;
        }

        public String getPlayerName() {
            return playerName;
        }

        public Boolean getCheatMode() {
            return cheatMode;
        }
}

// We would save it to our list of high scores as follows:
DatabaseReference mFirebaseRef = FirebaseDatabase.getInstance().getReference();
GameScore score = new GameScore(1337, "Sean Plott", false);
mFirebaseRef.child("scores").push().setValue(score);
Per ulteriori dettagli, consulta Guida alla lettura e scrittura di dati su Android.

Relazioni tra dati

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

In Firebase Realtime Database, le relazioni vengono espresse meglio mediante strutture di dati piatte che suddividono i dati in percorsi separati, in modo da poterli scaricare 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
ParseObject myAuthor = new ParseObject("Author");
myAuthor.put("name", "Grace Hopper");
myAuthor.put("birthDate", "December 9, 1906");
myAuthor.put("nickname", "Amazing Grace");

// Create the post
ParseObject myPost = new ParseObject("Post");
myPost.put("title", "Announcing COBOL, a New Programming Language");

// Add a relation between the Post and the Author
myPost.put("parent", myAuthor);

// This will save both myAuthor and myPost
myPost.saveInBackground();
Firebase
DatabaseReference firebaseRef = FirebaseDatabase.getInstance().getReference();
// Create the author
Map<String, String> myAuthor = new HashMap<String, String>();
myAuthor.put("name", "Grace Hopper");
myAuthor.put("birthDate", "December 9, 1906");
myAuthor.put("nickname", "Amazing Grace");

// Save the author
String myAuthorKey = "ghopper";
firebaseRef.child('authors').child(myAuthorKey).setValue(myAuthor);

// Create the post
Map<String, String> post = new HashMap<String, String>();
post.put("author", myAuthorKey);
post.put("title", "Announcing COBOL, a New Programming Language");
firebaseRef.child('posts').push().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"
    }
    ...
  }
}
Per ulteriori dettagli, consulta Struttura il database guida.

Lettura dei dati

In Analizza, leggi i dati utilizzando l'ID di un oggetto Parse specifico oppure che esegue query utilizzando ParseQuery.

In Firebase, puoi recuperare i dati collegando un listener 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 recuperare i punteggi di un determinato giocatore, in base all'esempio presentato nella sezione "Objects".

Analizza
ParseQuery<ParseObject> query = ParseQuery.getQuery("GameScore");
query.whereEqualTo("playerName", "Dan Stemkoski");
query.findInBackground(new FindCallback<ParseObject>() {
    public void done(List<ParseObject> scoreList, ParseException e) {
        if (e == null) {
            for (ParseObject score: scoreList) {
                Log.d("score", "Retrieved: " + Long.toString(score.getLong("score")));
            }
        } else {
            Log.d("score", "Error: " + e.getMessage());
        }
    }
});
Firebase
DatabaseReference mFirebaseRef = FirebaseDatabase.getInstance().getReference();
Query mQueryRef = mFirebaseRef.child("scores").orderByChild("playerName").equalTo("Dan Stemkoski");

// This type of listener is not one time, and you need to cancel it to stop
// receiving updates.
mQueryRef.addChildEventListener(new ChildEventListener() {
    @Override
    public void onChildAdded(DataSnapshot snapshot, String previousChild) {
        // This will fire for each matching child node.
        GameScore score = snapshot.getValue(GameScore.class);
        Log.d("score", "Retrieved: " + Long.toString(score.getScore());
    }
});
Per maggiori dettagli sui tipi di listener di eventi disponibili e su come ordinare e filtrare i dati, controlla Lettura e scrittura di dati su Android guida.

Strategia di migrazione suggerita

Riconsidera 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 periodo durante il quale l'app deve scrivere su entrambi i database. Le opzioni disponibili sono:

Sincronizzazione in background

In questo scenario, hai due versioni dell'app: la vecchia versione che utilizza Parse e una nuova versione che utilizza Firebase. Le sincronizzazioni tra i due database sono gestite dal Parse Cloud Code (analisi a Firebase), il codice rimane in ascolto delle modifiche su Firebase e le sincronizza con Analizza. Prima di poter iniziare a utilizzare la nuova versione, devi:

  • Converti i dati di analisi esistenti nella nuova struttura Firebase e scrivili nel 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 alcun 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 provider di identità federati diffusi come Google, Facebook e Twitter. Fornisce inoltre librerie UI per farti risparmiare sull'investimento significativo necessario per implementare e gestire un'esperienza di autenticazione completa per la tua app su tutte le piattaforme.

Per scoprire di più, consulta la documentazione di Firebase Authentication.

Differenze rispetto all'autenticazione di analisi

L'analisi fornisce una classe utente specializzata denominata ParseUser che gestisce automaticamente la funzionalità richiesta per la gestione degli account utente. ParseUser è una sottoclasse di ParseObject, il che significa che i dati utente sono disponibili in Analizza dati e possono essere estesi con campi aggiuntivi come qualsiasi altro ParseObject.

Un FirebaseUser 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 FirebaseUser, 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
ParseUser user = new ParseUser();
user.setUsername("my name");
user.setPassword("my pass");
user.setEmail("email@example.com");

// other fields can be set just like with ParseObject
user.put("phone", "650-253-0000");

user.signUpInBackground(new SignUpCallback() {
    public void done(ParseException e) {
        if (e == null) {
            // Hooray! Let them use the app now.
        } else {
            // Sign up didn't succeed. Look at the ParseException
            // to figure out what went wrong
        }
    }
});
Firebase
FirebaseAuth mAuth = FirebaseAuth.getInstance();

mAuth.createUserWithEmailAndPassword("email@example.com", "my pass")
    .continueWithTask(new Continuation<AuthResult, Task<Void>> {
        @Override
        public Task<Void> then(Task<AuthResult> task) {
            if (task.isSuccessful()) {
                FirebaseUser user = task.getResult().getUser();
                DatabaseReference firebaseRef = FirebaseDatabase.getInstance().getReference();
                return firebaseRef.child("users").child(user.getUid()).child("phone").setValue("650-253-0000");
            } else {
                // User creation didn't succeed. Look at the task exception
                // to figure out what went wrong
                Log.w(TAG, "signInWithEmail", task.getException());
            }
        }
    });

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 .

Per prima cosa, esporta il database utenti dalla console di analisi o per configurare un database. 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 utilizzando il flusso descritto nella sezione Migrazione degli account, Gli account Firebase hanno gli stessi ID degli account Parse, il che ti consente di eseguire facilmente la migrazione e la riproduzione qualsiasi relazione definita dall'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. Il compositore di notifiche è un servizio senza costi basato su Firebase Cloud Messaging che consente notifiche agli utenti 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 ParseUser, il che significa che puoi aggiungere eventuali dati aggiuntivi da trasferire alle istanze Installation.

Il compositore di notifiche fornisce segmenti utente predefiniti basati su informazioni quali l'app, la versione dell'app e il dispositivo lingua. 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 del dispositivo

Al momento della stesura di questo documento, l'SDK Parse Android utilizza una versione precedente di FCM di registrazione non compatibili con le funzionalità offerte da Notifications Composer.

Puoi ricevere un nuovo token aggiungendo l'SDK FCM alla tua app. ma Ciò potrebbe invalidare il token utilizzato dall'SDK Parse per ricevere le notifiche. Per evitare questo problema, puoi configurare l'SDK Parse in modo da utilizzare sia l'ID mittente di Parse sia il tuo ID mittente. In questo modo non invalidi il token utilizzato dall'SDK Parse, ma tieni presente che questa soluzione alternativa smetterà di funzionare quando Parse chiude il suo progetto.

Migrazione dei canali a FCM argomento

Se usi l'analisi dei canali per inviare notifiche, puoi eseguire la migrazione agli argomenti FCM, che forniscono lo stesso modello publisher-iscritto. Per gestire la transizione da Analisi 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 relativi agli argomenti FCM corrispondenti. In questa versione dell'app dovresti disattivare la ricezione delle notifiche su l'SDK Parse, rimuovendo quanto segue dal file manifest dell'app:

<service android:name="com.parse.PushService" />
<receiver android:name="com.parse.ParsePushBroadcastReceiver"
  android:exported="false">
<intent-filter>
<action android:name="com.parse.push.intent.RECEIVE" />
<action android:name="com.parse.push.intent.DELETE" />
<action android:name="com.parse.push.intent.OPEN" />
</intent-filter>
</receiver>
<receiver android:name="com.parse.GcmBroadcastReceiver"
  android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />

<!--
IMPORTANT: Change "com.parse.starter" to match your app's package name.
-->
<category android:name="com.parse.starter" />
</intent-filter>
</receiver>

<!--
IMPORTANT: Change "YOUR_SENDER_ID" to your GCM Sender Id.
-->
<meta-data android:name="com.parse.push.gcm_sender_id"
  android:value="id:YOUR_SENDER_ID" />;

Ad esempio, se un utente è abbonato ai "Giants" argomento, ad esempio:

ParsePush.unsubscribeInBackground("Giants", new SaveCallback() {
    @Override
    public void done(ParseException e) {
        if (e == null) {
            FirebaseMessaging.getInstance().subscribeToTopic("Giants");
        } else {
            // Something went wrong unsubscribing
        }
    }
});

Con questa strategia, puoi inviare messaggi sia al canale Parse sia all'argomento corrispondenteFCM, supportando gli utenti sia della versione precedente sia di quella nuova. 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 di Parse Config, quindi recuperare ParseConfig sul client. Ogni istanza ParseConfig che ricevi è sempre immutabile. Quando in futuro recupererai un nuovo ParseConfig dalla rete, non verrà modificata alcuna istanza ParseConfig esistente, ma ne verrà creata una nuova e resa disponibile tramite getCurrentConfig().

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 sperimentare sia con Parse Config che Firebase Remote Config, puoi eseguire il deployment Una nuova versione dell'app che utilizza entrambi gli SDK finché non è stata eseguita la migrazione di un numero sufficiente di utenti dalla versione di sola analisi.

Confronto codice

Analizza

ParseConfig.getInBackground(new ConfigCallback() {
    @Override
    public void done(ParseConfig config, ParseException e) {
        if (e == null) {
            Log.d("TAG", "Yay! Config was fetched from the server.");
        } else {
            Log.e("TAG", "Failed to fetch. Using Cached Config.");
            config = ParseConfig.getCurrentConfig();
        }

        // Get the message from config or fallback to default value
        String welcomeMessage = config.getString("welcomeMessage", "Welcome!");
    }
});

Firebase

mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
// Set defaults from an XML resource file stored in res/xml
mFirebaseRemoteConfig.setDefaults(R.xml.remote_config_defaults);

mFirebaseRemoteConfig.fetch()
    .addOnSuccessListener(new OnSuccessListener<Void>() {
        @Override
        public void onSuccess(Void aVoid) {
            Log.d("TAG", "Yay! Config was fetched from the server.");
            // Once the config is successfully fetched it must be activated before newly fetched
            // values are returned.
            mFirebaseRemoteConfig.activateFetched();
        }
    })
    .addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception exception) {
            Log.e("TAG", "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.
String welcomeMessage = mFirebaseRemoteConfig.getString("welcomeMessage");