How to Post a Tweet to Twitter with the OAuth API

Recently, I released a few twitter wrapper apps. Apps that use twitter to do searches for specific #twitter tags.  I found that while there was tons of information on the internet about how to do it, I still had quite a bit of trouble putting together all of the pieces for Twitter’s new OAuth Api.  I found many great guides such as this post on how to make an android callback, or this guide on using the Signpost library.  Through a bunch of trial and error, I was able to put together a working version that posts tweets to a twitter account. This is a code snippet from the Activity class for the submit tweet page.  This Activity presents a user with a button to log into their twitter account.  They are taken to the web browser where they give twitter their permission to use the app.  At that point, they are brought back to this activity through the onNewIntent method.  The necessary twitter account information is then stored in Android preferences objects for future use.

  1.  
  2. public class SubmitTwitter extends Activity implements OnClickListener {
  3.  
  4.  public static final String PREFS_NAME = "AccountPrefs";
  5.  public static final String PREFS_TWITTER_ACCOUNT_NAME = "TwitterAccountName";
  6.  public static final String PREFS_TWITTER_USER_TOKEN = "TwitterUserToken";
  7.  public static final String PREFS_TWITTER_USER_SECRET = "TwitterUserSecret";
  8.  public static final String PREFS_TWITTER_USER_VERIFIER = "TwitterVerifier";
  9.  
  10.  private CommonsHttpOAuthConsumer httpOauthConsumer;
  11.  private DefaultOAuthProvider httpOauthprovider;
  12.  
  13.  public static final String consumerKey = "[TWITTER_CONSUMER_KEY]";
  14.  public static final String consumerSecret = "[TWITTER_CONSUMER_SECRET]";
  15.  
  16.  public static final String CALLBACKURL = "fml://submitTwitter";
  17.  
  18.  @Override
  19.  protected void onCreate(Bundle savedInstanceState) {
  20.   super.onCreate(savedInstanceState);
  21.  
  22.   setContentView(R.layout.submit_tweet);
  23.  
  24.   SharedPreferences settings = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
  25.  
  26.   if (settings.contains(PREFS_TWITTER_ACCOUNT_NAME) && null != settings.getString(PREFS_TWITTER_ACCOUNT_NAME, null)) {
  27.    twitterAccountName = settings.getString(PREFS_TWITTER_ACCOUNT_NAME, "");
  28.    ((TextView)findViewById(R.id.currentUser)).setText(twitterAccountName);
  29.   }
  30.  
  31.   Button signIn = (Button) findViewById(R.id.signIn);
  32.   signIn.setOnClickListener(this);
  33.  
  34.   Button signOut = (Button) findViewById(R.id.signOut);
  35.   signOut.setOnClickListener(this);
  36.  
  37.   Button submit = (Button) findViewById(R.id.submit);
  38.   submit.setOnClickListener(new OnClickListener() {
  39.  
  40.    @Override
  41.    public void onClick(View v) {
  42.     EditText request = (EditText) findViewById(R.id.request);
  43.     String tweet = request.getText().toString();
  44.  
  45.     if (!"".equals(tweet)) {
  46.      TwitterSearch.Post(getBaseContext(), tweet + " #fml");
  47.      request.setText("");
  48.      startActivity(new Intent(getBaseContext(), MainActivity.class));
  49.  
  50.     } else {
  51.      Toast.makeText(getBaseContext(), "You must include a Message.", Toast.LENGTH_LONG).show();
  52.     }
  53.  
  54.    }
  55.   });
  56.  }
  57.  
  58.  @Override
  59.  protected void onNewIntent(Intent intent) {
  60.   super.onNewIntent(intent);
  61.   Uri uri = intent.getData();
  62.   // Check if you got NewIntent event due to Twitter Call back only
  63.   if (uri != null && uri.toString().startsWith(CALLBACKURL)) {
  64.  
  65.    String verifier = uri
  66.      .getQueryParameter(oauth.signpost.OAuth.OAUTH_VERIFIER);
  67.  
  68.    try {
  69.     // this will populate token and token_secret in consumer
  70.     httpOauthprovider.retrieveAccessToken(httpOauthConsumer,
  71.       verifier);
  72.  
  73.     SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
  74.     String userToken = httpOauthConsumer.getToken();
  75.     String tokenSecret = httpOauthConsumer.getTokenSecret();
  76.     Editor editor = prefs.edit();
  77.     editor.putString(PREFS_TWITTER_USER_TOKEN, userToken);
  78.     editor.putString(PREFS_TWITTER_USER_SECRET, tokenSecret);
  79.     editor.putString(PREFS_TWITTER_USER_VERIFIER, verifier);
  80.     editor.commit();
  81.    } catch (Exception e) {
  82.     Toast.makeText(getBaseContext(), e.getMessage(), Toast.LENGTH_LONG).show();
  83.    }
  84.   }
  85.  }
  86.  
  87.  @Override
  88.  public void onClick(View v) {
  89.   try {
  90.          httpOauthConsumer = new CommonsHttpOAuthConsumer(consumerKey, consumerSecret);
  91.    httpOauthprovider = new DefaultOAuthProvider("http://twitter.com/oauth/request_token", "http://twitter.com/oauth/access_token", "http://twitter.com/oauth/authorize");
  92.    String authUrl = httpOauthprovider.retrieveRequestToken(httpOauthConsumer, CALLBACKURL);
  93.    this.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(authUrl)));
  94.         } catch (Exception e) {
  95.             Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
  96.         }
  97.  }
  98. }

This is the static method call that does the post to Twitter.  It uses Signpost to create a signed request.

  1. public class TwitterSearch {
  2.  private static final String TWITTER_POST_STATUS_URI = "http://api.twitter.com/1/statuses/update.json";
  3.  
  4.  public static void Post(Context context, String status) {
  5.  
  6.   SharedPreferences prefs = context.getSharedPreferences(SubmitTwitter.PREFS_NAME, Activity.MODE_PRIVATE);
  7.  
  8.   try {
  9.    HttpPost post = new HttpPost(TWITTER_POST_STATUS_URI);
  10.          final List nvps = new ArrayList();
  11.          nvps.add(new BasicNameValuePair("status", status));
  12.          post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
  13.          // set this to avoid 417 error (Expectation Failed)
  14.          post.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false);
  15.  
  16.    OAuthConsumer consumer = new CommonsHttpOAuthConsumer(SubmitTwitter.consumerKey, SubmitTwitter.consumerSecret);
  17.    consumer.setTokenWithSecret(prefs.getString(SubmitTwitter.PREFS_TWITTER_USER_TOKEN, ""),
  18.      prefs.getString(SubmitTwitter.PREFS_TWITTER_USER_SECRET, ""));
  19.  
  20.    consumer.sign(post);
  21.    HttpClient client = new DefaultHttpClient();
  22.    final HttpResponse response = client.execute(post);
  23.  
  24.   } catch (Exception e) {
  25.    Log.e("TwitterSearch", e.getMessage());
  26.   }
  27.  
  28.  }
  29. }

Finally we register our callback in our AndroidManifest.xml

  1. <intent-filter>
  2.    <data android:scheme="fml" android:host="submitTwitter" />
  3. </intent-filter>

I wouldn’t do it justice to attempt to explain in detail what is going on here… instead I would recommend looking over the blogs I pointed out above. Feel free to email me with any questions you have. I certainly believe that since Android is an open platform, as developers we owe it to each other to help to make the best apps possible. Email me at ryan at lowequalityapps.com

Introducing Pray for Me!

Using Twitter, Pray for Me discovers prayer requests from around the world.  Submit your own prayer request with your own Twitter account.

Perfect way to help others around the world with the power of prayer!

New Features coming soon!
- Search for Prayers by location
- Respond to prayer requests
- Many more