Nella lezione precedente, abbiamo integrato la SDK e il servizio di autenticazione di Firebase all'interno di un nuovo progetto Android. In questa lezione, vedremo come integrare il social login tramite Facebook utilizzando Firebase nella nostra applicazione.
I passi da compiere sono molto simili a quelli illustrati nella lezione 6, a differenza dell'implementazione dei metodi di login e logout.
Modifica del build.gradle del modulo app
Apriamo il build.gradle del Module:app e nelle dipendenze dell'applicazione aggiungiamo la dipendenza sulla versione più recente dell'SDK di Facebook come segue:
dependencies {
. . .
//Facebook SDK for login
implementation 'com.facebook.android:facebook-login:[4,5)'
}
Sincronizziamo il gradle cliccando sul Sync Now che comparirà in alto a destra dopo aver aggiunto la dipendenza.
Modifica delle risorse e dell'AndroidManifest
Apriamo adesso il file strings.xml e aggiungiamo l'id dell'app e lo schema del protocollo di login di Facebook come segue:
<resources>
. . .
<string name="facebook_app_id">118446748837203</string>
<string name="fb_login_protocol_scheme">fb118446748837203</string>
</resources>
Chiudiamo il file e apriamo l'AndroidManifest.xml per andare ad aggiungere all'interno del tag application
e subito dopo la dichiarazione della LoginActivity
:
- i metadati per Facebook per mappare l'ID dell'applicativo con una stringa identificativa;
- la
FacebookActivity
necessaria per una corretta gestione della SDK; - la
CustomTabActivity
per mostrare una View simile ad un tab di Chrome in cui visualizzare la schermata di login di Facebook qualora l'app nativa non fosse installata sul dispositivo.
Di seguito si riporta il codice da aggiungere.
<meta-data android:name="com.facebook.sdk.ApplicationId"
android:value="@string/facebook_app_id"/>
<activity android:name="com.facebook.FacebookActivity"
android:configChanges=
"keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:label="@string/app_name" />
<activity
android:name="com.facebook.CustomTabActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="@string/fb_login_protocol_scheme" />
</intent-filter>
</activity>
Modifica del layout
Passiamo adesso alla modifica del layout per aggiungere il bottone che permetterà all'utente di effettuare il login. Per farlo, apriamo il file activity_login.xml che si trova in src/main/res/layout, e inseriamo all'interno del ConstaintLayout
il codice seguente:
<com.facebook.login.widget.LoginButton
android:id="@+id/fb_login_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
In questo modo abbiamo aggiunto il bottone rilasciato di default con la Facebook SDK, centrandolo al centro del parent. È importante ricordare che una volta effettuato il login, al posto del bottone verrà visualizzato il LinearLayout
definito nella lezione 15.
Modifica della LoginActivity
All'interno dell'Activity dovremo compiere diverse operazioni, che si riassumono nei seguenti passi:
- implementare l'interfaccia
OnClickListener
; - inizializzare l'autenticazione tramite Firebase e Facebook;
- gestire l'access token tramite Firebase;
- aggiornare l'interfaccia in base all'esito dell'autenticazione;
- definire il metodo di logout.
Iniziamo con l'instanziare il bottone di login widget che utilizzeremo nella nostra Activity
.
private LoginButton mLoginButton;
. . .
@Override
protected void onCreate(Bundle savedInstanceState) {
. . .
findViewById(R.id.bt_log_out).setOnClickListener(this);
}
. . .
Inizializziamo all'interno dell'OnCreate
la FirebaseAuth
e il CallbackManager
per la gestione della risposta a seguito del login, avvenuto con successo o meno. Per farlo definiamo le variabili:
private FirebaseAuth mFirebaseAuth;
private CallbackManager mCallbackManager;
e nel metodo onCreate
:
protected void onCreate(Bundle savedInstanceState) {
. . .
mFirebaseAuth = FirebaseAuth.getInstance();
mCallbackManager = CallbackManager.Factory.create();
mLoginButton = findViewById(R.id.fb_login_button);
mLoginButton.setReadPermissions("email", "public_profile");
mLoginButton.registerCallback(mCallbackManager, new FacebookCallback<LoginResult>() {
@Override
public void onSuccess(LoginResult loginResult) {
mLoginButton.setVisibility(View.GONE);
handleAccessToken(loginResult.getAccessToken());
}
@Override
public void onCancel() {
updateUI(null);
}
@Override
public void onError(FacebookException error) {
updateUI(null);
}
});
}
In questo modo abbiamo:
- ottenuto un'istanza di
FirebaseAuth
; - inizializzato la
Callback
della SDK di Facebook per la gestione del login; - recuperato il riferimento al bottone di login e impostato il permesso di lettura attraverso il metodo
setReadPermission()
, passando come parametro il valore email epublic_profile
; - registrato il nostro oggetto
callbackManager
con il bottone di autenticazione attraverso il metodoregisterCallback
; - gestito l'interfaccia utente in base all'esito del login. In particolare, in caso di successo verrà nascosto il bottone di login e richiamato il metodo
handleAccessToken
, che prende in input l'access token ottenuto tramite il processo di autenticazione. Negli altri casi verrà richiamato il metodo per l'aggiornamento dell'interfaccia.
Per completare l'integrazione del login, aggiungiamo la definizione del metodo onActivityResult
che inoltra al callbackManager
il risultato del login.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
mCallbackManager.onActivityResult(requestCode, resultCode, data);
}
Implementiamo ora i metodi handleAccessToken
e updateUI
per gestire l’access token restituito da Facebook durante il processo di login e aggiornare l’interfaccia utente in base all’esito del login.
Il handleAccessToken
deve essere implementato come segue.
private void handleAccessToken(AccessToken accessToken) {
showProgressDialog();
AuthCredential credential = FacebookAuthProvider.getCredential(accessToken.getToken());
mFirebaseAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
FirebaseUser user = mFirebaseAuth.getCurrentUser();
updateUI(user);
} else {
Toast.makeText(LoginActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
updateUI(null);
}
}
});
}
All’interno del metodo, si è:
- richiamato il metodo che mostra la
ProgressDialog
; - ottenuto le credenziali attraverso il metodo statico
getCredential
dell’oggettoFacebookAuthProvider
, che prende in input l’access token ottenuto durante l’autenticazione e restituisce un oggettoAuthCredential
che contiene al suo interno le informazioni del token fornito da Facebook; - tentato l’accesso a Facebook tramite il metodo
signInWithCredential
passando in input le credenziali appena recuperate restituendo un oggettoTask<AuthResult>
; - aggiunto un listener al task che viene richiamato quando il task sarà terminato.
In particolare, quando il task sarà terminato, in caso di successo verranno recuperate le informazioni dell’utente e aggiornata l’interfaccia tramite il metodo updateUI
. Contrariamente verrà mostrato un messaggio di errore e sarà ripristinata l’interfaccia iniziale.
Implementiamo ora il metodo updateUI
, che non farà altro che nascondere la ProgressDialog
, e in caso di successo aggiornerà l’interfaccia nascondendo il bottone di login e rendendo visibile il LinearLayout
con le informazioni dell’utente. In caso contrario, verrà mostrato solo il bottone di login nascondendo nuovamente il layout con le informazioni sull’utente. Si riporta per completezza l’implementazione del metodo:
private void updateUI(FirebaseUser user) {
hideProgressDialog();
if (user != null) {
mUserInfoLayout.setVisibility(View.VISIBLE);
mUserNameTV.setText(user.getDisplayName());
String userId = "";
for(UserInfo profile : user.getProviderData()){
if(FacebookAuthProvider.PROVIDER_ID.equals(profile.getProviderId())) {
userId = profile.getUid();
}
}
String imageUrl = "https://graph.facebook.com/" + userId + "/picture?type=large";
Picasso.with(this)
.load(imageUrl)
.placeholder(R.drawable.placeholder)
.into(mUserImageIV);
} else {
mLoginButton.setVisibility(View.VISIBLE);
mUserInfoLayout.setVisibility(View.GONE);
}
}
In particolare, per popolare il layout con le informazioni dell’utente è possibile utilizzare l’oggetto FirebaseUser
da cui è possibile estrarre le informazioni di interesse circa l’utente, come il nome e l’immagine di profilo. L’URL dell’immagine di profilo può essere ottenuta tramite il metodo getPhotoUrl().toString()
dell’oggetto, ma questa soluzione limita la dimensione dell’immagine alla dimensione small offerta dalle API di Facebook. Questa limitazione è facilmente superabile usando le graph API di Facebook e sfruttando lo user identifier come riportato nel codice.
L’URL dell’immagine di profilo così ottenuta sarà quindi consumata dalla libreria Picasso che caricherà l’immagine.
Infine, definiamo il metodo di logout come segue.
public void signOut() {
mFirebaseAuth.signOut();
LoginManager.getInstance().logOut();
updateUI(null);
}
Risultato finale
Eseguiamo l’applicazione sul dispositivo mobile o sull’emulatore.
All’avvio dell’applicazione, viene mostrata la schermata iniziale contenente il bottone di default precedentemente aggiunto all’interfaccia e qui di seguito riportato.
Cliccando sul bottone verrà richiesto all’utente di autenticarsi con il proprio account Facebook, chiedendo allo stesso l’autorizzazione per l’accesso ai dati personali da parte dell’applicazione.
Figura 85. Schermata di a) autenticazione di Facebook, b) autorizzazione per l’accesso ai dati (click per ingrandire)
Una volta loggati, verremo nuovamente reindirizzati alla schermata della LoginActivity
ma, al posto del bottone di login, verranno mostrate le informazioni dell’utente e il bottone di logout.
Figura 86. LoginActivity con le informazioni dell’utente e il bottone di logout (click per ingrandire)
Cliccando sul bottone di logout verrà effettuato il logout da Facebook e l’applicazione mostrerà nuovamente il bottone di login.