メディア寄りの情報系ブログ

情報系の内容をメディア寄りの観点で紹介します

AndroidStudioでTwitterクライアントを作るPart2_OAuth認証

 

はじめに

さて早速作っていきましょう!

Twitterクライアントを作るうえで必要不可欠な要素…それはツイートする機能!

ですよね,やっぱりメイン機能から作っていきたいですよね.

 

ところがTwitter API を使うためには必要不可欠な要素があります.

それがOAuth認証機能です.

 

ということでじれったいですが,今回はTwitterクライアントを作るうえで必須なOAuth認証に関して書いていきます.

必ずやらなければいけないことなので我慢してやっておきましょう.

 

今回はあるサイトの処理をほぼまんま使わせていただきましたが,勉強の意味を込めて自分なりの解釈を載せておきたいと思います.

 

今回はアプリを初回起動時のみOAuth認証を行い,

2回目以降は承認なくアプリを使えるようにしたいと思います.

 

ちなみに今回の実装が上手くいくとこのような画面が出てきます.

 

f:id:mltmdkana:20161106143633p:plain

 

Twitterやってる人なら一度は見たことのある画面ですよね!

(ちょっとワクワクします)

 

手順

1. string.xmlへの設定書き込み

2. MainActivityへ処理の流れを記述する

3. ユーティリティクラスの作成

4. AndroidManifestのパーミッション設定

5. OAuth認証

 

1. string.xmlへの設定書き込み

 

ではまず,前回の記事のTwitter Developerで取得したconsumer keyとconsumer secret を設定ファイルの代わりにapp/res/values/strings.xml内に記述していきます.

 

・string.xml 

<resources>
<string name="app_name">FiLitter</string>

<string name="navigation_drawer_open">Open navigation drawer</string>
<string name="navigation_drawer_close">Close navigation drawer</string>

<!--追加部分-->
<string name="twitter_consumer_key">consumer key</string>
<string name="twitter_consumer_secret">consumer secret</string>
<string name="twitter_callback_url">test://twitter</string>

<string name="action_settings">Settings</string>
</resources>

 

これでいわゆるeclipceで言うtwitter4j.propatiesファイルの代わりになります.

または専用の設定用クラスを作るのもありだと思います.

以上で設定の書き込みは終了です.

 

2. MainActivityへ処理の流れを記述する

 

次にMainActivityの処理を見てみましょう. 

 各メソッドごとに見てみましょう.

 

・MainActivity onCreate

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

//省略

if(!TwitterUtils.hasAccessToken(this)){
Intent intent = new Intent(getApplication(), TwitterOAuthActivity.class);
startActivity(intent);
finish();
}
}

 

後に紹介するTwitterUtilsクラスのhasAccessTokenメソッドによってアクセストークンを取得(保持)しているかを判定しています.ここで取得していなければアプリケーション認証Activityへ遷移,のちにアクセストークンの取得を行います.

2回目以降(トークン取得後)はこの処理は飛ばしてアプリを利用できるという流れになっています.

複雑になりがちな処理もまずは大きい部分(MainActivity)の処理を見て流れをつかんでおくと良いですね.

 

MainActivityへの記述は以上で終了です.

 

3. ユーティリティクラスの作成

 

Twitterインスタンスを生成するメソッドや,トークンを取得する クラスです.

 

・TwitterUtils.java

package hoge;

import android.content.Context;
import android.content.SharedPreferences;

import twitter4j.Twitter;
import twitter4j.TwitterFactory;
import twitter4j.auth.AccessToken;
import twitter4j.conf.Configuration;

public class TwitterUtils {

//SharedPrerence用のキー
private static final String TOKEN = "token";
private static final String TOKEN_SECRET = "token_secret";
private static final String PREF_NAME = "twitter_access_token";


//Twitterインスタンスの生成
public static Twitter getTwitterInstance(Context context){
//string.xmlで記述した設定の呼び出し
String consumerKey = context.getString(R.string.twitter_consumer_key);
String consumerSecret = context.getString(R.string.twitter_consumer_secret);

//Twitterオブジェクトのインスタンス
TwitterFactory factory = new TwitterFactory();
Twitter twitter = factory.getInstance();
twitter.setOAuthConsumer(consumerKey, consumerSecret);

//トークンの設定
if(hasAccessToken(context)){
twitter.setOAuthAccessToken(loadAccessToken(context));
}
return twitter;
}

//トークンの格納
public static void storeAccessToken(Context context, AccessToken accessToken) {

//トークンの設定
SharedPreferences preferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putString(TOKEN, accessToken.getToken());
editor.putString(TOKEN_SECRET, accessToken.getTokenSecret());

//トークンの保存
editor.commit();
}

//トークンの読み込み
public static AccessToken loadAccessToken(Context context) {

//preferenceからトークンの呼び出し
SharedPreferences preferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
String token = preferences.getString(TOKEN, null);
String tokenSecret = preferences.getString(TOKEN_SECRET, null);
if(token != null && tokenSecret != null){
return new AccessToken(token, tokenSecret);
}
else{
return null;
}
}

//トークンの有無判定
public static boolean hasAccessToken(Context context) {
return loadAccessToken(context) != null;
}
}

 

比較的簡単だと思いますので,そのまま載せちゃいますね.

 コメントアウトを読んでくれれば分かり易いかも??

 

最近,どんな処理なの?と聞かれたときに,プログラムの通りだよとしか説明できなくなってきた気がするというか,良い意味でも悪い意味でもプログラムが読めるようになってきた気がします.

 

以上でユーティリティクラスは完成です.

 

 

4. AndroidManifestのパーミッション設定

次の項目では,URLによってアプリケーションを起動するなど,ネットワークへの接続が必要となりますので,AndroidManifest.xmlファイルへ,パーミッション許可の処理を書く必要があります.

 

・AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="hogehoge">

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

<application
<!--省略-->

 

こんな感じでapplicationタグの上に追加してあげればよいです.

 

5. OAuth認証

 

OAuth認証を行うクラスの作成をします.

今回最も重要な部分ですので頑張りましょう.

 

ここでの処理はURIによるアクティビティの遷移が必要になりますので,先にAndroidManifest.xmlにactivityの登録をしておきます.

 

・AndroidManifest.xml

 

 <application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">

<!--省略-->

<!--OAuth認証用アクティビティ-->
<activity
android:name=".TwitterOAuthActivity"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>

<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>

<data
android:host="twitter"
android:scheme="test" />
</intent-filter>
</activity>
</application>

 

ポイントはlaunchMode="singleTask"になっていることです.こうすることで認証後にonNewIntentが呼ばれ再度MainActivityに戻る処理を実現できるみたいです…

(正直わからないです…)

また,dataタグのschemeは独自のものを指定する必要があるみたいです.

具体的な部分まで説明はできないので,詳しくは本家様のページを参照してみて下さい

 

 

それでは肝心のTwitterOAuthActivityクラスの各メソッドについて説明していきます.

 

・TwitterOAuthActivity onCreate

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

//CallBack用URLの設定
callBackURL = getString(R.string.twitter_callback_url);
//Twitterインスタンスの取得
twitter = TwitterUtils.getTwitterInstance(this);

//認証開始
startAuthorize();
}

 CallBack用URLとTwitterインスタンスの生成を行います.

その後,下で定義するstartAuthorize()によって認証を行います.

 

 

・TwitterOAuthActivity startAuthorize

private void startAuthorize() {
//AsyncTaskによる非同期処理
AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(Void... params) {
try {
//リクエストトークンの取得
requestToken = twitter.getOAuthRequestToken(callBackURL);
return requestToken.getAuthorizationURL();
}catch (TwitterException e){
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String url) {
if (url != null) {
//渡されたurlへアクティビティを遷移する
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
} else {
// 失敗。。。
}
}
};
task.execute();
}

 

AsyncTaskによって非同期処理を行います.

これをしないと NetworkExceptionだったかがでます.一つのスレッドで処理できることに限界があるとかなんとか…?(だれかこの辺教えてほしいです)

 

まあ,とにかくこに非同期処理によってdoInBackground,onPostExcuteの順に処理が呼ばれることになります.

soIntBackgroundでは設定済みのCallBackURLからリクエストトークンを取得し,onPostExcuteへリクエストトークンと一緒にurlを渡します.その後onPostExcuteは認証と同じタイミングで渡されたurlへアクティビティを遷移する…という処理を行います.

 

一応Async Taskについての分かり易い記事を載せておきますね.

 

dev.classmethod.jp

 

 

 ・TwitterOAuthActivity onNewIntent

@Override
public void onNewIntent(Intent intent) {
if (intent == null || intent.getData() == null || !intent.getData().toString().startsWith(callBackURL)) {
return;
}
//URLによって実行されたアプリから引数を取得する
String verifier = intent.getData().getQueryParameter("oauth_verifier");

AsyncTask<String, Void, AccessToken> task = new AsyncTask<String, Void, AccessToken>() {
@Override
protected AccessToken doInBackground(String... params) {
try {
//アクセストークンの取得
return twitter.getOAuthAccessToken(requestToken, params[0]);
} catch (TwitterException e) {
e.printStackTrace();
}
return null;
}

@Override
protected void onPostExecute(AccessToken accessToken) {
//トークンの登録
if (accessToken != null) {
// 認証成功!
showToast("認証成功!");
successOAuth(accessToken);
} else {
// 認証失敗。。。
showToast("認証失敗。。。");
}
}
};
task.execute(verifier);
}

 

 今度はアクセストークンを取得します.

処理の流れは先ほどと同じでdoInBackgourndでアクセストークンを取得して,onPostExcuteでトークンの登録を行う流れになります.

今回の処理はURLから実行されたアプリであるため,それまでの引数を取得する必要があります.

ということでgetQueryParameterメソッドによって引数を取得しているみたいです.excute()無いの引数に取得したverifierが入っているのは,AsyncTackに渡す引数でしょうか?(とすると中身はURL…ですかね?)

実際先ほど取得したリクエストトークンとその引数によってアクセストークンを取得していることが判ります.

 

 

・TwitterOAuthActivity successOAuth

private void successOAuth(AccessToken accessToken) {

//Utilクラスからトークン登録メソッドを呼び出し
TwitterUtils.storeAccessToken(this, accessToken);

//MainActivityへ遷移
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);

//このアクティビティを狩猟する
finish();
}

 

3.で作成したUtilクラスから登録メソッドを呼び出しているだけです.

実際にアクセストークンを取得できたときに呼び出しているメソッドです.

認証,登録が終わったら,アクティビティを終了してまたアプリに戻るとようにしています.

 

 

・TwitterOAuthActivithy showToast

//トーストを表示するメソッド
private void showToast(String text) {
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
}

 

認証成功,失敗時にトーストで知らせるためのメソッドです.

あってもなくてもかまいません.

 

 

以上がTwitterOAuthActivityクラスのすべてのメソッドの紹介になります.

ちなみにすべてを合わせると以下のようになっています.

 

・TwitterOAuthActivity.java

package hoge;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;

import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.auth.AccessToken;
import twitter4j.auth.RequestToken;

public class TwitterOAuthActivity extends Activity {

private String callBackURL;
private Twitter twitter;
private RequestToken requestToken;

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

//CallBack用URLの設定
callBackURL = getString(R.string.twitter_callback_url);
//Twitterインスタンスの取得
twitter = TwitterUtils.getTwitterInstance(this);

//認証開始
startAuthorize();
}

private void startAuthorize() {
//AsyncTaskによる非同期処理
AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(Void... params) {
try {
//リクエストトークンの取得
requestToken = twitter.getOAuthRequestToken(callBackURL);
return requestToken.getAuthorizationURL();
}catch (TwitterException e){
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String url) {
if (url != null) {
//渡されたurlへアクティビティを遷移する
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
} else {
// 失敗。。。
}
}
};
task.execute();
}

@Override
public void onNewIntent(Intent intent) {
if (intent == null || intent.getData() == null || !intent.getData().toString().startsWith(callBackURL)) {
return;
}
//URLによって実行されたアプリから引数を取得する
String verifier = intent.getData().getQueryParameter("oauth_verifier");

AsyncTask<String, Void, AccessToken> task = new AsyncTask<String, Void, AccessToken>() {
@Override
protected AccessToken doInBackground(String... params) {
try {
//アクセストークンの取得
return twitter.getOAuthAccessToken(requestToken, params[0]);
} catch (TwitterException e) {
e.printStackTrace();
}
return null;
}

@Override
protected void onPostExecute(AccessToken accessToken) {
//トークンの登録
if (accessToken != null) {
// 認証成功!
showToast("認証成功!");
successOAuth(accessToken);
} else {
// 認証失敗。。。
showToast("認証失敗。。。");
}
}
};
task.execute(verifier);
}

private void successOAuth(AccessToken accessToken) {

//Utilクラスからトークン登録メソッドを呼び出し
TwitterUtils.storeAccessToken(this, accessToken);

//MainActivityへ遷移
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);

//このアクティビティを狩猟する
finish();
}

//トーストを表示するメソッド
private void showToast(String text) {
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
}
}

 

少し長いですが,ひとつづつ見てみるとどうでしょうか?

結構あやふやな説明がありましたが割とニュアンスは伝わったのではないでしょうか.

 

 

まとめ

いかがだったでしょうか.

認証関連は仕組みから,初心者には少しややこしいと思います.実際私も詳しいことはわかっていません.トークンっていったい…?なんて思うこともあります.(Twitterのログインに必要な情報を暗号化したものだそうです)

 

それでも,できてしまうのだから,すごいですよねネットの情報って・・

まあわからないことは多いですが少しずつでも理解が深まれば良いなと思います.

 

とりあえず今回はこの辺で

次はメイン機能を作っていく予定です.

 

おまけ

この記事を書いた後めちゃくちゃコンフリクト起こしました.(ソースコードコメントアウトを付けたため)

 

 

参考サイト

 

AndroidでTwitterクライアントアプリを開発する(開発編) | ミラボ

 

Android再入門 - Twitterクライアントを作ってみよう - OAuth認証 - Qiita

 

 

 

関連記事

 

・次の記事

 

 

・前の記事

mltmdkana.hatenablog.com