Blog technique sur mes expériences de développeur.
25 janvier 2015
Il y a plusieurs mois, je vous proposais un tutoriel permettant de mettre en place le Facebook Connect au sein de votre application Android.
Généralement, le trio Facebook, Twitter et Google+ est proposé afin de pouvoir se connecter à un service via une application tierce. Aujourd’hui, nous allons donc nous attaquer l’intégration du Twitter OAuth dans une application Android.
A l’image de ce que nous avions fait pour mettre en place le Facebook Connect dans le précédent article, nous allons également, dans le cas de Twitter, associer notre application Android à une application Twitter.
Pour ce faire, rendez-vous sur la partie du site de Twitter dédiée aux applications, et cliquez sur le bouton Create New App.
Un formulaire s’ouvre alors vous demandant de renseigner les premières informations relatives à votre application :
A noter que dans le cadre d’une application mobile comme celle que nous allons mettre en place dans ce tutoriel, l’URL de Callback ne sera pas utilisé, aussi, vous pouvez par exemple y dupliquer l’URL du site internet associé à votre application.
Voici par exemple le formulaire rempli de l’application créée dans le cadre de ce tutoriel :
Une fois le formulaire rempli, acceptez les conditions d’utilisation puis cliquez sur Create your Twitter application.
Vous devriez alors être automatiquement redirigé vers le tableau de bord de votre application comme en témoigne la capture d’écran ci-dessous :
A partir de ce tableau de bord, nous allons être en mesure de modifier et/ou affiner les paramètres de notre application comme par exemple :
La première chose à faire est de se rendre dans l’onglet Settings afin de cocher la case Allow this application to be used to Sign in with Twitter. Dans cette option cochée, nous serions pas en mesure de mettre en place le Twitter OAuth dans notre application Android. N’oubliez pas de valider le changement en cliquant que le bouton Update Settings en bas de page.
Finalement, nous allons changer les droits de notre application pour lui permettre de tout faire. Aussi, nous ne serons pas embêter par la suite. Rendez-vous dans l’onglet Permissions* et cochez l’option Read, Write And Access direct messages. Une nouvelle fois, n’oubliez pas de valider le changement en cliquant que le bouton Update Settings en bas de page.
Maintenant que notre application Twitter est configurée, nous allons pouvoir attaquer le développement de notre application Android.
Dans Android Studio, créez alors un nouveau projet Android grâce à l’assistant graphique.
Lorsque nous avions mis en place le Facebook Connect dans un précédent article, nous avions utilisé le SDK Facebook officiel. Dans le cadre de la mise en place du Twitter OAuth, nous n’allons pas utiliser de SDK officiel, mais la bibliothèque Opensource twitter4j (comprendre Twitter for java).
Cette bibliothèque étant disponible sur Maven Central, il convient d’ajouter la ligne suivante à la section dependencies de votre fichier build.gradle pour pouvoir importer et utiliser la bibliothèque dans votre projet :
compile 'org.twitter4j:twitter4j-core:4.0.+'
Notez que si nous allons utiliser cette bibliothèque uniquement pour mettre en place le Twitter OAuth dans notre application, elle est en réalité capable de faire beaucoup plus, comme par exemple :
Maintenant que l’unique bibliothèque que nous allons utiliser est en place, nous allons pouvoir nous attaquer à la programmation Android !
Maintenant que notre application est en place, nous allons mettre en place le Twitter OAuth à proprement parlé au sein de notre application Android. Mais avant ça, il nous reste encore quelques petites configurations à faire.
Tout d’abord, nous devons autoriser notre application à accéder à internet. Aussi, il convient de rajouter les lignes suivantes dans le fichier AndroidManifest.xml
de votre application Android :
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Nous allons également rajouter les clefs relatives à l’application Twitter que nous avons créé plus tôt dans ce tutoriel dans le fichier strings.xml
. Aussi, il convient d’ajouter les champs suivants :
Ces deux informations sont disponibles dans l’onglet Keys And Access Tokens de votre application Twitter :
Au niveau du fichier strings.xml
, vous devriez alors avoir quelque chose comme ça :
<string name="consumer_key">88********</string>
<string name="consumer_secret">UM*****</string>
Nous allons faire les choses très simplement, ainsi, je remplace juste la TextView affichant “Hello world” qui a été générée automatiquement un bouton :
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
>
<Button
android:id="@+id/twitterConnect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Se connecter via Twitter"
/>
</RelativeLayout>
Il ne nous reste ensuite plus qu’à capturer l’évènement du clic au niveau du fragment en implémentant l’interface OnClickListener :
public static class PlaceholderFragment
extends Fragment
implements OnClickListener
{
public PlaceholderFragment()
{
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
final View rootView = inflater.inflate(R.layout.fragment_main, container, false);
final Button twitterConnect = (Button) rootView.findViewById(R.id.twitterConnect);
twitterConnect.setOnClickListener(this);
return rootView;
}
@Override
public void onClick(View view)
{
//TODO
}
}
Il conviendra donc de lancer le processus de connexion dans la méthode onClick. En attendant, notre application ressemble à ça :
En soit, lancer la connexion à Twitter est très simple puisqu’on la délègue à la plate-forme Twitter. Aussi, il convient simplement de lancer une Activity
un peu personnalisé. Nous allons donc dans un premier temps uniquement nous concentrer sur l’Intent
.
ConfigurationBuilder
La première étape consiste à utiliser un objet ConfigurationBuilder
auquel il convient de renseigner deux choses : la Consumer Key et la **Consumer Secret **.
final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
configurationBuilder.setOAuthConsumerKey(getString(R.string.consumer_key));
configurationBuilder.setOAuthConsumerSecret(getString(R.string.consumer_secret));
TwitterFactory
La seconde étape consiste à obtenir un objet Twitter
. Pour ce faire, nous devons utiliser une TwitterFactory
qui, dans son constructeur, accepte un objet de type Configuration
. Pour obtenir cet objet, il convient Configuration
il convient d’appeler la méthode build()
de notre ConfigurationBuilder
créé lors de l’étape précédente :
final TwitterFactory twitterFactory = new TwitterFactory(configurationBuilder.build());
Finalement, pour obtenir notre objet Twitter
, il convient de faire appel à la méthode getInstance()
de notre TwitterFactory
:
final Twitter twitter = twitterFactory.getInstance();
Intent
Dans cette troisième étape, nous allons afficher le formulaire de connexion à Twitter. Ce formulaire sera affiché dans une WebView
au sein d’une nouvelle Activity
. L’objectif de cette étape est de donc de récupérer l’URL du formulaire à afficher dans la WebView
et passer l’information à la nouvelle Activity
.
Pour obtenir l’URL du formulaire de connexion, il convient de récupérer un objet RequestToken
puis de faire appel à la méthode getAuthenticationURL()
. La récupération de l’objet RequestToken
est possible grâce à la méthode getOAuthRequestToken()
de l’objet Twitter
que nous avons créé dans l’étape précédente.
A noter que nous allons également passer à la méthode getOAuthRequestToken()
une fausse URL de callback, ce qui nous permettra plus tard dans cet article d’intercepter le résultat de la validation du formulaire d’authentification.
Attention ! La méthode getOAuthRequestToken()
lève une exception qu’il convient de traiter correctement !
try
{
final RequestToken requestToken = twitter.getOAuthRequestToken("twitter-callback:///");
final String url = requestToken.getAuthenticationURL();
}
catch (TwitterException exception)
{
exception.printStackTrace();
}
Maintenant que nous avons notre URL, nous pouvons construire notre Intent
:
final Intent intent = new Intent(getActivity(), LoginTwitterActivity.class);
intent.putExtra("AuthenticationURL", url);
Comme vous pouvez le constater, nous passons l’URL dans les extras. L’activité LoginTwitterActivity
n’existe pas pour le moment, mais nous allons la créer dans l’étape suivante.
Finalement, pour terminer cette troisième étape, il convient d’appeler la méthode startActivityForResult()
. En effet, cela nous permettra de vérifier si l’utilisateur est bien connecté dans la méthode onActivityResult()
du fragment.
La méthode startActivityForResult()
prend deux paramètres : l’Intent
et un code de requête, ce qui nous permettra d’identifier notre retour dans la méthode onActivityResult()
du fragment, par exemple le nombre 3. :)
Vous devriez alors avoir quelque chose comme ça :
startActivityForResult(intent, 3);
Finalement, tout le code que nous venons d’écrire ne doit pas s’exécuter dans le thread de l’UI car des requêtes réseaux sont faites. Il convient alors d’encapsuler tout ça dans une AsyncTask
ou un Thread
. J’ai choisi d’utiliser un Thread
. Mon code est alors le suivant :
new Thread(new Runnable()
{
@Override
public void run()
{
final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
configurationBuilder.setOAuthConsumerKey(getString(R.string.consumer_key));
configurationBuilder.setOAuthConsumerSecret(getString(R.string.consumer_secret));
final TwitterFactory twitterFactory = new TwitterFactory(configurationBuilder.build());
final Twitter twitter = twitterFactory.getInstance();
try
{
final RequestToken requestToken = twitter.getOAuthRequestToken("twitter-callback:///");
final String url = requestToken.getAuthenticationURL();
final Intent intent = new Intent(getActivity(), LoginTwitterActivity.class);
intent.putExtra("AuthenticationURL", url);
startActivityForResult(intent, 3);
}
catch (TwitterException exception)
{
exception.printStackTrace();
}
}
}).start();
Si l’on souhaite être vraiment propre, il convient d’afficher des loaders pour montrer à l’utilisateur que l’application tourne !
Nous allons donc nous attaquer à la création du formulaire d’authentification. Comme je vous le disais précédemment, il s’agit en réalité tout simplement d’une Activity
(ou d’un Fragment
) qui affiche le fameux formulaire dans une WebView
.
A l’image de notre MainActivity
, je vous propose de créer une LoginTwitterActivity
qui porte un LoginTwitterFragment
:
public class LoginTwitterActivity
extends Activity
{
public static class LoginTwitterFragment
extends Fragment
{
public LoginTwitterFragment()
{
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
final View rootView = inflater.inflate(R.layout.fragment_login_twitter, container, false);
return rootView;
}
}
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null)
{
getFragmentManager().beginTransaction().add(R.id.container, new LoginTwitterFragment()).commit();
}
}
}
Concernant les layouts, celui de LoginTwitterActivity
est le même que MainActivity
, à savoir :
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
tandis que celui de LoginTwitterFragment
ressemble à ça :
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<WebView
android:id="@+id/loginWebView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
Finalement, n’oubliez pas de déclarer cette nouvelle Activity
dans votre fichier AndroidManifest.xml
:
<activity android:name=".LoginTwitterActivity" />
Dans le LoginTwitterFragment
, il convient maintenant de récupérer la référence de notre WebView
et de lui demander de charger l’URL permettant d’accéder au formulaire d’authentification. Pour cela, rendez-vous dans la méthode onCreateView()
du fragment :
final View rootView = inflater.inflate(R.layout.fragment_login_twitter, container, false);
final WebView webview = (WebView) rootView.findViewById(R.id.loginWebView);
final String url = getActivity().getIntent().getStringExtra("AuthenticationURL");
webview.loadUrl(url);
return rootView;
Finalement, avant de lancer le chargement de l’URL, nous allons donner à notre webView un WebViewClient
pour empêcher que le formulaire ne s’ouvre en dehors de l’application. Dans un premier temps, nous n’allons pas surcharger de méthodes :
webview.setWebViewClient(new WebViewClient()
{
});
Si nous exécutions notre application à ce stade et que nous cliquons sur le bouton Se connecter via Twitter, vous devriez voir apparaître le formulaire à l’écran :
Notre URL de callback définie plus tôt dans le cas sera maintenant appelée lorsque l’utilisateur sera identifié ou lorsqu’il cliquera sur le bouton Annuler du formulaire. Il convient donc de surcharger la méthode shouldOverrideUrlLoading()
de notre WebViewClient
pour intercepter l’appel à la callback et rediriger l’utilisateur vers le précédent écran avec le résultat de l’authentification. La surchage de la méthode shouldOverrideUrlLoading()
doit alors ressembler à ça :
webview.setWebViewClient(new WebViewClient()
{
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
if (url.contains("twitter-callback:///") == true)
{
//TODO
return true;
}
return false;
}
});
Dans l’url que nous venons de filtrer, il convient maintenant de récupérer le paramètre oauth_verifier :
final Uri uri = Uri.parse(url);
final String oauthVerifierParam = uri.getQueryParameter("oauth_verifier");
Nous allons maintenant créer une Intent
à retourner à l’écran précédent dans laquelle il convient de donner en extra le paramètre oauth_verifier. Une fois l’Intent
renvoyé, nous pouvons fermer l’écran en cours.
final Intent intent = new Intent();
intent.putExtra("oauth_verifier", oauthVerifierParam);
getActivity().setResult(RESULT_OK, intent);
getActivity().finish();
Le code complet devrait donc être le suivant :
webview.setWebViewClient(new WebViewClient()
{
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
if (url.contains("twitter-callback:///") == true)
{
final Uri uri = Uri.parse(url);
final String oauthVerifierParam = uri.getQueryParameter("oauth_verifier");
final Intent intent = new Intent();
intent.putExtra("oauth_verifier", oauthVerifierParam);
getActivity().setResult(RESULT_OK, intent);
getActivity().finish();
return true;
}
return false;
}
});
Nous allons maintenant vérifier que notre utilisateur s’est connecté ou non via son compte Twitter. Pour ce faire, il convient de revenir dans notre MainActivity
et plus précisément dans notre PlaceholderFragment
dans lequel nous allons surcharger la méthode onActivityResult()
:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
}
La première étape consiste à vérifier que le requestCode
est bien celui que nous avions envoyé à savoir 3 et que le resultCode
est OK :
if(resultCode == Activity.RESULT_OK && requestCode == 3)
{
//TODO
}
Nous allons maintenant récupérer l’extra oauth_verifier. S’il est différent de null
, c’est que l’authentification de l’utilisateur a réussi :
if (oauthVerifierParam != null)
{
//TODO
}
else
{
Toast.makeText(getActivity(), "Erreur d'identification", Toast.LENGTH_SHORT).show();
}
Si l’extra oauth_verifier n’est pas null
, nous sommes alors en mesure de récupérer des tokens qui nous permettront par la suite de récupérer les informations de l’utilisateur. Pour le moment, afin de récupérer les tokens, il convient que nous puissons réutiliser notre précédent objet Twitter
. Il convient donc d’en faire un attribut de notre fragment. Ensuite, nous pourrons appeler la méthode getOAuthAccessToken()
qui prend en paramètre notre fameux oauth_verifier. Elle nous renvoie alors un objet AccessToken
:
try
{
final AccessToken accessToken = twitter.getOAuthAccessToken(oauthVerifierParam);
}
catch (TwitterException exception)
{
exception.printStackTrace();
}
Depuis ce nouvel objet AccessToken
nous sommes alors en mesure de récupérer le nom de l’utilisateur grâce à la méthode getScreenName()
:
final String name = accessToken.getScreenName();
Toast.makeText(getActivity(), "Bonjour " + name, Toast.LENGTH_SHORT).show();
Une nouvelle fois, il convient de faire quelque modification au code écrit précédemment pour ne pas faire d’appels réseaux dans le thread de l’UI. Notre méthode onActivityResult
devient alors :
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (resultCode == Activity.RESULT_OK && requestCode == 3)
{
final String oauthVerifierParam = data.getStringExtra("oauth_verifier");
if (oauthVerifierParam != null)
{
new Thread(new Runnable()
{
@Override
public void run()
{
try
{
final AccessToken accessToken = twitter.getOAuthAccessToken(oauthVerifierParam);
final String name = accessToken.getScreenName();
getActivity().runOnUiThread(new Runnable()
{
@Override
public void run()
{
Toast.makeText(getActivity(), "Bonjour " + name, Toast.LENGTH_SHORT).show();
}
});
}
catch (TwitterException exception)
{
exception.printStackTrace();
}
}
}).start();
}
else
{
Toast.makeText(getActivity(), "Erreur d'identification", Toast.LENGTH_SHORT).show();
}
}
super.onActivityResult(requestCode, resultCode, data);
}
Si vous lancez l’application et que vous vous identifiez via le formulaire, vous devriez alors voir votre nom d’utilisateur s’afficher à l’écran comme en témoigne la capture d’écran ci-dessous :
Il est bien évidemment possible de reconnecter automatiquement un utilisateur au démarrage de votre application par exemple. Pour ce faire, il convient en réalité de construire un objet Twitter
comme nous l’avons fait un début de ce tutoriel à un détail prêt : il convient de fournir au ConfigurationBuilder
un AccessToken ainsi qu’un AccessTokenSecret. Ces deux tokens sont récupérables directement après la dernière connexion de l’utilisateur, grâce aux méthodes getToken()
et getTokenSecret()
de l’objet AccessToken
. Il convient donc de stocker des informations dans les préférences de l’application pour connecter automatiquement votre utilisateur et récupérer ses informations de profil.
Pour la déconnexion de l’utilisateur, il convient de supprimer des préférences les fameux AccessToken et AccessTokenSecret et de recommencer le processus de conexion pour en générer de nouveaux.
Le projet Android créé pour la rédaction de cet article est disponible sur Github.