11

I'm following a lot of instructions to make a simple tweet from my app. I've already registered it on Twitter, but I just can't make a tweet. I can login, but not update my status. Here's the code to login

private void twitterLogOn() {
        Twitter twitter = new TwitterFactory().getInstance();
        try {

            twitter.setOAuthConsumer(consumerKey, consumerSecret);
            rToken = twitter.getOAuthRequestToken(myCallBack);
            startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(rToken.getAuthenticationURL())));
        } catch (IllegalStateException e) {
            // access token is already available, or consumer key/secret is not
            // set.
            if (!twitter.getAuthorization().isEnabled()) {
                System.out.println("OAuth consumer key/secret is not set.");
                finish();
            }
        } catch (Exception e) {
            Toast.makeText(Configuration.this,getString(R.string.networkError), Toast.LENGTH_SHORT).show();
        }
    }

That seems to work fine, but when I go back to my app after the login, this next code should be executed, ending always in the exception Toast.

public void onResume() {    
        super.onResume();

        Uri uri = getIntent().getData();

        if (uri != null) {    
            oauthVerifier = uri.getQueryParameter("oauth_verifier");

            try {    
                Twitter tt = new TwitterFactory().getInstance(); // Do I need this new twitter instance?
                tt.setOAuthConsumer(consumerKey, consumerSecret);
                AccessToken at = tt.getOAuthAccessToken(rToken, oauthVerifier); // Gives the error

                       // Do tweet here ...

                } catch (Exception e) {
                    Toast.makeText(Configuration.this, "Network Host not responding",Toast.LENGTH_SHORT).show();
                }
            }
    }

Any good hawk eye there that can tell me what I'm doing wrong? This is the line firing the exception

AccessToken at = tt.getOAuthAccessToken(rToken, oauthVerifier);

Thanks in advance!

EDIT

Stack Trace: (read somewhere this is just hiding a 401 error)

07-24 12:49:31.931: WARN/System.err(18441): Received authentication challenge is nullRelevant discussions can be on the Internet at:
07-24 12:49:31.931: WARN/System.err(18441):     http://www.google.co.jp/search?q=9ddbeb3a or
07-24 12:49:31.931: WARN/System.err(18441):     http://www.google.co.jp/search?q=5c9c15a6
07-24 12:49:31.931: WARN/System.err(18441): TwitterException{exceptionCode=[9ddbeb3a-5c9c15a6 c8a7b39b-36e69ae1], statusCode=-1, retryAfter=-1, rateLimitStatus=null, featureSpecificRateLimitStatus=null, version=2.2.3}
07-24 12:49:31.931: WARN/System.err(18441):     at twitter4j.internal.http.HttpClientImpl.request(HttpClientImpl.java:204)
07-24 12:49:31.931: WARN/System.err(18441):     at twitter4j.internal.http.HttpClientWrapper.request(HttpClientWrapper.java:65)
07-24 12:49:31.931: WARN/System.err(18441):     at twitter4j.internal.http.HttpClientWrapper.post(HttpClientWrapper.java:102)
07-24 12:49:31.931: WARN/System.err(18441):     at twitter4j.auth.OAuthAuthorization.getOAuthAccessToken(OAuthAuthorization.java:142)
07-24 12:49:31.931: WARN/System.err(18441):     at twitter4j.auth.OAuthAuthorization.getOAuthAccessToken(OAuthAuthorization.java:160)
07-24 12:49:31.931: WARN/System.err(18441):     at twitter4j.TwitterBaseImpl.getOAuthAccessToken(TwitterBaseImpl.java:349)
07-24 12:49:31.931: WARN/System.err(18441):     at com.my.app.TwitterTweetActivity.onResume(TwitterTweetActivity.java:76)
07-24 12:49:31.931: WARN/System.err(18441):     at com.my.app.TwitterTweetActivity.onResume(TwitterTweetActivity.java:64)
07-24 12:49:31.931: WARN/System.err(18441):     at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1149)
07-24 12:49:31.931: WARN/System.err(18441):     at android.app.Activity.performResume(Activity.java:3833)
07-24 12:49:31.931: WARN/System.err(18441):     at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2215)
07-24 12:49:31.941: WARN/System.err(18441):     at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2240)
07-24 12:49:31.941: WARN/System.err(18441):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1773)
07-24 12:49:31.941: WARN/System.err(18441):     at android.app.ActivityThread.access$1500(ActivityThread.java:123)
07-24 12:49:31.941: WARN/System.err(18441):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:936)
07-24 12:49:31.941: WARN/System.err(18441):     at android.os.Handler.dispatchMessage(Handler.java:99)
07-24 12:49:31.941: WARN/System.err(18441):     at android.os.Looper.loop(Looper.java:123)
07-24 12:49:31.941: WARN/System.err(18441):     at android.app.ActivityThread.main(ActivityThread.java:3812)
07-24 12:49:31.941: WARN/System.err(18441):     at java.lang.reflect.Method.invokeNative(Native Method)
07-24 12:49:31.941: WARN/System.err(18441):     at java.lang.reflect.Method.invoke(Method.java:507)
07-24 12:49:31.941: WARN/System.err(18441):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
07-24 12:49:31.941: WARN/System.err(18441):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
07-24 12:49:31.941: WARN/System.err(18441):     at dalvik.system.NativeStart.main(Native Method)
07-24 12:49:31.941: WARN/System.err(18441): Caused by: java.io.IOException: Received authentication challenge is null
07-24 12:49:31.941: WARN/System.err(18441):     at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.processAuthHeader(HttpURLConnectionImpl.java:1153)
07-24 12:49:31.941: WARN/System.err(18441):     at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.processResponseHeaders(HttpURLConnectionImpl.java:1095)
07-24 12:49:31.951: WARN/System.err(18441):     at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.retrieveResponse(HttpURLConnectionImpl.java:1048)
07-24 12:49:31.951: WARN/System.err(18441):     at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:726)
07-24 12:49:31.951: WARN/System.err(18441):     at twitter4j.internal.http.HttpResponseImpl.<init>(HttpResponseImpl.java:35)
07-24 12:49:31.951: WARN/System.err(18441):     at twitter4j.internal.http.HttpClientImpl.request(HttpClientImpl.java:168)
07-24 12:49:31.951: WARN/System.err(18441):     ... 22 more

API for the method: getOAuthREquestToken

Blundell
  • 75,855
  • 30
  • 208
  • 233
MetalCraneo
  • 335
  • 1
  • 4
  • 14
  • 1
    You should try breaking your second bock of code in two. One section that exchanges the request token for an access token and one section that post a new status. The request token is only valid once so subsequent attempts to exchange it for an access token will cause an error. I'm not sure if this will fix your problem though. – abraham Jun 24 '11 at 09:13

2 Answers2

21

I've gone an solved it myself, only took 4 hours!!

I'm not 100% sure on the reasoning, but I know the fix works.

Fix:

In your manifest for this Activity you need to make it a single instance:

 <activity
        android:name=".TwitterTweetActivity"
        android:launchMode="singleInstance">
        <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="your-unique-schema-01-android" />
        </intent-filter>
    </activity>

Now when your Activity resumes you need to catch it coming back from the browser with onNewIntent() like so:

 @Override
protected void onResume() {
    super.onResume();
    dealWithTwitterResponse(getIntent());
}

Replaced with:

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    dealWithTwitterResponse(intent);
}
 

And it should work!

Reasoning (correct me if I'm wrong):

So the problem is your rToken object isn't the same object it was when created...

When you create your Twitter instance and get the rToken object this is in your activity. The activity then goes into the background (onPause) whilst the browser comes up for the user to login.

When the activity is recreated the rToken object is different therefore this is why the getOAuthAccessToken() method throws the error.

Extra Credit:

I've just written a Tutorial to match: How to send Tweets on Android from a Users Acc

Community
  • 1
  • 1
Blundell
  • 75,855
  • 30
  • 208
  • 233
  • Great! this is a very complete answer. Although I solved this way ago, you describe very well the problem and the solution. When using "onNewIntent" I had another heavy issue cause it force you to make the activity "singleInstance" (singletop didn't work). If an activity is "singleInstance" it can't be part of a task started from a "non singleInstance" activity, wich was a trouble in my app. The final solution was simply to create a "dummy activity" with all that Twitter mechanism you describe, singleInstance, and call it from the "real activity" that should have that code. Thank you very much – MetalCraneo Aug 18 '11 at 20:41
  • I found that if you make a static reference to your rToken in the activity you can use it after the activity resumes and get the access token. This way you don't have to make the activity single instance. – taf Jul 05 '12 at 11:18
  • I have been battling with this problem for weeks, thanks a lot for sharing! – kabuto178 Dec 04 '12 at 13:03
  • please Answer this question [getOAthAccessToken function misbehaviour during Twitter Intergration](http://stackoverflow.com/questions/21235283/getoathaccesstoken-function-misbehaviour-during-twitter-intergration) – Vivek Warde Jan 21 '14 at 12:42
5

The reason is that after the authentication returns, you created another instance of the activity and used rToken in its onResume method, which is null.

markmarch
  • 214
  • 3
  • 7
  • This is the truth, but I marked that other answer as correct just cause it has a code example for solving the problem. Thank you anyway. – MetalCraneo Aug 18 '11 at 20:36