What's brewing in the mobile world?

Writing an Android Twitter client with Image Upload using Twitter4j

Twitter-Emory

The following instructions are loosely based on this awesome Twitter presentation and should allow your apps to begin tweeting in no time.

  1. Go out to dev.twitter.com and register an app.  Make sure you register as a browser app and set the callback URL to something you own – we won’t actually be using this callback URL, but something needs to be provided.  Twitter will provide you an OAuth Consumer Key and Secret – we’ll make use of these below.  Go ahead and set the access type to Read, Write & Direct Messages (unless you’re aware you’ll be doing less.)
  2. Visit twitter4j.org and obtain the latest stable version of Twitter4j (you want the slimmed version for Android.)
  3. Go ahead and add the twitter4j-core jar to your project as a library.  If you’re planning to do image uploads (you should, image uploads are cool), you’ll want to include the twitter4j-media jar as well.
  4. Add android.permission.INTERNET to your app’s manifest – also open up your strings.xml and add the following:
    <string name="twitter_callback">twitter-callback:///</string>
  5. What we’ve got at this point are some credentials for our Twitter app. What we need is to obtain permission from the user for our app to do their bidding.  This is where things get a little tricksy, but it boils down to the following code in the activity where you’re setting up a user’s Twitter access:
    // Twitter mTwitter and RequestToken mRequestToken
    // are private members of this activity
    mTwitter = new TwitterFactory().getInstance();
    mRequestToken = null;
    mTwitter.setOAuthConsumer( OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET );
    String callbackURL = getResources().getString(R.string.twitter_callback);
    try
    {
         mRequestToken = mTwitter.getOAuthRequestToken(callbackURL);
    }
    catch (TwitterException e)
    {
         e.printStackTrace();
    }
    Intent i = new Intent(mContext, TwitterWebviewActivity.class);
    i.putExtra("URL", mRequestToken.getAuthenticationURL());
    startActivityForResult(i, TWITTER_AUTH);
    

    We’re creating a Twitter object and authenticating our app. We’re then asking Twitter to generate a request for User access and providing a callback URL. We store the request object in the activity, so that when we obtain a response we know they’re a proper pair. The request also has a URL, which we direct the user to such that they can see and respond to our access request.

  6. To present the Twitter request to the user, we’re using a webview. The activity’s code is fairly short. The layout looks like the following:
    <?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">
    	<WebView
    		xmlns:android="http://schemas.android.com/apk/res/android"
    		android:layout_width="fill_parent"
    		android:layout_height="fill_parent"
    		android:id="@+id/webview"/>
    </LinearLayout>
    

    The code for the TwitterWebActivity class is below. It loads the URL we passed in through the intent into the webview and listens in for the callback. Once it sees an attempt to redirect to the callback, it grabs out the parameter we need (oauth_verifier) and returns it to the activity it was called from.

    private Intent mIntent;
    public void onCreate(Bundle savedInstanceState)
    {
    	super.onCreate(savedInstanceState);
    	setContentView(R.layout.twitter_webview);
    	mIntent = getIntent();
    	String url = (String)mIntent.getExtras().get("URL");
    	WebView webView = (WebView)findViewById(R.id.webview);
    	webView.setWebViewClient( new WebViewClient()
    	{
    		@Override
    		public boolean shouldOverrideUrlLoading(WebView view, String url)
    		{
    			if( url.contains( getResources().getString( R.string.twitter_callback ) ) )
    			{
    				Uri uri = Uri.parse( url );
    				String oauthVerifier = uri.getQueryParameter( "oauth_verifier" );
    				mIntent.putExtra( "oauth_verifier", oauthVerifier );
    				setResult( RESULT_OK, mIntent );
    				finish();
    				return true;
    			}
    			return false;
    		}
    	});
    	webView.loadUrl(url);
    }
    
  7. Back to our setup activity! In onActivityResult we’re going to look for a requestCode of TWITTER_AUTH and store a few things into the app’s SharedPreferences (in the code below, the SharedPrefs are already open and named settings):
    if (resultCode == Activity.RESULT_OK)
    {
    	String oauthVerifier = (String) data.getExtras().get("oauth_verifier");
    	AccessToken at = null;
    	try
    	{
    		// Pair up our request with the response
    		at = mTwitter.getOAuthAccessToken(mRequestToken, oauthVerifier);
    		settings.edit()
    			.putString( "twitter_access_token", at.getToken() )
    			.putString( "twitter_access_token_secret", at.getTokenSecret() )
    			.commit();
    	}
    	catch (TwitterException e)
    	{
    		e.printStackTrace();
    	}
    }
    
  8. If everything above is in place and working as expected, the following code should update your status:
    String accessToken = settings.getString( "access_token", null );
    String accessTokenSecret = settings.getString( "access_token_secret", null );
    Configuration conf = new ConfigurationBuilder()
    	.setOAuthConsumerKey( OAUTH_CONSUMER_KEY )
    	.setOAuthConsumerSecret( OAUTH_CONSUMER_SECRET )
    	.setOAuthAccessToken(accessToken)
    	.setOAuthAccessTokenSecret(accessTokenSecret)
    	.build();
    Twitter t = new TwitterFactory(conf).getInstance();
    t.updateStatus( "@MokaSocial You guys rock!" );
    
  9. Sharing an image on TwitPic is simple. Go out to their site and obtain an API key. Change the code where we’re creating the Configuration to the following:
    Configuration conf = new ConfigurationBuilder()
    	.setMediaProviderAPIKey( TWITPIC_API_KEY )
    	.setOAuthConsumerKey( OAUTH_CONSUMER_KEY )
    	.setOAuthConsumerSecret( OAUTH_CONSUMER_SECRET )
    	.setOAuthAccessToken(accessToken)
    	.setOAuthAccessTokenSecret(accessTokenSecret)
    	.build();
    

    Then add the following bit to upload the image and get the URL (in our case, we’ve got the URI of the file we want to upload)

    ImageUpload upload = new ImageUploadFactory(conf).getInstance(MediaProvider.TWITPIC);
    String url = upload.upload( new File(imageUri.getPath()) );
    

Well, that’s all there is to it. A big thanks to the Twitter4j team for the slick library and Danny Gagne for the awesome presentation!

6 Comments

Have something to say? Feel free, we want to hear from you! Leave a Comment

  1. Sherwin says:

    I implemented number 8. Is OAUTH_CONSUMER_KEY is just the same with CONSUMER_KEY?

    and also, this code is not working

    Configuration conf = new ConfigurationBuilder()
    .setOAuthConsumerKey( OAUTH_CONSUMER_KEY )
    .setOAuthConsumerSecret( OAUTH_CONSUMER_SECRET )
    .setOAuthAccessToken(accessToken)
    .setOAuthAccessTokenSecret(accessTokenSecret)

    It needs variable conf to be ConfigurationBuilder.

    can you help me figure this out?

    Thanks!

    • Emory Myers says: (Author)

      Hi Sherwin! You were absolutely right that OAUTH_CONSUMER_KEY and CONSUMER_KEY were the same thing in steps 5 and 8 above – I just fixed this, good catch!

      Regarding the type of conf in step 8, it looks like you left off the last method we’re chaining on line 7 – build – which builds and returns a Configuration from the new ConfigurationBuilder.

      Hopefully this helps, thanks!

  2. Sherwin says:

    I just figured it out. Thanks for this article –cheers–

  3. Boris Lemke says:

    Hey, Im new to android dev. I went through a few tutorial, and I do understand what to do with this tutorial. Its just, I alway get problems after pasting the codes from your site. You may wanna take a look at this:

    http://dl.dropbox.com/u/33331786/eclipseerror.JPG

    Can you be more specified where i should import the jars to, and where to copy the codes to?
    Thanks, I’d appreciate any help!

    • Hey Boris, you’re on the right track – I like to keep my .jars in a /libs/ folder, that keeps it clean. Then right click them and add to build path.

      You have some more cleanup you have to do – right click on those errors and see your options – you should be declaring a lot of fields and variables like mTwitter and mRequestToken, importing a lot of classes, that kind of thing.

      Rock on with your Twitter app! And friend us on FaceBook! https://www.facebook.com/mokasocial

  4. great work !!!!! says:

    thanks for sharing great article .

Comments are now closed for this article.