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>