Sunday, April 3, 2011

Диалог авторизации Twitter OAuth клиента

Приветствую.

В этот раз, этот пост можно считать небольшой заметкой к продолжению темы OAuth и Twitter, осилим вместе!.

Я хотел бы поделиться тем, как я реализовал диалог общения пользователя моего приложения с Twitter, с целью авторизации приложения пользователем.

С чего начать?
Начнем, как всегда, с малого. Первое, что нам потребуется, это организовать интерфейс между частью программы, отвечающую за реализацию Twitter API, запросы по сути, и частью - диалогом авторизации. И так, какие вариации исхода работы пользователя с нашим диалогом? Успех, ошибка или отмена. В нашем случае, ошибка и отмена одно и тоже, так что, сведем к успеху и отмене. Перейдем к реализации:

public interface OAuthDialogListener {
public abstract void onAllow(String pin);
public abstract void onDeny();
}

Вы могли заметить, что onAllow имеет параметр pin. PIN это код, которые пользователь увидит на странице twitter после успешной авторизации приложения.

Диалог. Проще - лучше!
Глупо заставлять пользователя делать какие то махинации, которые мы, как разработчики, могли бы автоматизировать. Хотя очень часто наблюдаем совсем противоположное поведение различных приложений. Значит, от диалога нам потребуется:
  1. Отображение веб страницы twitter для поэтапного прохода авторизации пользователя и приложения;
  2. Получение PIN с веб страницы, при успешной авторизации приложения;
  3. Отработка событий отмены и успеха в процессе авторизации приложения пользователем;
Кажется все учли, так что, можем приступать к делу.

public class OAuthDialogActivity extends Activity {
public static OAuthDialogListener passOAuthDialogListener = null;

private WebView webView;
private String oauthToken;

private OAuthDialogListener dialogListener = null;
}

Диалог будет основан на Activity, так же объявим публичный статичный listener, для передачи как аргумент при создании диалога в будущем, к сожалению у Intent проблемы с передачей объектов такого рода. Далее, нам потребуется oauth_token для формирования нужной url авторизации, а так же родной listener и webView, для отображения и прохождения всех этапов авторизации приложения.

Продолжим, попробуем реализовать создание и подготовку нашего диалога:

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

dialogListener = passOAuthDialogListener;

webView = new WebView(this);
setContentView(webView);
WebSettings webSettings = webView.getSettings();
webSettings.setSavePassword(false);
webSettings.setSaveFormData(false);
webSettings.setJavaScriptEnabled(true);
webSettings.setBuiltInZoomControls(true);
webSettings.setSupportMultipleWindows(false);
    webSettings.supportZoom();

webView.setWebViewClient(new TwitterWebViewClient());
webView.addJavascriptInterface(new TwitterOAuthJavaScriptInterface(), "twitterOAuth");

Bundle bundle = getIntent().getExtras();
oauthToken = bundle.getString("oauth_token");

webView.loadUrl("http://api.twitter.com/oauth/authorize?oauth_token=" + oauthToken);
}

По порядку:
  • Запомним аргумент listener;
  • Создадим webView и установим как основной View нашего диалога (Activity);
  • Заполним WebSettings так, чтобы само устройство не запоминало никаких паролей и имен, так же нам потребуется JavaScript, включим его тоже;
  • Установим наш клиент-обработчик webView, о нем дальше;
  • Добавим наш JavaScript (twitterOAuth) для работы с html страницами;
  • Получаем oauth_token как аргумент диалога;
  • Загружаем первый шаг авторизации используя полученный oauth_token;
Думаю, тут ничего особо трудного и не понятного нет, так что продолжим:

private class TwitterWebViewClient extends WebViewClient {
@Override
public void onPageFinished(WebView view, String url) {
view.loadUrl("javascript:window.twitterOAuth.complete(document.getElementById('oauth_pin').innerHTML);");
view.loadUrl("javascript:window.twitterOAuth.denied(document.getElementsByTagName('html')[0].innerHTML);");
super.onPageFinished(view, url);
}
}

Здесь еще проще, по готовности страницы в webView, мы выполняем методы нашего JavaScript, причем, передаем элемент oauth_pin, а во втором случае, весь текст html страницы. Зачем? Если oauth_pin существует на странице, это говорит об успешности авторизации, а так же, данный элемент содержит нужный нам PIN. Что касается второго метода, нам нужна вся страница для поиска строки, которая говорила бы об отмене для текущего токена.

JavaScript -> Java
Наступило время для обработки методов JavaScritp в нашем коде. Как было раньше написано, сейчас опишем класс-javascript, который реализует наши два метода успеха и отмены:

private class TwitterOAuthJavaScriptInterface {
@SuppressWarnings("unused")
public void complete(String pin) {
if (dialogListener != null) {
dialogListener.onAllow(pin);
}
finish();
}

@SuppressWarnings("unused")
public void denied(String html) {
if (html.indexOf("oob?denied=" + oauthToken) > 0) {
if (dialogListener != null) {
dialogListener.onDeny();
}
finish();
}
}
}

Twitter Helper - Authorize
Не забудем добавить метод в наш Twitter API Helper класс, а именно, метод вызова диалога с пользовательским listener:

public static void authorize(Context context, String oauthToken, OAuthDialogListener listener) {
OAuthDialogActivity.passOAuthDialogListener = listener;
Intent intent = new Intent(context, OAuthDialogActivity.class);
intent.putExtra(OAUTH_TOKEN, oauthToken);
context.startActivity(intent);
}

Устанавливаем публичный статический аргумент диалога, создаем Intent с классом диалога, добавляем аргумент oauthToken (OAUTH_TOKEN - константа String, можете описать как вам нравится), далее запускаем наш диалог (activity).

Конечно же, не забываем, мы работаем в Android, и каждый новый activity должен быть описан в AndroidManifest.xml, а значит добавляем такую секцию:

<uses-permission android:name="android.permission.INTERNET" />

<activity android:name="com.fuhu.twitter.activity.OAuthDialogActivity"
android:noHistory="true">
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

Удачи в ваших личных начинаниях.

No comments:

Post a Comment