Monday, April 18, 2011

Интегрируем Twitter в ваше Android приложение




Начав писать свою небольшую игрушку для гуглофона, захотелось отправлять рекорды в твиттер. Как оказалось на просторах интернета есть множество статей по поводу подключения к вашему аккаунту в твиттере, но рабочих примеров крайне мало. Немного усилий и я нашел нужный мне код, который оказался вполне работоспособен. Что ж, приступим к интеграции.

С недавнего времени Twitter использует OAuth протокол для авторизации. И так нам необходимо авторизироваться использую этот протокол. И собственно говоря, отправить сообщение прямиком в наш микроблог. Для этого я решил использовать следующие библиотеки:
signpost library для непосредственного использования механизма OAuth, Twitter4J library для отправки твитов.



Стартуем


И так нам понадобиться рабочий Twitter аккаунт ( если его у вас нет, зарегистрируйтесь вот тут ). Далее нам потребуется зарегистрировать наше тестовое приложение для взаимодействия с Twitter'ом. И так идем вот сюда
Теперь заполняем нужные поля, важно нам только следующее, тип приложения(Application Type) — Browser, Default Access type — Read & Write. Остальное заполняем произвольным образом, но помня о формате вводимых данных (не пытаемся ввести в URL & callback URL что-то по типу &*^&JKLLKL:, вводите все как следует).
image
Как только заполнили все поля, ввели капчу — увидим следующий текст.

Consumer key
************************ ( набор символов )
Consumer secret
************************ ( набор символов )
Request token URL
api.twitter.com/oauth/request_token
Access token URL
api.twitter.com/oauth/access_token
Authorize URL
api.twitter.com/oauth/authorize
Registered OAuth Callback URL
smth.com

Да, этот callback в нашем приложении мы использовать не будем, там мы поступим немного по-другому а определим свой собственный callback.

Начинаем писать приложение

И так нам понадобятся следующие библиотеки:
  • signpost-commonshttp4-1.2.1.1.jar
  • signpost-core-1.2.1.1.jar
  • httpclient-4.0.1.jar
  • twitter4j-core-2.1.11

image
image
И так теперь у нас есть соотв. библиотеки.
В итоге набросаем небольшой план, как будет выглядеть наше приложение. Для простоты примера будет лишь 1 Activity.
  • строка статуса, которая отображает подключились мы к твиттеру или нет
  • кнопка Tweet, которая собственно постит наше тестовое сообщение, а если мы не залогинены, то открывает браузер, в котором мы залогиниваемся
  • фомально выходит из твиттера, очищая предыдущие настройки ( а вдруг какое-то еще приложение задействует аккаунт)

image

Файл констант

В этом файлике определим нужные нам константы для коннекта.
public class Constants {

public static final String CONSUMER_KEY = "< тут CONSUMER KEY >";
public static final String CONSUMER_SECRET= "<тут CONSUMER SECRET >";

public static final String REQUEST_URL = "http://api.twitter.com/oauth/request_token";
public static final String ACCESS_URL = "http://api.twitter.com/oauth/access_token";
public static final String AUTHORIZE_URL = "http://api.twitter.com/oauth/authorize";

final public static String CALLBACK_SCHEME = "x-latify-oauth-twitter";
final public static String CALLBACK_URL = CALLBACK_SCHEME + "://callback";

}


Приведу схему по которой происходит взаимодействие между твиттером и приложением.
image

CONSUMER_KEY — уникальный ключ для нашего приложения, получаем как только зарегистрировали наше приложение (что-то наподобие логина)
CONSUMER_SECRET — секретный ключ для нашего приложения (что-то наподобие пароля для «логина»)
REQUEST_URL — нужен для получения request token. Часть OAuth. Получаем сразу после регистрации.
AUTHORIZE_URL — URL необходимый для получения доступа к твиттеру. Часть OAuth. Получаем сразу после регистрации.
ACCESS_URL — для получения access token. Часть OAuth. Получаем сразу после регистрации.
CALLBACK SCHEME ункальный индетификатор который мы используем, как callback для получения access token. Вобще говоря выбор схемы ничем не ограничивается. Для примеры будем использовать x-sample-oauth-twitter here.
CALLBACK_URL — собственно наш callback с помощью которого мы получив ответ, на что авторизация прошла успешно, можем посылать нужные нам запросы с помощью access token.

Твит кнопка


tweet.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (TwitterUtils.isAuthenticated(prefs)) {
sendTweet();
} else {
Intent i = new Intent(getApplicationContext(), PrepareRequestTokenActivity.class);
i.putExtra("tweet_msg",getTweetMsg());
startActivity(i);
}
}
});


Здесь все просто, наша кнопка просто проверяет залогинен ли пользователь, если все ок, то посылаем наше сообщение, если нет то предлагает нам залогиниться в браузере. Для этого используем PrepareRequestTokenActivity. Процесс логина чуть позже.

Аутенфикация

Рассмотрим сначала ситуацию, мы с вами ( user ) еще не прошел процесс аутенфикации. До того как мы сможем посылать наши сообщения, нас редиректит в браузере на страничку входа в аккаунт твиттера. Это реализовано с помощью PrepareRequestTokenActivity.
Рассмотрим какие классы нам для этого понадобятся.

PrepareRequestTokenActivity — Устанавливает OAuth пользоветеля и поставщика (Signpost library)и старутет асинхронный OAuthRequestTokenTask. Так же содержит callback, когда мы уже прошли аутенфикацию для получения access token.
OAuthRequestTokenTask — отвечает за получение request token, и вызов браузера, в котором мы собственно и проходим аутенфикацию.
RetrieveAccessTokenTask — внутренний класс PrepareRequestTokenActivity. Вызывается методомon NewIntent вунтри PrepareRequestTokenActivity. Хранит наши полученные token'ы после авторизации.

PrepareRequestTokenActivity и вызов асинхронного OAuthRequestTokenTask
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
this.consumer = new CommonsHttpOAuthConsumer(Constants.CONSUMER_KEY, Constants.CONSUMER_SECRET);
this.provider = new CommonsHttpOAuthProvider(Constants.REQUEST_URL,Constants.ACCESS_URL,Constants.AUTHORIZE_URL);
} catch (Exception e) {
Log.e(TAG, "Error creating consumer / provider",e);
}

Log.i(TAG, "Starting task to retrieve request token.");
new OAuthRequestTokenTask(this,consumer,provider).execute();
}


Здесь мы и получаем наш callback URL, чтобы вернуть управление приложению (x-oauthflow-twitter://callback).
@Override
protected Void doInBackground(Void... params) {

try {
Log.i(TAG, "Retrieving request token from Google servers");
final String url = provider.retrieveRequestToken(consumer, Constants.OAUTH_CALLBACK_URL);
Log.i(TAG, "Popping a browser with the authorize URL : " + url);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)).setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_FROM_BACKGROUND);
context.startActivity(intent);
} catch (Exception e) {
Log.e(TAG, "Error during OAUth retrieve request token", e);
}

return null;
}



Страница логина

И так мы находимся на странице логина.
Для того, чтобы браузер запустился следует зарегистрировать наше Activity (PrepareRequestTokenActivity) в файле манифеста (AndroidManifest.xml)
>







image
Продолжаем работу. Теперь нам надо получить access token для доступа к нашему микроблогу, производим это через RetrieveAccessTokenTask. Вызывается который уже упомянутым выше методом onNewIntent.
@Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
final Uri uri = intent.getData();
if (uri != null && uri.getScheme().equals(Constants.OAUTH_CALLBACK_SCHEME)) {
Log.i(TAG, "Callback received : " + uri);
Log.i(TAG, "Retrieving Access Token");
new RetrieveAccessTokenTask(this,consumer,provider,prefs).execute(uri);
finish();
}
}



Теперь когда все на месте, надо учесть что нужно сохранить нашу сессию, т.е. если даже мы перезапустили приложение нам не надо заново проходить авторизацию, для этого напишем функцию которая хранит все наши значения в фоне.
@Override
protected Void doInBackground(Uri...params) {
final Uri uri = params[0];
final String oauth_verifier = uri.getQueryParameter(OAuth.OAUTH_VERIFIER);

try {
provider.retrieveAccessToken(consumer, oauth_verifier);

final Editor edit = prefs.edit();
edit.putString(OAuth.OAUTH_TOKEN, consumer.getToken());
edit.putString(OAuth.OAUTH_TOKEN_SECRET, consumer.getTokenSecret());
edit.commit();

String token = prefs.getString(OAuth.OAUTH_TOKEN, "");
String secret = prefs.getString(OAuth.OAUTH_TOKEN_SECRET, "");

consumer.setTokenWithSecret(token, secret);
context.startActivity(new Intent(context,AndroidTwitterSample.class));

executeAfterAccessTokenRetrieval();

Log.i(TAG, "OAuth - Access Token Retrieved");

} catch (Exception e) {
Log.e(TAG, "OAuth - Access Token Retrieval Error", e);
}

return null;
}


Метод executeAfterAccessTokenRetrieval неспоредственно извлекает наше сообщение и проводит его по процедуре аутенфикации с помощью OAuth.
private void executeAfterAccessTokenRetrieval() {
String msg = getIntent().getExtras().getString("tweet_msg");
try {
TwitterUtils.sendTweet(prefs, msg);
} catch (Exception e) {
Log.e(TAG, "OAuth - Error sending to Twitter", e);
}
}


Ну и не забудем оповестить пользователя о успешном выполнении нашей задачи. напишем простенький toast для этого.
private final Handler mTwitterHandler = new Handler();

final Runnable mUpdateTwitterNotification = new Runnable() {
public void run() {
Toast.makeText(getBaseContext(), "Tweet sent !", Toast.LENGTH_LONG).show();
}
};


Само сообщение посылается с помощью методов библиотеки Twitter4J.
public static void sendTweet(SharedPreferences prefs,String msg) throws Exception {
String token = prefs.getString(OAuth.OAUTH_TOKEN, "");
String secret = prefs.getString(OAuth.OAUTH_TOKEN_SECRET, "");

AccessToken a = new AccessToken(token,secret);
Twitter twitter = new TwitterFactory().getInstance();
twitter.setOAuthConsumer(Constants.CONSUMER_KEY, Constants.CONSUMER_SECRET);
twitter.setOAuthAccessToken(a);
twitter.updateStatus(msg);
}


Перевод туториала:
blog.doityourselfandroid.com/2011/02/13/guide-to-integrating-twitter-android-application/
с дальнейшим проведением проверки работоспособности.
Использовалось:

А так же исходники автора англоязычной статьи, надеюсь они помогут полностью понять описанный процесс — гитхаб ссылка