Integrando Twitter en aplicaciones Android con SignPost y Twitter4J

Nota importante: esta entrada está muy anticuada, ¡data de Octubre de 2011! La API de Twitter ha cambiado mucho desde entonces y es posible que esta entrada no sea ya correcta.

 

La semana pasada vimos cómo integrar Twitter en aplicaciones Android usando la google-api-java-client y Twitter4J. Sin embargo, vimos que dicha solución dependía de una cantidad enorme de librerías de la API de Google, que tenía como resultado una aplicación que pesaba ~2.5MB, y eso era casi íntegro en librerías.

En esta entrada vamos a ver cómo hacer la autorización de uso de nuestra aplicación en la cuenta de Twitter del usuario, y cómo poner tweets en su cuenta usando SignPost y Twitter4J, obteniendo como resultado una aplicación que pesa sólo 400KB.

En la anterior entrada usábamos la google-api-java-client para implementar el cauce de OAuth 2.0. En este caso vamos a utilizar la librería SignPost para el cauce OAuth 1.0, aunque Twitter eventualmente migrará a OAuth 2.0 como los demás y este método no servirá.

Nota: recordad que Twitter va cambiando y en algún momento usarán tecnologías que esta entrada no cubre porque no podemos anticiparnos a ellos. Sin embargo no podemos estar al tanto de todos estos cambios e ir modificando las guías según ellos introduzcan modificaciones. Lo sentimos por adelantado.

¡Comencemos!

El primer paso consiste en descargar las librerías de SignPost. Para ello nos dirimos a la página de OAuth-SignPost, en la cual podemos pulsar en Downloads y descargar tanto signpost-core-1.2.1.1.jar como signpost-commonshttp4-1.2.1.1.jar. Una vez descargadas nos dirigimos a la página de Twitter4J y buscamos la descarga de twitter4j-android-2.2.4.zip que es la versión slim de Twitter4J para que pese menos en nuestros proyectos Android. Del fichero comprimido que descargamos sólo nos interesa el la librería que está en lib/twitter4j-core-android-2.2.4.jar.

Una vez tengamos las librerías, es el momento de crear una aplicación en la página de Twitter Developers. Recordemos que primero necesitamos una cuenta de Twitter para poder realizar estos ejemplos. Dicha aplicación no será más que un conjunto de claves que usaremos en nuestra aplicación real para realizar la interacción con Twitter. En los campos del formulario pondremos lo siguiente:

  • Name: el nombre de la aplicación. En nuestro caso será “Going Social vidasConcurrentes”, aunque en un caso de aplicación real lo suyo sería que tuviera el nombre de dicha aplicación (puesto que será el nombre que verá el usuario al tener que autorizar el uso de su cuenta de Twitter, y no debe ser confuso).
  • Description: una breve descripción de la aplicación.
  • WebSite: no hace falta que sea una URL real, pero aquí debe ir la URL del lugar donde los usuarios pueden descargar la aplicación o donde puedan encontrar más información sobre ella. Cuando publiquen un tweet desde nuestra aplicación aparecerá al final “via Going Social Test” para nuestro caso. Y al hacer click irá a la página que pongamos en este campo.
  • Callback: podéis poner aquí cualquier cosa que tenga formato de URL. Más adelante explicaremos qué es y para qué sirve el callback, pero de momento vale con saber que cualquier cosa nos sirve en este campo.

Aceptaremos las reglas de Twitter y registraremos la aplicación. Una vez hecho seremos redirigidos a la página principal de nuestra recientemente creada aplicación. Echando un rápido vistazo vemos que tenemos cinco pestañas. Las que nos interesan son Details y Settings. Lo primero, antes de explicar qué hay en Details, vamos a la pestaña Settings. En ella veremos una sección llamada “Application Type”, donde elegiremos Read and Write puesto que queremos que nuestra aplicación pueda escribir tweets por el usuario. Los demás campos son opcionales. Ahora sí, visitamos la pestaña Details. En ella tenemos la información necesaria para la autorización OAuth. Tanto Consumer Key como Consumer Secret serán las claves que usaremos en nuestra aplicación para realizar una autorización segura para el usuario. Las tres URL que vemos son las que usaremos para pedir el token del usuario, autorizar la aplicación y acceder a la cuenta.

Iniciamos nuestro Eclipse configurado con el Android SDK y creamos un nuevo proyecto, que en nuestro caso tendrá las siguientes propiedades:

  • Project Name: GoingSocialTwitterSignPost
  • Build Target: 2.1-update
  • Application Name: GoingSocialTwitterSignPost
  • Package Name: com.vidasconcurrentes.goingsocialtwittersignpost
  • Create Activity: GoingSocialTwitterSignPostActivity
  • Min SDK Version: 7

Una vez tengamos el proyecto creado, creamos un nuevo directorio en el proyecto (bien con nuestro explorador de ficheros o bien haciendo click derecho en el proyecto y seleccionando New > Folder). Le llamamos lib y copiamos las tres librerías que hemos descargado en su interior. El siguiente paso es vincular dichas librerías.

Una vez estén, hacemos click derecho en el proyecto y seleccionamos Properties. Bajo Java Build Path, pulsando en la pestaña Libraries, tenemos las librerías enlazadas en este proyecto. Pulsamos en Add JARs… y navegamos en nuestro proyecto, el directorio lib, y dentro seleccionamos las tres librerías recién incluidas. Una vez aceptemos tendremos algo así:

Comenzamos entonces con nuestro código. En este caso vamos a hacer un ejemplo más simple que en la entrada anterior.

Lo primero que vamos a hacer es el layout que usará nuestra aplicación para mostrar la interfaz. Simplemente podemos copiar el siguiente código dentro de main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <TextView android:layout_gravity="center" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="Este es el codigo de respuesta" android:id="@+id/codigoRespuesta" android:layout_marginBottom="15dip"></TextView>
    <Button android:layout_gravity="center" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="Autorizar" android:layout_marginBottom="30dip" android:id="@+id/botonAutorizar"></Button>
    <TextView android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="Este tweet está enviado desde una aplicación de #Android, con el seguimiento de una entrada de @vidasConcurrent" android:layout_gravity="center" android:id="@+id/tweet" android:layout_marginBottom="15dip"></TextView>
    <Button android:layout_gravity="center" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="Enviar tweet" android:id="@+id/botonEnviarTweet"></Button>
</LinearLayout>

Si ahora ejecutásemos la aplicación, que aún no hace nada, veremos lo siguiente:

Ahora sí, empezamos el código. Comenzamos modificando la Activity que se genera por defecto, quedando su código de esta forma:

public class GoingSocialTwitterSignPostActivity extends Activity {

	private static final String CONSUMER_KEY = "XXXXXXXXXXXXXXXXXXXXXX";
	private static final String CONSUMER_SECRET = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
	private static final String REQUEST_URL = "https://api.twitter.com/oauth/request_token";
	private static final String AUTHORIZE_URL = "https://api.twitter.com/oauth/authorize";
	private static final String ACCESS_URL = "https://api.twitter.com/oauth/access_token";
	private static final String CALLBACK_URL = "app://testtwitter";

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
	}
}

Donde CONSUMER_KEY y CONSUMER_SECRET deben ser las que nos proporcionó Twitter al crear la aplicación y CALLBACK_URL es lo que queramos, con ese tipo de formato. Ayuda a mantener comprensible para nosotros la aplicación si ponemos app://nombre_actividad_donde_estamos.

Ahora nos interesa poder acceder a los dos TextView y a los dos Button que veíamos en la interfaz. Lo podemos hacer creando cuatro atributos nuevos y modificando el código de onCreate() de esta forma:

private TextView codigoRespuesta;
private Button botonAutorizar;
private TextView campoTweet;
private Button botonEnviarTweet;

@Override
public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);

	codigoRespuesta = (TextView) findViewById(R.id.codigoRespuesta);
	botonAutorizar = (Button) findViewById(R.id.botonAutorizar);
	campoTweet = (TextView) findViewById(R.id.tweet);
	botonEnviarTweet = (Button) findViewById(R.id.botonEnviarTweet);

	botonAutorizar.setOnClickListener(new View.OnClickListener() {
		@Override
		public void onClick(View v) {
			autoriza();
		}
	});

	botonEnviarTweet.setOnClickListener(new View.OnClickListener() {
		@Override
		public void onClick(View v) {

		}
	});
}

No es necesario que nuestros atributos tengan el mismo nombre que los identificadores de los elementos de la interfaz, pero siempre ayuda para ver con qué estamos tratando. Como vemos, hemos añadido un OnClickListener a cada uno de los botones. El método onClick() de cada uno de ellos se llamará cuando se pulse sobre ellos, y es donde vamos a incluir nuestro código siguiente (de hecho ya hemos puesto la llamada al método autoriza(), que es lo siguiente que implementamos). Antes de nada, nos interesa incluir los siguientes dos atributos a la clase, junto a los ya añadidos:

private CommonsHttpOAuthConsumer httpOauthConsumer;
private OAuthProvider httpOauthprovider;

Estos dos objetos serán los encargados de crear y consumir las operaciones del cauce del OAuth. Continuamos con la implementación del método actualiza():

private void autoriza() {
	try {
		httpOauthConsumer = new CommonsHttpOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
		httpOauthprovider = new DefaultOAuthProvider(REQUEST_URL, ACCESS_URL, AUTHORIZE_URL);
		String authUrl = httpOauthprovider.retrieveRequestToken(httpOauthConsumer, CALLBACK_URL);

		this.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(authUrl)));
	} catch (Exception e) {
		codigoRespuesta.setText(e.getMessage());
	}
}

Este método hace varias cosas. Lo primero es crear el consumer del OAuth, que es quien contiene las claves del consumidor (CONSUMER_KEY y CONSUMER_SECRET). Lo segundo es crear el productor, que cuenta con las tres URL que nos proporcionó también Twitter Devs. Por último le pedimos al productor que nos de la URL para autorizar la aplicación, y saltamos a un navegador con dicha URL. En caso de tener algún error, saltará una excepción y la pondremos en el campo de texto.

El cauce de nuestra aplicación consiste en:

  • El usuario pulsa en autorizar.
  • Se abre una de las aplicaciones de navegador web del usuario (podríamos usar un WebView como en la entrada anterior), y el usuario autoriza la aplicación.
  • La página de Twitter intenta ir a la CALLBACK_URL que le dijimos al ir a la URL de autorizado. Nuestra tarea es evitar que vaya allí, y conseguir que vuelva a nuestra aplicación.
  • La aplicación ya está autorizada, podemos publicar tweets y todo lo que nos ofrezca la librería Twitter4J.

El siguiente paso, por tanto, consiste en recuperar el control de la aplicación una vez que el usuario autorice su uso. Para ello vamos a sobreescribir un método de las Activity llamado onNewIntent(), cuyo código quedará:

private AccessToken accessToken;

@Override
protected void onNewIntent(Intent intent) {
	super.onNewIntent(intent);

	Uri uri = intent.getData();
	if (uri != null && uri.toString().startsWith(CALLBACK_URL)) {
		String verifier = uri.getQueryParameter(oauth.signpost.OAuth.OAUTH_VERIFIER);
		try {
			httpOauthprovider.retrieveAccessToken(httpOauthConsumer, verifier);
			accessToken = new AccessToken(httpOauthConsumer.getToken(), httpOauthConsumer.getTokenSecret());

			botonAutorizar.setEnabled(false);
		} catch (Exception e) {
			codigoRespuesta.setText(e.getMessage());
		}
	}
}

Cuando el navegador intente cargar una nueva URL con nuestro CALLBACK_URL, se lanzará este método. Comprobamos que la URL comience con el CALLBACK_URL, y si es así obtenemos un verificador para comprobar que el token de acceso está bien firmado con nuestras claves. Si no hay errores, tendremos en el objeto de la clase AccessToken la información que dice que la aplicación está autorizada. Sería interesante que almacenásemos los dos campos del AccessToken, que son el token y token_secret, por ejemplo en las SharedPreferences de la aplicación, tal y como contamos aquí. De ese modo evitamos que el usuario tenga que autorizar la aplicación cada vez que la inicie.

Ahora que ya tenemos los datos de acceso para el usuario, es momento de crear la funcionalidad para el botón de envio de tweet. Crearemos un nuevo método que se encargue de enviar el tweet, de la siguiente forma:

private void enviaTweet() {
	try {
		Twitter twitter = new TwitterFactory().getInstance();
		twitter.setOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
		twitter.setOAuthAccessToken(accessToken);

		twitter.updateStatus(campoTweet.getText().toString());

		codigoRespuesta.setText("Tweet enviado!");
	} catch(Exception e) {
		codigoRespuesta.setText(e.getMessage());
	}
}

Lo primero es crear un objeto de tipo Twitter que nos ofrece Twitter4J. Posteriormente le asignamos el consumidor de OAuth con el CONSUMER_KEY y CONSUMER_SECRET, además de añadirle el token de acceso que hemos recibido. Una vez esto esté hecho, ponemos el tweet que queramos, que en este caso es el texto del campo de texto que mostramos en la interfaz. Si hay un error, se nos muestra en el campo de texto superior.

Es importante, de cara a futuros usos de Twitter en nuestras aplicaciones, que las reglas de Twitter nos dicen que aunque un usuario haya autorizado nuestra aplicación esto no significa que nosotros podamos enviar tweets en su cuenta indiscriminadamente o sin mostrarle el contenido. Como mínimo debemos mostrarle el tweet y un botón que le permita aceptar la publicación, en caso de no dejarle que lo edite.

Nos resta una cosa antes de poder probar que todo esto que hemos hecho funciona, y es modificar el AndroidManifest.xml. Recordemos que aquí debemos incluir cómo se ejecutan todas las actividades, los permisos que necesita la aplicación y los filtros de los Intent (entre otros). Lo modificamos así:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.vidasconcurrentes.goingsocialtwittersignpost"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="7" />
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".GoingSocialTwitterSignPostActivity"
                  android:label="@string/app_name"
                  android:launchMode="singleInstance">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <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="app" android:host="goingsocial" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Hemos añadido la línea de uses-permission, para reflejar que vamos a usar internet desde la aplicación. Hemos añadido el launchMode a la actividad, que siendo singleInstance significa que sólo puede haber en ejecución una instancia de dicha actividad, esto nos servirá para poder recibir el callback. Por otra parte hemos añadido el segundo intent-filter. Que sea BROWSABLE es para que funcione el callback, referenciando a información dado un enlace. Dicha información viene dada por la clave data. Tenemos que poner la parte izquierda de nuestro CALLBACK_URL en scheme y la parte derecha en host. La clave data tiene por tanto este formato dada una URI: scheme://host:port/path.
Recordemos que el hecho de que en el intent-filter que ya aparecía tengamos la acción android.intent.action.MAIN significa que es la Activity principal (la primera que se ejecuta) de nuestra aplicación. Que la categoría sea …LAUNCHER significa que esta Activity aparecerá en el Launcher del dispositivo.

Una vez tenemos todo esto desplegado, es momento de ejecutar y probar la aplicación. Veamos el resultado mostrado en la aplicación después de probar varias cosas, comenzando con la vista inicial:

¿Qué pasa si intentamos mandar el tweet sin haber autorizado aún?

Pulsamos en Autorizar, se carga el navegador para que autoricemos la aplicación:

Tras autorizarla, el navegador intenta ir al CALLBACK_URL, la aplicación lo va a interceptar:

Ya hemos autorizado la aplicación así que no podemos hacerlo otra vez. Pulsamos en Enviar Tweet y comprobamos que se ha publicado (incluyendo la fuente de dicho tweet):

¡Y ya hemos conseguido publicar contenido en Twitter desde nuestra aplicación!

En esta entrada hemos visto cómo, de manera muy sencilla, podemos publicar contenido en Twitter desde nuestra aplicación de Android. Esto es especialmente útil cuando queremos dar a los usuarios la opción de compartir con sus seguidores que están usando nuestra aplicación, lo cual nos asegura un mayor público. Hemos usado las librerías SignPost para el cauce OAuth y Twitter4J para usar la API de Twitter. Sólo hemos publicado un tweet, pero dicha API permite prácticamente todo lo que se puede hacer con Twitter. ¡Os invitamos a que juguéis con ello!

¡Lo mejor de todo es que incluir esta funcionalidad en nuestra aplicación sólo significa añadir 400KB al paquete!

Podéis descargar el proyecto de Eclipse de la aplicación que creé para hacer esta entrada desde aquí (MD5: af3b47e2552758245805c972fcf5acfd), listo para ser importado.

¡Un saludo a todos los lectores! ¡Feliz difusión de vuestras apps!

16 Respuestas a Integrando Twitter en aplicaciones Android con SignPost y Twitter4J

  1. Excelente post. Sin embargo, necesito ayuda ya que no me funciona por un problema al pulsar el botón Autorizar. Al pulsarlo, se produce una excepción y el texto de la etiqueta cambia a “Communication with the service provider failed: null”
    Captura de código disponible en (la línea subrayada produce la excepción):
    https://dl.dropbox.com/u/26323323/Captura.PNG

    Gracias por adelantado ;)

    • disculpa a mi me sale el mismo error ayudame de Communication with the service provider failed: null quiero saber si sabes de q es ayudame con esp

      • Me he bajado el código fuente y lo único que hice para que me funcionara bien el ejemplo fue renombrar la carpeta lib a libs.
        Saludos!

  2. Buen tutorial y muy bien explicado.

    Podríais ayudarme con la subida de fotos?? se podría hacer con esta librería??

  3. Excelente post!!!!

    Por el tema de la callback url, tiene q ser el mismo en el manifiest y el de la clase java

    private static final String CALLBACK_URL = “app://testtwitter”;

    el resto funciona de maravilla!

  4. hola, hice el programa paso a paso… y me da un error del la lib twitterfactory

    04-13 20:28:30.302: E/dalvikvm(265): Could not find class ‘oauth.signpost.commonshttp.CommonsHttpOAuthConsumer’, referenced from method com.vidasconcurrentes.goingsocialtwittersignpost.GoingSocialTwitterSignPostActivity.autoriza
    04-13 20:28:30.302: W/dalvikvm(265): VFY: unable to resolve new-instance 37 (Loauth/signpost/commonshttp/CommonsHttpOAuthConsumer;) in Lcom/vidasconcurrentes/goingsocialtwittersignpost/GoingSocialTwitterSignPostActivity;
    04-13 20:28:30.311: D/dalvikvm(265): VFY: replacing opcode 0x22 at 0x0000
    04-13 20:28:30.311: D/dalvikvm(265): Making a copy of Lcom/vidasconcurrentes/goingsocialtwittersignpost/GoingSocialTwitterSignPostActivity;.autoriza code (148 bytes)
    04-13 20:28:30.311: E/dalvikvm(265): Could not find class ‘twitter4j.TwitterFactory’, referenced from method com.vidasconcurrentes.goingsocialtwittersignpost.GoingSocialTwitterSignPostActivity.enviaTweet
    04-13 20:28:30.311: W/dalvikvm(265): VFY: unable to resolve new-instance 40 (Ltwitter4j/TwitterFactory;) in Lcom/vidasconcurrentes/goingsocialtwittersignpost/GoingSocialTwitterSignPostActivity;
    04-13 20:28:30.331: D/dalvikvm(265): VFY: replacing opcode 0x22 at 0x0000
    04-13 20:28:30.331: D/dalvikvm(265): Making a copy of Lcom/vidasconcurrentes/goingsocialtwittersignpost/GoingSocialTwitterSignPostActivity;.enviaTweet code (136 bytes)
    04-13 20:28:30.381: I/dalvikvm(265): Could not find method oauth.signpost.OAuthProvider.retrieveAccessToken, referenced from method com.vidasconcurrentes.goingsocialtwittersignpost.GoingSocialTwitterSignPostActivity.onNewIntent
    04-13 20:28:30.381: W/dalvikvm(265): VFY: unable to resolve interface method 39: Loauth/signpost/OAuthProvider;.retrieveAccessToken (Loauth/signpost/OAuthConsumer;Ljava/lang/String;)V
    04-13 20:28:30.411: D/dalvikvm(265): VFY: replacing opcode 0x72 at 0x001f
    04-13 20:28:30.411: D/dalvikvm(265): Making a copy of Lcom/vidasconcurrentes/goingsocialtwittersignpost/GoingSocialTwitterSignPostActivity;.onNewIntent code (172 bytes)
    04-13 20:28:31.901: D/AndroidRuntime(265): Shutting down VM
    04-13 20:28:31.901: W/dalvikvm(265): threadid=3: thread exiting with uncaught exception (group=0x4001b188)
    04-13 20:28:31.901: E/AndroidRuntime(265): Uncaught handler: thread main exiting due to uncaught exception
    04-13 20:28:31.911: E/AndroidRuntime(265): java.lang.NoClassDefFoundError: oauth.signpost.commonshttp.CommonsHttpOAuthConsumer
    04-13 20:28:31.911: E/AndroidRuntime(265): at com.vidasconcurrentes.goingsocialtwittersignpost.GoingSocialTwitterSignPostActivity.autoriza(GoingSocialTwitterSignPostActivity.java:72)
    04-13 20:28:31.911: E/AndroidRuntime(265): at com.vidasconcurrentes.goingsocialtwittersignpost.GoingSocialTwitterSignPostActivity.access$0(GoingSocialTwitterSignPostActivity.java:70)
    04-13 20:28:31.911: E/AndroidRuntime(265): at com.vidasconcurrentes.goingsocialtwittersignpost.GoingSocialTwitterSignPostActivity$1.onClick(GoingSocialTwitterSignPostActivity.java:52)
    04-13 20:28:31.911: E/AndroidRuntime(265): at android.view.View.performClick(View.java:2364)
    04-13 20:28:31.911: E/AndroidRuntime(265): at android.view.View.onTouchEvent(View.java:4179)
    04-13 20:28:31.911: E/AndroidRuntime(265): at android.widget.TextView.onTouchEvent(TextView.java:6541)
    04-13 20:28:31.911: E/AndroidRuntime(265): at android.view.View.dispatchTouchEvent(View.java:3709)
    04-13 20:28:31.911: E/AndroidRuntime(265): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
    04-13 20:28:31.911: E/AndroidRuntime(265): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
    04-13 20:28:31.911: E/AndroidRuntime(265): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
    04-13 20:28:31.911: E/AndroidRuntime(265): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
    04-13 20:28:31.911: E/AndroidRuntime(265): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1659)
    04-13 20:28:31.911: E/AndroidRuntime(265): at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1107)
    04-13 20:28:31.911: E/AndroidRuntime(265): at android.app.Activity.dispatchTouchEvent(Activity.java:2061)
    04-13 20:28:31.911: E/AndroidRuntime(265): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1643)
    04-13 20:28:31.911: E/AndroidRuntime(265): at android.view.ViewRoot.handleMessage(ViewRoot.java:1691)
    04-13 20:28:31.911: E/AndroidRuntime(265): at android.os.Handler.dispatchMessage(Handler.java:99)
    04-13 20:28:31.911: E/AndroidRuntime(265): at android.os.Looper.loop(Looper.java:123)
    04-13 20:28:31.911: E/AndroidRuntime(265): at android.app.ActivityThread.main(ActivityThread.java:4363)
    04-13 20:28:31.911: E/AndroidRuntime(265): at java.lang.reflect.Method.invokeNative(Native Method)
    04-13 20:28:31.911: E/AndroidRuntime(265): at java.lang.reflect.Method.invoke(Method.java:521)
    04-13 20:28:31.911: E/AndroidRuntime(265): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
    04-13 20:28:31.911: E/AndroidRuntime(265): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
    04-13 20:28:31.911: E/AndroidRuntime(265): at dalvik.system.NativeStart.main(Native Method)
    04-13 20:28:31.931: I/dalvikvm(265): threadid=7: reacting to signal 3
    04-13 20:28:31.931: E/dalvikvm(265): Unable to open stack trace file ‘/data/anr/traces.txt': Permission denied

    ahi esta el log…. y no se que puede ser…!!! revise el codigo y descargue el ejemplo y aun asi no me funciona… help!+

  5. Hola lectores,

    ahora mismo no dispongo del tiempo suficiente para poder investigar todas las actualizaciones que Twitter va incorporando a sus conexiones (como el PIN, que no puedo ayudar con ello porque en el momento que hice la entrada no existía tal PIN).

    Sin embargo, y en vista de que existen dificultades (y es cierto, a mi también me representó dificultad) he incorporado al final de la entrada un link para descargar el proyecto que yo hice para crear esta entrada.

    ¡Espero que sirva de ayuda! Ahora mismo no puedo ofreceros más :/

  6. Buen ejemplo y bien explicado.
    Pero me surge un problema, cuando llega la hora de autentificar desde el telefono, twitter me da un pin… que hago con el???

  7. No entiendo muy bien lo del callback

    ejemplo:

    en twitter me dieron este

    http://ejemplo1.com

    En la actividad pongo esta variable

    private static final String CALLBACK_URL = “http://ejemplo1.com”;

    y por ultimo en el manifest pongo esto
    data android:scheme=”app” android:host=”ejemplo1.com” />

    estoy en lo correcto o ando mal en algo ??? es que despues de poner la contraseña me regresa a la aplicacion pero no se desactiva el boton “botonAutorizar”

    ocea que esta linea no se esta ejecutando
    por ke me envia al cath

    String verifier = uri.getQueryParameter(oauth.signpost.OAuth.OAUTH_VERIFIER);

    • El tema del Callback es algo complejo. Mi recomendación es que utilices algo como lo que yo puse en la entrada: app://goingsocial.
      De esta forma te evitas el .com del final y sabes que el scheme es app. Es importante entender que el Callback no es más que un dummy que se pone ahí para que escuchemos a qué URL quieren ir, y si es nuestro Callback entonces lo interceptamos.

      De todas formas, recuerda usar LogCat para comprobar todos los errores que pudieran surgir al ejecutar.

      Un saludo!

  8. Hola! son geniales tus posts sobre Twitter para Android, el código me funciona OK pero estoy teniendo problemas cdo pulso el boton autorizar, me abre el navegador donde aparece el nombre de mi app y entro mis datos de usuario de twitter pero al regresar a la app Android me da este error: “Request token or token secret not set in server reply. The service provider you use is probably buggy”. Tienes alguna idea de que puede ser? Me ayudarias un monton… Gracias!