DevCorner: eseguiamo login e post su Twitter

Giuseppe Tripodi
Giuseppe Tripodi Tech Master
DevCorner: eseguiamo login e post su Twitter

Continuano i nostri appuntamenti con DevCorner incentrati sul social e, dopo aver visto come utilizzare Facebook e Google+, non potevamo certo ignorare il caro uccellino blu noto al mondo come Twitter. Andiamo quindi a vedere come effettuare il login e twittare, utilizzando la nota libreria Twitter4J.

La guida di quest'oggi sarà leggermente più facile da seguire delle precedenti poiché Twitter non ha un SDK nativo ma utilizza le REST API: per questo motivo possiamo sfruttare una libreria di terze parti che ci agevola notevolmente il lavoro e che viene illustrata anche in questo tutorial dei colleghi di AndroidHive, da cui abbiamo preso ispirazione.

La prima cosa da fare è creare una nuova applicazione che sfrutti il social network, per questo motivo rechiamoci su Dev Twitter e clicchiamo sul tasto Create New Application e compiliamo tutti i campi: anche se non è obbligatorio, inserite un valore anche in Callback URL (un link qualsiasi andrà bene!), o l'applicazione si comporterà come se fosse pensata per un uso Desktop e non funzionerà da mobile.

Crezione Twitter app

Dalla tab Settings della schermata successiva carichiamo un logo, impostiamo i permessi su Read and Write e mettiamo il segno di spunta su Allow this application to be used to Sign in with Twitter.

Settings App

Tornando sul tab Details, prendiamo nota di Consumer Key e  Consumer Secret, che ci serviranno successivamente.

Scarichiamo adesso Twitter4J ed estraiamo il contenuto in una cartella, facendo particolare attenzione a conservare il file twitter4j-core-3.0.3.jar, contenuto nella cartella lib. Creiamo quindi un nuovo progetto su Eclipse (o su qualsiasi altro IDE utilizziate), facendo attenzione ad impostare come SDK minimo 11.

A questo punto, la prima cosa da fare è includere la libreria scaricata all'interno del nostro progetto. Per farlo, copiamo il file twitter4j-core-3.0.3.jar all'interno della cartella libs.

Twitter4JLib

Adesso rechiamoci nel Manifest ed aggiungiamo i permessi android.permission.INTERNETandroid.permission.ACCESS_NETWORK_STATE. Inoltre, dobbiamo inserire un Intent-filter per la finestra di login di Twitter, in modo che il nostro XML finale abbia un aspetto simile:




    

    
    

    
        
            
                

                
            
            
                

                
                

                
            
        
    

A questo punto occupiamoci dell'interfaccia: in un'unica Activity vogliamo inserire un tasto per il Login, che diventi invisibile una volta effettuato l'accesso per lasciare il posto a un campo di testo, il tasto Tweet e il tasto Logout.

Il risultato finale del nostro activity_main.xml, quindi, sarà così:


     
    
    

 
    
    
     
    
    
     
    
    
     
    
    
 

Prima di passare alla MainActivity.java, creiamo anche una classe chiamata AlertDialogManager.java, che ci servirà per gestire un Dialog personalizzato. All'interno, scriviamoci quanto segue:

package com.peppeuz.dctwitter;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
public class AlertDialogManager {

    public void showAlertDialog(Context context, String title, String message,
            Boolean status) {
        AlertDialog alertDialog = new AlertDialog.Builder(context).create();

       
        alertDialog.setTitle(title);

        
        alertDialog.setMessage(message);

        if(status != null)
           
            alertDialog.setIcon((status) ? R.drawable.ic_launcher : R.drawable.ic_launcher);

        
        alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
            }
        });

  
        alertDialog.show();
}
}

Andiamo adesso a scrivere il "cuore" dell'applicazione, contenuto nel MainActivity.java: qui inseriremo tre metodi per Login, Logout e Tweet, ma prima di qualsiasi altra cosa scriviamo il nostro OnCreate dove, oltre a definire le View presenti e assegnargli un OnClickListener, scriveremo tutti i parametri necessari per Twitter: a tal proposito, non dimenticatevi di sostituire Secret Key e Secret Consumer con quelli relativi alla vostra applicazione.

Nell'OnCreate, inoltre, abbiamo inserito un controllo che si occupa di verificare se era già stato eseguito in precedenza il login, salvando l'AccessToken all'interno delle SharedPreferences.

public class MainActivity extends Activity implements OnClickListener { // Constants
	
	static String TWITTER_CONSUMER_KEY = "W8RMRJjqlQ8p0xFAtf0TZQ";
	static String TWITTER_CONSUMER_SECRET = "nIvmrf7ZRCTj4jCjlPLEo6EuYPlp8tg0K40NZvncY";

	
	static String PREFERENCE_NAME = "twitter_oauth";
	static final String PREF_KEY_OAUTH_TOKEN = "oauth_token";
	static final String PREF_KEY_OAUTH_SECRET = "oauth_token_secret";
	static final String PREF_KEY_TWITTER_LOGIN = "isTwitterLogedIn";

	static final String TWITTER_CALLBACK_URL = "oauth://t4jsample";


	static final String URL_TWITTER_AUTH = "auth_url";
	static final String URL_TWITTER_OAUTH_VERIFIER = "oauth_verifier";
	static final String URL_TWITTER_OAUTH_TOKEN = "oauth_token";

	Button btnLoginTwitter;
	Button btnUpdateStatus;
	Button btnLogoutTwitter;
	EditText txtUpdate;

	ProgressDialog pDialog;

	
	private static Twitter twitter;
	private static RequestToken requestToken;


	private static SharedPreferences mSharedPreferences;


	AlertDialogManager alert = new AlertDialogManager();

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
				.permitAll().build();
		StrictMode.setThreadPolicy(policy);
		setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

	
		if (TWITTER_CONSUMER_KEY.trim().length() == 0
				|| TWITTER_CONSUMER_SECRET.trim().length() == 0) {
		
			alert.showAlertDialog(MainActivity.this, "Twitter oAuth tokens",
					"Please set your twitter oauth tokens first!", false);
		
			return;
		}

	
		btnLoginTwitter = (Button) findViewById(R.id.btnLoginTwitter);
		btnUpdateStatus = (Button) findViewById(R.id.btnUpdateStatus);
		btnLogoutTwitter = (Button) findViewById(R.id.btnLogoutTwitter);
		txtUpdate = (EditText) findViewById(R.id.txtUpdateStatus);

		
		mSharedPreferences = getApplicationContext().getSharedPreferences(
				"MyPref", 0);

		btnLoginTwitter.setOnClickListener(this);

		btnUpdateStatus.setOnClickListener(this);

		btnLogoutTwitter.setOnClickListener(this);

		
		if (!isTwitterLoggedInAlready()) {
			Uri uri = getIntent().getData();
			if (uri != null && uri.toString().startsWith(TWITTER_CALLBACK_URL)) {
				
				String verifier = uri
						.getQueryParameter(URL_TWITTER_OAUTH_VERIFIER);

				try {
				
					AccessToken accessToken = twitter.getOAuthAccessToken(
							requestToken, verifier);

				
					Editor e = mSharedPreferences.edit();

					e.putString(PREF_KEY_OAUTH_TOKEN, accessToken.getToken());
					e.putString(PREF_KEY_OAUTH_SECRET,
							accessToken.getTokenSecret());
					
					e.putBoolean(PREF_KEY_TWITTER_LOGIN, true);
					e.commit();

				
					btnLoginTwitter.setVisibility(View.GONE);

					

					txtUpdate.setVisibility(View.VISIBLE);
					btnUpdateStatus.setVisibility(View.VISIBLE);
					btnLogoutTwitter.setVisibility(View.VISIBLE);

				
					long userID = accessToken.getUserId();
					User user = twitter.showUser(userID);
					String username = user.getName();

					Toast.makeText(getApplicationContext(),
							Html.fromHtml("Benvenuto " + username + ""),
							Toast.LENGTH_LONG).show();

				} catch (Exception e) {
					
					Log.e("Errore Login", "> " + e.getMessage());
				}
			}
		}

	}

Il codice per il login su Twitter fa ovviamente affidamento alla libreria utilizzata e c'è ben poco da capire: vi basti sapere che, come in tutti i casi di login via App, utilizza un Token che certifica il login.

Una volta collegati, inoltre, apparirà un Toast che vi dà il benvenuto con il vostro nome.

private void loginToTwitter() {
		
		if (!isTwitterLoggedInAlready()) {
			ConfigurationBuilder builder = new ConfigurationBuilder();
			builder.setOAuthConsumerKey(TWITTER_CONSUMER_KEY);
			builder.setOAuthConsumerSecret(TWITTER_CONSUMER_SECRET);
			Configuration configuration = builder.build();

			TwitterFactory factory = new TwitterFactory(configuration);
			twitter = factory.getInstance();

			try {
				requestToken = twitter
						.getOAuthRequestToken(TWITTER_CALLBACK_URL);
				this.startActivity(new Intent(Intent.ACTION_VIEW, Uri
						.parse(requestToken.getAuthenticationURL())));
			} catch (TwitterException e) {
				e.printStackTrace();
			}
		} else {
			
			btnLoginTwitter.setVisibility(View.GONE);


			txtUpdate.setVisibility(View.VISIBLE);
			btnUpdateStatus.setVisibility(View.VISIBLE);
			btnLogoutTwitter.setVisibility(View.VISIBLE);

			Toast.makeText(getApplicationContext(),
					"Utente già collegato", Toast.LENGTH_LONG).show();
		}
	}

Lo stesso discorso vale per il metodo di logout che, oltre a mostrare nuovamente il tasto di Login e nascondere gli altri, non fa altro che rimuovere dalle SharedPreferences il token ottenuto ed i nostri dati:

	private void logoutFromTwitter() {
		
		Editor e = mSharedPreferences.edit();
		e.remove(PREF_KEY_OAUTH_TOKEN);
		e.remove(PREF_KEY_OAUTH_SECRET);
		e.remove(PREF_KEY_TWITTER_LOGIN);
		e.commit();

		btnLogoutTwitter.setVisibility(View.GONE);
		btnUpdateStatus.setVisibility(View.GONE);
		txtUpdate.setVisibility(View.GONE);

		btnLoginTwitter.setVisibility(View.VISIBLE);
	}

Discorso decisamente più complicato è quello per aggiornare lo status: per farlo creiamo una classe che estende AsyncTask, per fare in modo che la nostra operazione venga completata in modo asincrono, in background: completato il procedimento, ci viene mostrato un toast che conferma la pubblicazione del Tweet.

	class updateTwitterStatus extends AsyncTask<String, String, String> {

		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			pDialog = new ProgressDialog(MainActivity.this);
			pDialog.setMessage("Update in corso...");
			pDialog.setIndeterminate(false);
			pDialog.setCancelable(false);
			pDialog.show();
		}

		
		protected String doInBackground(String... args) {
			Log.d("Tweet Text", "> " + args[0]);
			String status = args[0];
			try {
				ConfigurationBuilder builder = new ConfigurationBuilder();
				builder.setOAuthConsumerKey(TWITTER_CONSUMER_KEY);
				builder.setOAuthConsumerSecret(TWITTER_CONSUMER_SECRET);

				
				String access_token = mSharedPreferences.getString(
						PREF_KEY_OAUTH_TOKEN, "");
				
				String access_token_secret = mSharedPreferences.getString(
						PREF_KEY_OAUTH_SECRET, "");

				AccessToken accessToken = new AccessToken(access_token,
						access_token_secret);
				Twitter twitter = new TwitterFactory(builder.build())
						.getInstance(accessToken);

				twitter4j.Status response = twitter.updateStatus(status);

				Log.d("Status", "> " + response.getText());
			} catch (TwitterException e) {
			
				Log.d("Twitter Update Error", e.getMessage());
			}
			return null;
		}

		
		protected void onPostExecute(String file_url) {
			
			pDialog.dismiss();
		
			runOnUiThread(new Runnable() {
				@Override
				public void run() {
					Toast.makeText(getApplicationContext(),
							"Tweet pubblicato", Toast.LENGTH_SHORT)
							.show();
					
					txtUpdate.setText("");
				}
			});
		}

	}

Mettendo tutto insieme, configurando il metodo OnClick con i vari if e importando tutto il necessario, quel che avremo fuori nel metodo MainActivity è qualcosa del genere:

package com.peppeuz.dctwitter;

import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.User;
import twitter4j.auth.AccessToken;
import twitter4j.auth.RequestToken;
import twitter4j.conf.Configuration;
import twitter4j.conf.ConfigurationBuilder;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.ActivityInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.StrictMode;
import android.text.Html;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener {
	
	static String TWITTER_CONSUMER_KEY = "W8RMRJjqlQ8p0xFAtf0TZQ";
	static String TWITTER_CONSUMER_SECRET = "nIvmrf7ZRCTj4jCjlPLEo6EuYPlp8tg0K40NZvncY";

	
	static String PREFERENCE_NAME = "twitter_oauth";
	static final String PREF_KEY_OAUTH_TOKEN = "oauth_token";
	static final String PREF_KEY_OAUTH_SECRET = "oauth_token_secret";
	static final String PREF_KEY_TWITTER_LOGIN = "isTwitterLogedIn";

	static final String TWITTER_CALLBACK_URL = "oauth://t4jsample";


	static final String URL_TWITTER_AUTH = "auth_url";
	static final String URL_TWITTER_OAUTH_VERIFIER = "oauth_verifier";
	static final String URL_TWITTER_OAUTH_TOKEN = "oauth_token";

	Button btnLoginTwitter;
	Button btnUpdateStatus;
	Button btnLogoutTwitter;
	EditText txtUpdate;

	ProgressDialog pDialog;

	private static Twitter twitter;
	private static RequestToken requestToken;


	private static SharedPreferences mSharedPreferences;


	AlertDialogManager alert = new AlertDialogManager();

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
				.permitAll().build();
		StrictMode.setThreadPolicy(policy);
		setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

	
		if (TWITTER_CONSUMER_KEY.trim().length() == 0
				|| TWITTER_CONSUMER_SECRET.trim().length() == 0) {
		
			alert.showAlertDialog(MainActivity.this, "Twitter oAuth tokens",
					"Please set your twitter oauth tokens first!", false);
		
			return;
		}

	
		btnLoginTwitter = (Button) findViewById(R.id.btnLoginTwitter);
		btnUpdateStatus = (Button) findViewById(R.id.btnUpdateStatus);
		btnLogoutTwitter = (Button) findViewById(R.id.btnLogoutTwitter);
		txtUpdate = (EditText) findViewById(R.id.txtUpdateStatus);

		mSharedPreferences = getApplicationContext().getSharedPreferences(
				"MyPref", 0);

		btnLoginTwitter.setOnClickListener(this);

		btnUpdateStatus.setOnClickListener(this);

		btnLogoutTwitter.setOnClickListener(this);

		
		if (!isTwitterLoggedInAlready()) {
			Uri uri = getIntent().getData();
			if (uri != null && uri.toString().startsWith(TWITTER_CALLBACK_URL)) {
				String verifier = uri
						.getQueryParameter(URL_TWITTER_OAUTH_VERIFIER);

				try {
					AccessToken accessToken = twitter.getOAuthAccessToken(
							requestToken, verifier);

					Editor e = mSharedPreferences.edit();
					e.putString(PREF_KEY_OAUTH_TOKEN, accessToken.getToken());
					e.putString(PREF_KEY_OAUTH_SECRET,
							accessToken.getTokenSecret());
					e.putBoolean(PREF_KEY_TWITTER_LOGIN, true);
					e.commit(); 
					btnLoginTwitter.setVisibility(View.GONE);


					txtUpdate.setVisibility(View.VISIBLE);
					btnUpdateStatus.setVisibility(View.VISIBLE);
					btnLogoutTwitter.setVisibility(View.VISIBLE);

					long userID = accessToken.getUserId();
					User user = twitter.showUser(userID);
					String username = user.getName();

					Toast.makeText(getApplicationContext(),
							Html.fromHtml("Benvenuto " + username + ""),
							Toast.LENGTH_LONG).show();

				} catch (Exception e) {
					Log.e("Errore Login", "> " + e.getMessage());
				}
			}
		}

	}

	
	private void loginToTwitter() {
		if (!isTwitterLoggedInAlready()) {
			ConfigurationBuilder builder = new ConfigurationBuilder();
			builder.setOAuthConsumerKey(TWITTER_CONSUMER_KEY);
			builder.setOAuthConsumerSecret(TWITTER_CONSUMER_SECRET);
			Configuration configuration = builder.build();

			TwitterFactory factory = new TwitterFactory(configuration);
			twitter = factory.getInstance();

			try {
				requestToken = twitter
						.getOAuthRequestToken(TWITTER_CALLBACK_URL);
				this.startActivity(new Intent(Intent.ACTION_VIEW, Uri
						.parse(requestToken.getAuthenticationURL())));
			} catch (TwitterException e) {
				e.printStackTrace();
			}
		} else {
			btnLoginTwitter.setVisibility(View.GONE);

			txtUpdate.setVisibility(View.VISIBLE);
			btnUpdateStatus.setVisibility(View.VISIBLE);
			btnLogoutTwitter.setVisibility(View.VISIBLE);

			Toast.makeText(getApplicationContext(),
					"Utente già collegato", Toast.LENGTH_LONG).show();
		}
	}

	
	class updateTwitterStatus extends AsyncTask<String, String, String> {

		
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			pDialog = new ProgressDialog(MainActivity.this);
			pDialog.setMessage("Update in corso...");
			pDialog.setIndeterminate(false);
			pDialog.setCancelable(false);
			pDialog.show();
		}

		
		protected String doInBackground(String... args) {
			Log.d("Tweet Text", "> " + args[0]);
			String status = args[0];
			try {
				ConfigurationBuilder builder = new ConfigurationBuilder();
				builder.setOAuthConsumerKey(TWITTER_CONSUMER_KEY);
				builder.setOAuthConsumerSecret(TWITTER_CONSUMER_SECRET);

				String access_token = mSharedPreferences.getString(
						PREF_KEY_OAUTH_TOKEN, "");
				String access_token_secret = mSharedPreferences.getString(
						PREF_KEY_OAUTH_SECRET, "");

				AccessToken accessToken = new AccessToken(access_token,
						access_token_secret);
				Twitter twitter = new TwitterFactory(builder.build())
						.getInstance(accessToken);

				twitter4j.Status response = twitter.updateStatus(status);

				Log.d("Status", "> " + response.getText());
			} catch (TwitterException e) {
				Log.d("Twitter Update Error", e.getMessage());
			}
			return null;
		}

		
		protected void onPostExecute(String file_url) {
			pDialog.dismiss();
			runOnUiThread(new Runnable() {
				@Override
				public void run() {
					Toast.makeText(getApplicationContext(),
							"Tweet pubblicato", Toast.LENGTH_SHORT)
							.show();
					txtUpdate.setText("");
				}
			});
		}

	}

	
	private void logoutFromTwitter() {
		Editor e = mSharedPreferences.edit();
		e.remove(PREF_KEY_OAUTH_TOKEN);
		e.remove(PREF_KEY_OAUTH_SECRET);
		e.remove(PREF_KEY_TWITTER_LOGIN);
		e.commit();

		
		btnLogoutTwitter.setVisibility(View.GONE);
		btnUpdateStatus.setVisibility(View.GONE);
		txtUpdate.setVisibility(View.GONE);

		btnLoginTwitter.setVisibility(View.VISIBLE);
	}

	
	private boolean isTwitterLoggedInAlready() {
		return mSharedPreferences.getBoolean(PREF_KEY_TWITTER_LOGIN, false);
	}

	protected void onResume() {
		super.onResume();
	}

	@Override
	public void onClick(View view) {
		if (view == btnLoginTwitter) {
			loginToTwitter();
		}
		if (view == btnLogoutTwitter) {
			logoutFromTwitter();
		}
		if (view == btnUpdateStatus) {
		
			String status = txtUpdate.getText().toString();

			
			if (status.trim().length() > 0) {
				
				new updateTwitterStatus().execute(status);
			} else {
			
				Toast.makeText(getApplicationContext(),
						"Please enter status message", Toast.LENGTH_SHORT)
						.show();
			}
		}
	}

}

Anche per questa settimana il DevCorner vi saluta: adesso sapete come utilizzare i tre maggiori social network all'interno della vostra applicazione.

Tuttavia, nel caso di fastidiosi problemi, vi rimandiamo come sempre al nostro forum dove cercheremo di aiutarvi.

Via: DevCorner