[Twitter4J] Android実機上でgetOAuthAccessToken()がエラー

1,708 views
Skip to first unread message

matsumoto

unread,
Mar 5, 2011, 2:11:34 AM3/5/11
to Twitter4J J
初めまして、まつもとです。

AndroidにてTwitterのOAuth認証を行うアプリを開発しています。
下記ソースはOauth認証ページを開くためのwebviewを持つアクティビティの起動と、
帰ってきたインテントからアクセストークンを取得する物です。
エミュレーター上では問題なく動作するのですが、実機(GalaxyS)ではgetOAuthAccessTokeにてエラーが発生します。
原因が分からなくて困っています。
何かお気づきの点やこの問題に関して何かご存じの方はコメントよろしくお願いいたします。

■ソース
private RequestToken requesttoken;
private Twitter twitter = new TwitterFactory().getInstance();

public void executeOAAuth(){
try {


twitter.setOAuthConsumer(getString(R.string.consumer_key),getString(R.string.consumer_secret));

requesttoken =
twitter.getOAuthRequestToken(getString(R.string.callback_url));

String url = req.getAuthorizationURL();

Intent i = new Intent(this, OauthV.class);
i.putExtra("auth_url", url);

// アクティビティを起動
this.startActivityForResult(i,0);

} catch (TwitterException e) {
e.printStackTrace();
Log.d("twitter", e.toString());
}
}

protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {

if (resultCode == RESULT_OK){

// インテントからoauth_verifierを取り出して、
// access_tokenとaccess_token_secretを取得する。

AccessToken token = null;
String verifier = intent.getExtras().getString("oauth_verifier");

try {
Log.d("test",verifier);
token = twitter.getOAuthAccessToken(requesttoken, verifier);//ここでエ
ラー

}
catch (TwitterException e) {
e.printStackTrace();
setResult(RESULT_CANCELED);
finish();
}

String atokenStr = token.getToken();
String atokenStrSec = token.getTokenSecret();

//プレファレンス
SharedPreferences preferences =
getSharedPreferences( getString(R.string.preferences_name),
MODE_PRIVATE);
SharedPreferences.Editor editor=preferences.edit();
editor.putString("oauth_token",atokenStr);
editor.putString("oauth_token_secret",atokenStrSec);
editor.commit();

}
else{
setResult(RESULT_CANCELED);
finish();
}
// 設定おしまい。
setResult(RESULT_OK);
finish();
}

■ログ
03-05 15:35:12.827: DEBUG/dalvikvm(2541): GC_FOR_MALLOC freed 9600
objects / 522200 bytes in 129ms
03-05 15:35:12.859: INFO/DBG_WSS_DM(4658): [wssTelephonyData.java Line:
153] getInstance PHONE_TYPE_GSM
03-05 15:35:13.683: INFO/DBG_WSS_DM(4658): [wssTelephonyData.java Line:
153] getInstance PHONE_TYPE_GSM
03-05 15:35:13.737: DEBUG/test(6264):
L9X2ygmoT4uL5XmE8Z2qylYEp4bYHjFz4lBjY4FTDQ
03-05 15:35:17.593: DEBUG/dalvikvm(4195): GC_EXPLICIT freed 1283
objects / 59928 bytes in 142ms
03-05 15:35:18.726: DEBUG/AndroidRuntime(6264): Shutting down VM
03-05 15:35:18.726: WARN/dalvikvm(6264): threadid=1: thread exiting
with uncaught exception (group=0x4001d7d0)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): FATAL EXCEPTION: main
03-05 15:35:18.874: ERROR/AndroidRuntime(6264):
java.lang.RuntimeException: Unable to resume activity {com.twittertest/
com.twittertest.OLoginB}: java.lang.RuntimeException: Failure
delivering result ResultInfo{who=null, request=0, result=-1,
data=Intent { cmp=com.twittertest/.OauthV (has extras) }} to activity
{com.twittertest/com.twittertest.OLoginB}:
java.lang.IllegalStateException: OAuth consumer key/secret combination
not supplied
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): at
android.app.ActivityThread.performResumeActivity(ActivityThread.java:
3128)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): at
android.app.ActivityThread.handleResumeActivity(ActivityThread.java:
3143)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:
2684)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): at
android.app.ActivityThread.access$2300(ActivityThread.java:125)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): at
android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): at
android.os.Handler.dispatchMessage(Handler.java:99)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): at
android.os.Looper.loop(Looper.java:123)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): at
android.app.ActivityThread.main(ActivityThread.java:4627)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): at
java.lang.reflect.Method.invokeNative(Native Method)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): at
java.lang.reflect.Method.invoke(Method.java:521)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): at
com.android.internal.os.ZygoteInit
$MethodAndArgsCaller.run(ZygoteInit.java:858)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): at
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): at
dalvik.system.NativeStart.main(Native Method)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): Caused by:
java.lang.RuntimeException: Failure delivering result
ResultInfo{who=null, request=0, result=-1, data=Intent
{ cmp=com.twittertest/.OauthV (has extras) }} to activity
{com.twittertest/com.twittertest.OLoginB}:
java.lang.IllegalStateException: OAuth consumer key/secret combination
not supplied
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): at
android.app.ActivityThread.deliverResults(ActivityThread.java:3515)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): at
android.app.ActivityThread.performResumeActivity(ActivityThread.java:
3115)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): ... 12 more
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): Caused by:
java.lang.IllegalStateException: OAuth consumer key/secret combination
not supplied
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): at
twitter4j.TwitterBaseImpl.getOAuth(TwitterBaseImpl.java:362)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): at
twitter4j.TwitterBaseImpl.getOAuthAccessToken(TwitterBaseImpl.java:
342)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): at
com.twittertest.OLoginB.onActivityResult(OLoginB.java:75)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): at
android.app.Activity.dispatchActivityResult(Activity.java:3890)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): at
android.app.ActivityThread.deliverResults(ActivityThread.java:3511)
03-05 15:35:18.874: ERROR/AndroidRuntime(6264): ... 13 more
03-05 15:35:18.937: WARN/ActivityManager(2471): Process
com.twittertest has crashed too many times: killing!
03-05 15:35:18.937: WARN/ActivityManager(2471): Force finishing
activity com.twittertest/.OLoginB
03-05 15:35:18.944: INFO/Process(2471): Sending signal. PID: 6264 SIG:
9
03-05 15:35:18.972: INFO/WindowManager(2471): WIN DEATH:
Window{482d8b60 com.twittertest/com.twittertest.OauthV paused=false}
03-05 15:35:23.968: INFO/ActivityManager(2471): Displayed activity
com.twittertest/.OLoginB: 25960 ms (total 25960 ms)
03-05 15:35:28.941: WARN/ActivityManager(2471): Launch timeout has
expired, giving up wake lock!



■実行環境
Windows7
Eclipse3.5
JDK1.5
Androidターゲット android2.1 api level 7

ライブラリ twitter4j-core-android-2.2.1-SNAPSHOT.jar

実機
Galaxy S (SC-02B)
ファームウェアバージョン 2.1.1
ベースバンドバージョン SC02BOMKA5

Yusuke Yamamoto

unread,
Mar 5, 2011, 2:40:29 AM3/5/11
to twitt...@googlegroups.com
まつもとさん

初めまして。山本です。

executeOAAuth() でtwitterにコンシューマキーをセットしていますが、onActivityResult()で触れているtwitterインスタンスは同一であることが保証されているのでしょうか?
Androidのライフサイクルを理解していないのですが、別のTwitterインスタンスになる可能性があるとするとコンシューマキーが設定されていないことで例外が発生しているのかもしれません。
コンシューマキーをtwitter4j.propertiesに書くようにしてはいかがでしょう。
--
山本 裕介
yus...@mac.com

このメールは: [x] ブログ/Twitterへ転載可能 [ ] 私信
Twitter でフォロー : http://twitter.com/yusukey
blogを購読: http://samuraism.jp/

> --
> Twitter4J の最新情報をフォロー: http://twitter.com/t4j_news
> 現在のバージョン - 安定: 2.2.0, 開発中: 2.2.1-SNAPSHOT
> http://twitter4j.org/jira/secure/IssueNavigator.jspa?requestId=10030
> バグトラッキング: http://twitter4j.org/jira/browse/TFJ
>
> このメールは次の Google グループの参加者に送られています: Twitter4J J
> このグループにメールで投稿: twitt...@googlegroups.com
> このグループから退会する: http://groups.google.com/group/twitter4j-j?hl=ja

matsumoto

unread,
Mar 5, 2011, 4:27:57 AM3/5/11
to Twitter4J J
山本様

早速のお返事ありがとうございます。
私もandroidのライフサイクルをあまり理解していませんのでなんともいえないです。。
アドバイス頂いたように、twitter4j.propertiesで書いてみました。
コールバックURLもコードから指定せず、twitter公式のアプリケーション設定から指定するように変更してみました。

またしても、エミュレーターでは例外は発生せず実機では発生しました。
素人なもので時間はかかりますがRequestTokenも保持するように出来ないか試行錯誤してみます。



■ソース
public void executeOAAuth(){
try {
requesttoken = twitter.getOAuthRequestToken();
String url = requesttoken.getAuthorizationURL();

Intent i = new Intent(this, OauthV.class);
i.putExtra("auth_url", url);

// アクティビティを起動。
// REQUEST_CODEは任意(0<)なint型の値。
this.startActivityForResult(i,0);

} catch (TwitterException e) {
e.printStackTrace();
Log.d("twitter", e.toString());
}
}

protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {

if (resultCode == RESULT_OK){

// インテントからoauth_verifierを取り出して、
// access_tokenとaccess_token_secretを取得する。
AccessToken token = null;
String verifier = intent.getExtras().getString("oauth_verifier");

try {
Log.d("test",verifier);
token = twitter.getOAuthAccessToken(requesttoken, verifier);//ここでエ
ラー

}
catch (TwitterException e) {
e.printStackTrace();
setResult(RESULT_CANCELED);
finish();
}

String atokenStr = token.getToken();
String atokenStrSec = token.getTokenSecret();

//プレファレンスにトークン情報を書き込み
SharedPreferences preferences =
getSharedPreferences( getString(R.string.preferences_name),
MODE_PRIVATE);
SharedPreferences.Editor editor=preferences.edit();
editor.putString("oauth_token",atokenStr);
editor.putString("oauth_token_secret",atokenStrSec);
editor.commit();

}
else{
setResult(RESULT_CANCELED);
finish();
}
// 設定おしまい。
setResult(RESULT_OK);
finish();
}
}

■ログ
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): FATAL EXCEPTION: main
03-05 18:12:12.515: ERROR/AndroidRuntime(14827):
java.lang.RuntimeException: Unable to resume activity {com.twittertest/
com.twittertest.OLoginB}: java.lang.RuntimeException: Failure
delivering result ResultInfo{who=null, request=0, result=-1,
data=Intent { cmp=com.twittertest/.OauthV (has extras) }} to activity
{com.twittertest/com.twittertest.OLoginB}:
java.lang.IllegalStateException: No Token available.
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
android.app.ActivityThread.performResumeActivity(ActivityThread.java:
3128)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
android.app.ActivityThread.handleResumeActivity(ActivityThread.java:
3143)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:
2684)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
android.app.ActivityThread.access$2300(ActivityThread.java:125)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
android.os.Handler.dispatchMessage(Handler.java:99)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
android.os.Looper.loop(Looper.java:123)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
android.app.ActivityThread.main(ActivityThread.java:4627)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
java.lang.reflect.Method.invokeNative(Native Method)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
java.lang.reflect.Method.invoke(Method.java:521)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
com.android.internal.os.ZygoteInit
$MethodAndArgsCaller.run(ZygoteInit.java:858)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
dalvik.system.NativeStart.main(Native Method)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): Caused by:
java.lang.RuntimeException: Failure delivering result
ResultInfo{who=null, request=0, result=-1, data=Intent
{ cmp=com.twittertest/.OauthV (has extras) }} to activity
{com.twittertest/com.twittertest.OLoginB}:
java.lang.IllegalStateException: No Token available.
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
android.app.ActivityThread.deliverResults(ActivityThread.java:3515)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
android.app.ActivityThread.performResumeActivity(ActivityThread.java:
3115)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): ... 12 more
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): Caused by:
java.lang.IllegalStateException: No Token available.
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
twitter4j.auth.OAuthAuthorization.ensureTokenIsAvailable(OAuthAuthorization.java:
80)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
twitter4j.auth.OAuthAuthorization.getOAuthAccessToken(OAuthAuthorization.java:
128)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
twitter4j.auth.OAuthAuthorization.getOAuthAccessToken(OAuthAuthorization.java:
147)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
twitter4j.TwitterBaseImpl.getOAuthAccessToken(TwitterBaseImpl.java:
342)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
com.twittertest.OLoginB.onActivityResult(OLoginB.java:74)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
android.app.Activity.dispatchActivityResult(Activity.java:3890)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): at
android.app.ActivityThread.deliverResults(ActivityThread.java:3511)
03-05 18:12:12.515: ERROR/AndroidRuntime(14827): ... 13 more


他にもお気づきの点がある方がおられましたらコメントをよろしくお願いいたします。

Yusuke Yamamoto

unread,
Mar 5, 2011, 8:32:59 AM3/5/11
to twitt...@googlegroups.com
今度はリクエストトークンが見つからないみたいですね。
仰る通りリクエストトークンを保持する作り込みをする必要があるのかもしれません。

ただ、モバイルアプリケーションでOAuthは面倒なのでxAuthの申請をしてしまうのが楽でいいかも?
--
山本 裕介
yus...@mac.com

このメールは: [x] ブログ/Twitterへ転載可能 [ ] 私信
Twitter でフォロー : http://twitter.com/yusukey
blogを購読: http://samuraism.jp/

Mocel

unread,
Mar 5, 2011, 9:25:02 AM3/5/11
to Twitter4J J
こんにちは。

>Intent i = new Intent(this, OauthV.class);

で別の Activity を呼び出そうとされていますが、こちらのクラスが謎なので
ライフサイクルのどの状態になっているかも推測するのはかなり難易度高いですね。。。

getAuthorizationURL() でゲットした認証用 URL をパラメーターで渡しているようですけど、
標準の Web ブラウザ以外で Twitter の OAuth 認証画面を処理しているのでしょうか?
認証成功時にリダイレクトされる URL はどう処理していますか?

>String verifier = intent.getExtras().getString("oauth_verifier");

ここで欲しい値は得られていますか?

あとは、ご参考までに。
Android アプリで一般的に見かける OAuth 認証処理は、専用の Activity をひとつ設けて
その Activity から Twitter の OAuth 認証 URL をブラウザで表示させ、リダイレクト URL を
Intent Filter で拾って oauth_verifier を取り出す、といった感じに実装されてるようです。

ものすごく単純に書くと、次のような感じになると思います。
OnCreate() で認証用 URL を即アクセスしてますけど、これを Activity 上のボタンクリック
とかで実行するようにしたほうが実用的というか一般的ですね。

public class OAuthActivity extends Activity {

/**
* アプリケーションマニフェストのこの Activity に intent-filter を記述しておく。
* <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:scheme="sample" android:host="oauth" />
* </intent-filter>
*/
private static final String CALLBACK_URL = "sample://oauth";

private Twitter twitter;
private RequestToken reqToken;

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

twitter = Twitter.getInstance(getTwitter4JConfig());
reqToken = twitter.getOAuthRequestToken(CALLBACK_URL);
startActivity(new Intent(Intent.ACTION_VIEW,
Uri.parse(reqToken.getAuthenticationURL())));
}

private Configuration getTwitter4JConfig() {
// 文字列リソースにコンシューマーキー等を入れておく
return new ConfigurationBuilder()
.setOAuthConsumerKey(getString(R.string.oauth_consumer_key))
.setOAuthConsumerSecret(getString(R.string.oauth_consumer_secret))
.build();
}

@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Uri uri = intent.getData();

// Twitter からのリダイレクトかどうか判定
if (uri != null && uri.toString().startsWith(CALLBACK_URL)) {
String verifier = uri.getQueryParameter("oauth_verifier");
try {
AccessToken token =
twitter.getOAuthAccessToken(reqToken, verifier);

// ここでアクセストークンの保存等を

// 別定義してある MainActivity を呼び出す
Intent mainIntent = new Intent();
mainIntent.setClassName(this,
MainActivity.class.getName());
startActivity(mainIntent);

// この Activity にもう用はないので終了
finish();
} catch (Exception ex) {
Log.e(TAG, ex.getLocalizedMessage(), ex);
}
}
}
}


-Mocel
> ...
>
> read more ≫

matsumoto

unread,
Mar 6, 2011, 8:37:15 AM3/6/11
to Twitter4J J
リクエストトークンを保持する事は行いませんでしたが解決しました。
twitter4jではなく、Androidのライフサイクルの問題でした。お騒がせしました。

たしかにOAuthはめんどくさいですね。。。
xAuthは以前申請したのですが、1週間分しか許可が下りなかったため
挫けてしまいました。またいつか申請してみようと思います。

ありがとうございました。
> >>> String verifier = intent.getExtras().getString("oauth_verifier");...
>
> もっと読む ≫

matsumoto

unread,
Mar 6, 2011, 8:38:40 AM3/6/11
to Twitter4J J
コメントありがとうございます。

やっと解決しました。
原因はSparePartsでActivity/ProcessManagementsの設定をAggressiveに設定していたためでした。

そのため、アクティビティを開く度にonDestroy()が呼び出されていました。

データを返した時にはonActivityResult()が呼び出される前にonCreate()が呼び出されてしまっていたため
twitterインスタンス等が初期化されていたのが原因でした。


> 標準の Web ブラウザ以外で Twitter の OAuth 認証画面を処理しているのでしょうか?
Webブラウザではなく、webviewを持たせたアクティビティ(OauthV.class)を起動しています。

> 認証成功時にリダイレクトされる URL はどう処理していますか?
onPageFinished()内で頂いたサンプルコードとほぼ同じように処理しています。
oauth_verifierを抜き出して、インテントで返しています。

> >String verifier = intent.getExtras().getString("oauth_verifier");
> ここで欲しい値は得られていますか?
取得できていました。

サンプルコードまで記載して頂き有り難うございました。
> > 03-05...
>
> もっと読む ≫
Reply all
Reply to author
Forward
0 new messages