AndroidでTwitter4jを使用した、OAuth認証と認証解除
OAuth認証のサンプルはよく見かけるのですが、解除がなかったのでメモ。
(正しいかどうかは不明です・・・)
以下、ソース(エラー処理とか省く)
定数
public final class Const { public static final String CONSUMER_KEY = "xxxxx"; public static final String CONSUMER_SECRET = "xxxxx"; public static final String OAUTH_CALLBACK_URL = "myapp://callback"; // コールバック public static final String OAUTH_VERIFIER = "oauth_verifier"; public static final String OAUTH_URL = "oauth_url"; public static final String OAUTH_CHECK_TEXT = "https://api.twitter.com/oauth/authorize"; // Twitterのウェブサイトで認証or解除をしたかの確認文字列 }
認証開始のActivity
public class OAuthActivity extends Activity { private Twitter twitter = null; private RequestToken requestToken = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.oauth); // button Button oauthButton = (Button)findViewById(R.id.oauth_button); oauthButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { doOAuth(); } }); setView(); } // 画面処理 private void setView(){ TextView nameText = (TextView)findViewById(R.id.nameTextView); ImageView iconImage = (ImageView)findViewById(R.id.iconImageView); Button oauthButton = (Button)findViewById(R.id.oauth_button); OAuth oAuth = loadOAuth(); if (oAuth.isEmpty()) { oauthButton.setText("アプリ認証"); nameText.setText(""); iconImage.setImageBitmap(null); } else { oauthButton.setText("アプリ認証解除"); nameText.setText(oAuth.name); new ImageTask(iconImage).execute(oAuth.imageUrl); // Twitterアイコン読み込み } } // Twitter認証 private void doOAuth() { ConfigurationBuilder confbuilder = new ConfigurationBuilder(); confbuilder.setOAuthConsumerKey(CONSUMER_KEY).setOAuthConsumerSecret(CONSUMER_SECRET); twitter = new TwitterFactory(confbuilder.build()).getInstance(); try { requestToken = twitter.getOAuthRequestToken(OAUTH_CALLBACK_URL); } catch (TwitterException e) { // エラー } // ブラウザ起動 Intent intent = new Intent(this, OAuthWebActivity.class); intent.putExtra(OAUTH_URL, requestToken.getAuthorizationURL()); startActivityForResult(intent, 0); } // ブラウザからの戻り protected void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); // キャンセル if (resultCode == RESULT_CANCELED) { Toast.makeText(this, "キャンセル", Toast.LENGTH_LONG).show(); return; } // 認証or認証解除 if (resultCode == RESULT_OK){ String verifier = intent.getExtras().getString(OAUTH_VERIFIER); if (!TextUtils.isEmpty(verifier)) { // verifierがあれば認証 try { AccessToken accessToken = twitter.getOAuthAccessToken(requestToken, verifier); // user取得 User user = twitter.verifyCredentials(); saveOAuth(new OAuth(user.getScreenName(), user.getProfileImageURL().toString(), accessToken.getToken(), accessToken.getTokenSecret())); setView(); Toast.makeText(this, "認証OK", Toast.LENGTH_LONG).show(); } catch (TwitterException e) { // エラー } } else { // 認証解除 if (!loadOAuth().isEmpty()) { Toast.makeText(this, "認証解除", Toast.LENGTH_LONG).show(); saveOAuth(new OAuth()); // OAuthクリア } } } } // icon取得 class ImageTask extends AsyncTask<String, Void, Bitmap> { private ImageView iconView; public ImageTask(ImageView iconView) { this.iconView = iconView; } @Override protected void onPreExecute() { // progress表示 } @Override protected Bitmap doInBackground(String... params) { try { String url = params[0].toString(); URL imageUrl = new URL(url); Bitmap bitmap = BitmapFactory.decodeStream(imageUrl.openStream()); return bitmap; } catch (Exception e) { return null; } } @Override protected void onPostExecute(Bitmap bitmap) { // progress非表示 iconView.setImageBitmap(bitmap); } } // OAuthの保存と取得はPreference用の別クラス等に実装がよい // OAuth保存 private void saveOAuth(OAuth oAuth) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); Editor editor = prefs.edit(); editor.putString(OAuth.NAME, oAuth.name); editor.putString(OAuth.IMAGE_URL, oAuth.imageUrl); editor.putString(OAuth.TOKEN, oAuth.token); editor.putString(OAuth.TOKEN_SECRET, oAuth.tokenSecret); editor.commit(); } // OAuth取得 private OAuth loadOAuth() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); return new OAuth(prefs.getString(OAuth.NAME, ""), prefs.getString(OAuth.IMAGE_URL, ""), prefs.getString(OAuth.TOKEN, ""), prefs.getString(OAuth.TOKEN_SECRET, "")); } }
認証ブラウザActivity
public class OAuthWebActivity extends Activity { private boolean checkFlg = false; protected void onCreate(Bundle bundle) { super.onCreate(bundle); // layout setContentView(R.layout.oauth_web); // webview WebView webView = (WebView)findViewById(R.id.oauth_web_view); webView.getSettings().setJavaScriptEnabled(true); // JavaScript有効 webView.setScrollBarStyle(WebView.SCROLLBARS_INSIDE_OVERLAY); // スクロールバー設定 webView.setWebViewClient(new WebViewClient() { @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { // ページ読み込み開始 super.onPageStarted(view, url, favicon); if (url.startsWith(OAUTH_CALLBACK_URL)) { Uri uri = Uri.parse(url); // verifier取り出し String oauthVerifier = uri.getQueryParameter(OAUTH_VERIFIER); Intent intent = getIntent(); intent.putExtra(OAUTH_VERIFIER, oauthVerifier); if (checkFlg) { // 認証or認証解除 setResult(RESULT_OK, intent); } else { // キャンセルの場合 setResult(RESULT_CANCELED, null); } finish(); } } // ページ読み込み終了 public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); // 認証or認証解除をしたか確認 checkFlg |= url.equals(OAUTH_CHECK_TEXT); } }); // ページ読み込み webView.loadUrl(getIntent().getExtras().getString(OAUTH_URL)); } }
OAuth保持Entity
public class OAuth { public static final String NAME = "oauth_name"; public static final String IMAGE_URL = "oauth_image_url"; public static final String TOKEN = "oauth_token"; public static final String TOKEN_SECRET = "oauth_token_secret"; public String name; public String imageUrl; public String token; public String tokenSecret; public OAuth() { this.name = ""; this.imageUrl = ""; this.token = ""; this.tokenSecret = ""; } public OAuth(String name, String imageUrl, String token, String tokenSecret) { this.name = name; this.imageUrl = imageUrl; this.token = token; this.tokenSecret = tokenSecret; } public boolean isEmpty() { return TextUtils.isEmpty(name); } }
レイアウト:R.layout.oauth_web
<?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" android:id="@+id/main_layout"> <Button android:layout_width="wrap_content" android:id="@+id/oauth_button" android:layout_height="wrap_content"></Button> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/nameTextView"></TextView> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/iconImageView"></ImageView> </LinearLayout>
レイアウト:R.layout.oauth_web
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/oauth_web_layout"> <android.webkit.WebView android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/oauth_web_view"> </android.webkit.WebView> </LinearLayout>
AndroidManifest
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="me.undigital.test" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="4" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name="OAuthActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="OAuthWebActivity" android:label="@string/app_name"> </activity> </application> <uses-permission android:name="android.permission.INTERNET" /> </manifest>