DevCorner: effettuiamo il login con Facebook e postiamo sulla bacheca

Giuseppe Tripodi
Giuseppe Tripodi Tech Master
DevCorner: effettuiamo il login con Facebook e postiamo sulla bacheca

L’estate è agli sgoccioli: dopo mesi subiti a guardare foto in spiaggia sul noto social network blu, chissà che non vi sia venuta in mente qualche idea geniale per sfruttare il portale di Mark Zuckerberg in maniera migliore? Se la risposta è sì,o se semplicemente vi incuriosisce sapere come si fa ad implementare l’SDK di Facebook nella vostra applicazione per effettuare il login e pubblicare qualcosa sulla bacheca, continuate a leggere il tutorial di questa settimana.

L’intera procedura può sembrare complessa (specialmente seguendo il Getting Started di Facebook, a cui ci rifaremo) ma in realtà è solo un po’ lenta e macchinosa: per questo motivo non ci perdiamo in ulteriori chiacchiere e vediamo subito cosa fare.

Il primo step è scaricare l’SDK: rechiamoci quindi a questo indirizzo e, una volta effettuato il download estraiamo il contenuto dell’archivio in una cartella a nostra scelta. Adesso è il momento di importare l’SDK come libreria su Eclipse:

Facebook SDk - Import

clicchiamo quindi File, Import, Existing Android code into Workspace: nella finestra che ci appare clicchiamo su Browse e scegliamo la cartella dove abbiamo posizionato il contenuto dello zip: automaticamente appariranno sotto Project to import tutti i possibili progetti da importare, scegliamo quello chiamato semplicemente facebook (che sarà preselezionato) e clicchiamo Finish per terminare la procedura.

Facebook SDK - Selezione progetto

Se tutto andrà bene, vi ritroverete con un nuovo progetto chiamato FacebookSDK che andremo ad integrare nella nostra app.

Visto che ormai abbiamo aperto Eclipse, creiamo al volo una nuova app (noi l’abbiamo chiamata FaceApp) che per il momento non andremo a toccare. Tuttavia, prima di passare ad altro, clicchiamo col tasto destro sul nostro progetto, scegliamo Properties e successivamente andiamo sulla voce Android: come potrete notare, in basso c’è la voce per aggiungere delle librerie: clicchiamo quindi su Add e scegliamo FacebookSDK dall’elenco (se è la prima volta che utilizzate librerie esterne, ovviamente, sarà l’unica voce disponibile).

Facebook SDK - selezione libreria

Fatto questo, è il momento di creare la vera e propria Facebook App con la quale si interfaccerà il nostro software per Android: rechiamoci quindi sulla Dashboard App e scegliamo Create new app: nella schermata che vi si è aperta, dovrete inserire l’App Name e scegliere la Category.

Facebook - creazione nuova app

Il Namespace non è necessario per questo nostro primo tutorial e lo stesso vale per il Web Hosting; tenete presente, tuttavia, che Facebook è piuttosto schizzinoso con i nomi delle App: non accetta, infatti, niente che contenga la parola Facebook, Face, la sigla FB etc.

Per questo motivo, visto che ci sentiamo tanto intelligenti, simpatici e poliglotti, abbiamo chiamato la nostra app Faccialibro (e no, cari i miei presuntuoselli, Annuario scolastico non avrebbe suonato allo stesso modo).

Tornando a noi, una volta creata l’App, Facebook imposterà automaticamente il vostro indirizzo email: potete lasciare tutto non selezionato, ricordatevi solo di disattivare la Sandbox Mode se avete intenzione di condividere la vostra applicazione con qualcuno: se abilitata, infatti, questa modalità consentirà solo agli sviluppatori di utilizzare l’app.

Adesso è giunto il momento di abilitare la voce Native Android App e compilare i restanti campi: su Package Name copiate quello che trovate su Eclipse (nel mio caso com.peppeuz.FaceApp), lo stesso vale per il Class Name (com.peppeuz.FaceApp.MainActivity), abilitate il Facebook Login ed iniziate ad entrare nell’ottica di perdere un po’ di tempo.

Facebook - Android native app

Il restante campo, Key Hashes, è infatti quello che solitamente dà più problemi: se l’applicazione sembra funzionare correttamente ma in realtà non riesce a loggare, al 90% sarà un problema di Kay Hash sbagliato.

Si tratta di una chiave univoca che dovete generare dal vostro PC tramite debug.keystore, uno strumento che dovreste trovare all’interno della cartella .android se state utilizzando l’SDK di Android.

Per generare questa simpaticissima chiave dovete digitate in una finestra di terminale quanto segue

keytool -exportcert -alias <RELEASE_KEY_ALIAS> -keystore <RELEASE_KEY_PATH> | openssl sha1 -binary | openssl base64

sostituendo <RELEASE_KEY_ALIAS>  con androiddebugkey e <RELEASE_KEY_PATH> con il percorso dove si trova il vostro file debug.keystore. In ambiente Unix (Mac OS o Linux), solitamente la cartella .android si trova nella home, quindi il comando finale da digitare sarà:

keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64

mentre su Windows, verosimilmente, assomiglierà a qualcosa del genere:

keytool -exportcert -alias androiddebugkey -keystore .C:\Documents and Settings\Administrator.android\debug.keystore | openssl sha1 -binary | openssl base64

se avete digitato tutto correttamente, vi dovrebbe apparire la richiesta di password del keystore: di default è “android” (senza virgolette, ovviamente), inserendola e cliccando invio dovrebbe comparirvi finalmente la tango agognata Key Hash da inserire.

Facebook key hash

NB: mi sono permesso di lasciare la mia attuale chiave in chiaro perché è assolutamente inutile per chiunque non stia operando dalla mia macchina: ribadiamo, infatti, che la key hash dipende strettamente dal PC dal quale è stata generata.

NB 2: Se siete su Windows e non avete Openssl, potete scaricarlo da qui.

NB 3: se doveste avere problemi nel generare la Key Hash, potete provare questo metodo alternativo, suggerito spesso su StackOverflow: copiate il codice che segue nell'OnCreate di una qualsiasi App e dovreste vedervi apparire nel Log il vostro Key Hash.

try {
        PackageInfo info = getPackageManager().getPackageInfo(
                "Your package name", 
                PackageManager.GET_SIGNATURES);
        for (Signature signature : info.signatures) {
            MessageDigest md = MessageDigest.getInstance("SHA");
            md.update(signature.toByteArray());
            Log.d("Your Tag", Base64.encodeToString(md.digest(), Base64.DEFAULT));
            }
    } catch (NameNotFoundException e) {

    } catch (NoSuchAlgorithmException e) {

    }

Se, comunque, tutto è andato bene, alla fine in un modo o nell'altro vi ritroverete ad aver finito di configurare la "parte server" della vostra Facebook App: quello che vi serve adesso, è che vi appuntiate l'App ID della vostra applicazione, che potete trovare in alto nella schermata di configurazione.

Torniamo adesso finalmente ad Eclipse, per preparare la nostra App a funzionare con Facebook: attenzione ad eseguire molto bene questi passaggi, perché l'interfacciarsi del nostro software con il social network blu dipende da questi step.
Per prima cosa apriamo il file strings.xml(che ricordiamo si trova all'interno della cartella res/values): aggiungiamo una nuova stringa ed assegnamole come nome app_id (scritto esattamente così) e come valore il codice numerico copiato da Facebook.

Facebook - app_id

Proseguiamo recandoci sull'AndroidManifest.xml ed in particolar sul tab Permissions: scegliamo Add, Uses Permissions ed aggiungiamo il permesso per usare Internet, ossia android.permission.INTERNET

Facebook Permissions Internet

Sempre rimanendo nel Manifest, spostiamoci sul tab Application: clicchiamo su Add e scegliamo MetaData: assegnamo come nome com.facebook.sdk.ApplicationId e come value @string/app_id (andrà, quindi, a richiamare il nostro App ID che abbiamo incollato precedentemente).

Facebook - Metadata

Infine, sempre dalla stessa schermata, clicchiamo nuovamente Add e questa volta aggiungiamo una nuova Activity che avrà come nome com.facebook.LoginActivity.

Facebook - Facebook Login Activity

Abbiamo finalmente terminato le configurazioni per far funzionare la nostra app con facebook: se avete eseguito tutti i passi correttamente, alla fine il vostro AndroidManifest.xml dovrebbe essere più o meno così.




    

    

    
        
            
                

                
            

         
        
        
           
    

Possiamo adesso finalmente passare al (poco) codice che ci rimane da scrivere per vedere come eseguire il Login e come postare sulla nostra bacheca. La prima cosa da fare, come sempre, è definire l'interfaccia grafica. Qui metteremo una TextView sulla quale verrà riportato il nostro nome una volta loggati, il tasto proprietario di Facebook per effettuare il Login/Logout e in basso un bottone per postare tramite l'app.

Prima di scrivere il codice xml, però, parliamo un attimo del tasto di Facebook: si tratta di una tipologia particolare di bottone, inclusa nell'SDK di Facebook, che gestisce da sé i metodi per il Login e Logout. Non ci sarà quindi bisogno di gestire alcun click su di esso, l'unica cosa che dovremo fare (come vedremo in seguito), è gestire l'OnClickResault.

L'aspetto dell'XML della nostra MainActivity, quindi, sarà più o meno così:



    

    

    


Passiamo adesso al codice che dovremo scrivere sul nostro MainActicvity.java. Per prima cosa, definiamo tutti gli elementi che ci saranno necessari (la Textview, il bottone per postare, il Context e un valore booleano che useremo per controllare se l'utente è effettivamente collegato), implementiamo l'OnClickListener ed assegniamo un Listener al tasto Post:

public class MainActivity extends Activity implements OnClickListener{
	//
	Button post;
	Context ctx;
	TextView nome;
	Boolean logged;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		nome = (TextView) findViewById(R.id.nome);
		post = (Button) findViewById(R.id.post);
		post.setOnClickListener(this);
		ctx =this;
		logged = false;
	}

Fatto questo, dobbiamo gestire l'OnActivityResult: si tratta di un metodo che "riceve" gli input lanciati da altre Activity, come in questo caso quella del Login di Facebook che è inclusa nell'SDK. Tramite l'OnActivityResult siamo in grado di gestire quel che avverrà quando l'utente sarà effettivamente collegato.

	 @Override
	  public void onActivityResult(int requestCode, int resultCode, Intent data) {
	      super.onActivityResult(requestCode, resultCode, data);
	      Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
	      facebookLogin();
	  }

Come potrete notare, alla fine abbiamo richiamato un metodo di nome facebookLogin() che, però, non abbiamo ancora scritto. Rimediamo subito a questo problema: questo nostro metodo si occupa, una volta aperta la sessione con Facebook, di ottenere il nome dell'utente e scriverlo nella nostra TextView (qui tutte le altre informazioni che potete ottenere dopo il login); inoltre, imposta il valore loggato a true. Tuttavia, se non dovesse riuscirci (nel caso in cui, quindi, ottenga un utente null), riscrive il nostro "Ciao Anonimo!" e reimposta il booleano loggato a false.

public void facebookLogin(){

	    Session.openActiveSession(this, true, new Session.StatusCallback() {

	      @Override
	      public void call(Session session, SessionState state, Exception exception) {
	        if (session.isOpened()) {
	        	Request.newMeRequest(session, new Request.GraphUserCallback() {
		            @Override
		            public void onCompleted(final GraphUser user, final Response response) {
		              if (user != null) {		                
		                nome.setText("Ciao " + user.getName() + "!");
		                logged = true;
		              }
		            }
		          }).executeAsync();

	}
	        else
	        {
	        	nome.setText("Ciao anonimo!");
	        	logged = false;
	        }
	      }});
	}

Infine, gestiamo il click sul tasto Post e rimandiamo il tutto ad un metodo Condividi() che andiamo a scrivere successivamente:

	@Override
	public void onClick(View v) {
		if (v==post){
			condividi();
		}
		// TODO Auto-generated method stub

	}

Arriviamo, dunque, alla parte finale del nostro tutorial che è proprio la condivisione: per effettuare un post tramite l'app, dobbiamo inserire in un Bundle delle stringhe, che corrispondano a name, caption, description, link (dove si viene rimandati in caso di click) e immagine (ovviamente il nostro amato logo).

Dopo aver controllato che l'utente sia effettivamente collegato (in alternativa, l'app restituirà un Toast di errore), tutto quel che segue sono una serie di controlli per verificare che il post venga effettivamente pubblicato e può essere tranquillamente copincollato: l'importante è capire le variabili da cambiare e a cosa corrispondono. Questo, quindi, sarà il nostro metodo:

 public void condividi(){
		 Bundle params = new Bundle();
			params.putString("name", "App di prova per AndroidWorld!");
			params.putString("caption", "AndroidWorld: il primo sito italiano dedicato ad Android!");
			params.putString("description",
					"DevCorner: l'appuntamento settimanale per imparare a programmare su Android");
			params.putString("link", "https://www.androidworld.it/2013/09/03/devcorner-effettuiamo-il-login-con-facebook-e-postiamo-sulla-bacheca");
			params.putString("picture", "https://www.androidworld.it/wp-content/themes/android2013/images/logo_def.png");
			if ((Session.getActiveSession() == null)|| (logged==false)) {
				Toast.makeText(ctx,
						"Non sei ancora collegato su Facebbok: esegui il login per condividere la nota!",
						Toast.LENGTH_LONG).show();
			} 

			else {
				try{
				WebDialog feedDialog = (new WebDialog.FeedDialogBuilder(ctx,
						Session.getActiveSession(), params)).setOnCompleteListener(
						new OnCompleteListener() {

							@Override
							public void onComplete(Bundle values,
									FacebookException error) {
								if (error == null) {

									final String postId = values
											.getString("post_id");
									if (postId != null) {
										Toast.makeText(ctx,
												"Post effettuato correttamente!" 
										//+ postId

												,Toast.LENGTH_SHORT).show();
									} else {

										Toast.makeText(
												ctx.getApplicationContext(),
												"Post annullato",
												Toast.LENGTH_SHORT).show();
									}
								} else if (error instanceof FacebookOperationCanceledException) {
									// 
									Toast.makeText(
											ctx.getApplicationContext(),
											"Post annullato", Toast.LENGTH_SHORT)
											.show();
								} else {

									Toast.makeText(
											ctx.getApplicationContext(),
											"Si è presentato un errore durante la pubblicazione",
											Toast.LENGTH_SHORT).show();
								}
							}

						}).build();
				feedDialog.show();
			}

			catch (FacebookException e) {
				// TODO: handle exception
				Toast.makeText(
						ctx.getApplicationContext(),
						"Impossibile pubblicare",
						Toast.LENGTH_SHORT).show();

			}
			}

	 }

Infine, l'intero codice Java della MainActivity, sarà qualcosa di simile:

package com.peppeuz.faceapp;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;

import com.facebook.FacebookException;
import com.facebook.FacebookOperationCanceledException;
import com.facebook.Request;
import com.facebook.Response;
import com.facebook.Session;
import com.facebook.SessionState;
import com.facebook.model.GraphUser;
import com.facebook.widget.WebDialog;
import com.facebook.widget.WebDialog.OnCompleteListener;

public class MainActivity extends Activity implements OnClickListener{
	//
	Button post;
	Context ctx;
	TextView nome;
	Boolean logged;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		nome = (TextView) findViewById(R.id.nome);
		post = (Button) findViewById(R.id.post);
		post.setOnClickListener(this);
		ctx =this;
		logged = false;
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public void onClick(View v) {
		if (v==post){
			condividi();
		}
		// TODO Auto-generated method stub

	}

	public void facebookLogin(){

	    Session.openActiveSession(this, true, new Session.StatusCallback() {

	      @Override
	      public void call(Session session, SessionState state, Exception exception) {
	        if (session.isOpened()) {
	        	Request.newMeRequest(session, new Request.GraphUserCallback() {
		            @Override
		            public void onCompleted(final GraphUser user, final Response response) {
		              if (user != null) {		                
		                nome.setText("Ciao " + user.getName() + "!");
		                logged = true;
		              }
		            }
		          }).executeAsync();

	}
	        else
	        {
	        	nome.setText("Ciao anonimo!");
	        	logged = false;
	        }
	      }});
	}

	 @Override
	  public void onActivityResult(int requestCode, int resultCode, Intent data) {
	      super.onActivityResult(requestCode, resultCode, data);
	      Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
	      facebookLogin();
	  }

	 public void condividi(){
		 Bundle params = new Bundle();
			params.putString("name", "App di prova per AndroidWorld!");
			params.putString("caption", "AndroidWorld: il primo sito italiano dedicato ad Android!");
			params.putString("description",
					"DevCorner: l'appuntamento settimanale per imparare a programmare su Android");
			params.putString("link", "https://www.androidworld.it/2013/09/03/devcorner-effettuiamo-il-login-con-facebook-e-postiamo-sulla-bacheca");
			params.putString("picture", "https://www.androidworld.it/wp-content/themes/android2013/images/logo_def.png");
			if ((Session.getActiveSession() == null)|| (logged==false)) {
				Toast.makeText(ctx,
						"Non sei ancora collegato su Facebbok: esegui il login per condividere la nota!",
						Toast.LENGTH_LONG).show();
			} 

			else {
				try{
				WebDialog feedDialog = (new WebDialog.FeedDialogBuilder(ctx,
						Session.getActiveSession(), params)).setOnCompleteListener(
						new OnCompleteListener() {

							@Override
							public void onComplete(Bundle values,
									FacebookException error) {
								if (error == null) {

									final String postId = values
											.getString("post_id");
									if (postId != null) {
										Toast.makeText(ctx,
												"Post effettuato correttamente!" 
										//+ postId

												,Toast.LENGTH_SHORT).show();
									} else {

										Toast.makeText(
												ctx.getApplicationContext(),
												"Post annullato",
												Toast.LENGTH_SHORT).show();
									}
								} else if (error instanceof FacebookOperationCanceledException) {
									// 
									Toast.makeText(
											ctx.getApplicationContext(),
											"Post annullato", Toast.LENGTH_SHORT)
											.show();
								} else {

									Toast.makeText(
											ctx.getApplicationContext(),
											"Si è presentato un errore durante la pubblicazione",
											Toast.LENGTH_SHORT).show();
								}
							}

						}).build();
				feedDialog.show();
			}

			catch (FacebookException e) {
				// TODO: handle exception
				Toast.makeText(
						ctx.getApplicationContext(),
						"Impossibile pubblicare",
						Toast.LENGTH_SHORT).show();

			}
			}

	 }

}

Ecco fatto! Siamo riusciti (finalmente) a creare un'applicazione che integra login e post con Facebook: la guida, come avrete potuto notare, è più lunga del solito ma era necessario prestare maggiore cura, vista la mole di informazioni da impostare.

Qualora incappaste in qualche problema potete consultare il la Documentazione ufficiale di Facebook (che purtroppo, ribadiamo, non brilla per chiarezza) o venire a bussare alla porta del nostro forum dove cercheremo volentieri di darvi una mano.

Anche per questa settimana è tutto, buon divertimento con Facebook!

Via: DevCorner