How to tweet in Twitter within Android client?

Linking to social networks may be one of special features of your program. Today I’d like to make a small demo to make a tweet in Twitter from Android. The demo will use oAuth to authenticate user with Twitter and allow him to tweet when authentication is successful. The app won’t make any authentication with username and password, the authentication process will happen at Twitter website. When the process finishes, a successful access token will be returned to notify if user entered correct log in data. We can store this token for later use without requiring user to log in again.

1. Prerequisites

First of all, you have to register your app with Twitter so that you can access Twitter accounts inside your app. Go to https://dev.twitter.com/apps , log in or sign up if you still don’t have a twitter account –> Create a new application like following image

Twitter - Create new application

For callback URL, because you’ll call Twitter from Android app, not in web app, you can enter whatever you want, for example, the homepage of your app should be good idea.

When you finish this step, go to its settings and activate option Read, Write and Access direct messages at Application Type –> Access section. This option must be activated to allow composing message directly from your phones. Double checking if this option is really activated after saving. In my case, I have to set it 3 times until it’s really saved. :(.

If you read my previous blog Google Cloud Messaging, ASP.NET Web Api and Android client, you know that we always need a key to consume any service. Twitter works such likely Google Cloud Messaging in this way, we also need keys to authenticate our apps with Twitter service. In Twitter App panel, go to your Applications –> Details –> write down Consumer Key and Consumer Secret, you’ll need it later.

Twitter Consumer and Consumer secret key

Now you’re allowed to connect your app with Twitter’s service.

Next step of course is to make library to talk with Twitter’s service. However to save time, instead of writing a library myself, I would like to use an open source library http://twitter4j.org/en/ to call Twitter’s service. Like other open source library, twitter4j is an unofficial library, use it on your risk.

With Twitter4J, you can easily integrate your Java application with the Twitter service.
Twitter4J is featuring:
✔ 100% Pure Java – works on any Java Platform version 5 or later
✔ Android platform and Google App Engine ready
✔ Zero dependency : No additional jars required
✔ Built-in OAuth support
✔ Out-of-the-box gzip support
✔ 100% Twitter API 1.1 compatible
(From twitter4j.org)

Let’s download it, extract and copy twitter4j-core-3.0.3.jar (latest version from Twitter4J website) to libs folder of your Android project(remember to make reference to it, copy alone doesn’t make it referenced in your project). We only want to compose a tweet, the core library is enough. If you want to add more advanced features, you maybe need the others too.

Twitter4j reference

2. App

Our demo program consists only of 2 simple activities. MainActivity has only one button to “Log in to Twitter”

Login to Twitter activity

The seconde one TwitterActivity is where you can compose a message and post it to your Twitter account.

Twitter Activity to compose message

In MainActivity, when you start app, it’ll check if there is internet connection available (of course, without internet connection you can’t post anything to twitter) and if you already set the Consumer Key and Consumer Secret Key (to authorize your app with Twitter)

public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);

	if (!OSUtil.IsNetworkAvailable(getApplicationContext())) {
		AlertMessageBox.Show(MainActivity.this, "Internet connection", "A valid internet connection can't be established", AlertMessageBox.AlertMessageBoxIcon.Info);
		return;
	}

	if (StringUtil.isNullOrWhitespace(ConstantValues.TWITTER_CONSUMER_KEY) || StringUtil.isNullOrWhitespace(ConstantValues.TWITTER_CONSUMER_SECRET)) {
		AlertMessageBox.Show(MainActivity.this, "Twitter oAuth infos", "Please set your twitter consumer key and consumer secret", AlertMessageBox.AlertMessageBoxIcon.Info);
		return;
	}

	initializeComponent();
}

That means the permission for internet access and accessing network state in AndroidManifest.xml is necessary.

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

If an internet connection is available and required keys were set, user will see a button “Login with Twitter” on MainActivity. When user clicks on this button, app will check if user already logged in to Twitter successfully through this app before (by checking internal app settings). If yes, user will be guided to TwitterActivity to compose a message. If no, user will be asked to sign in to Twitter with oAuth. At the sign in page of Twitter, if user authenticates himself successfully, he will be redirected to TwitterActivity. So that’s the workflow of program.

The click listener of “Login with Twitter” looks like following

private View.OnClickListener buttonLoginOnClickListener = new View.OnClickListener() {
	@Override
	public void onClick(View v) {

		SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
		if (!sharedPreferences.getBoolean(ConstantValues.PREFERENCE_TWITTER_IS_LOGGED_IN,false))
		{
			new TwitterAuthenticateTask().execute();
		}
		else
		{
			Intent intent = new Intent(MainActivity.this, TwitterActivity.class);
			startActivity(intent);
		}

	}
};

With this code listing, you’ll check in internal app settings SharedPreferences if value PREFERENCE_TWITTER_IS_LOGGED_IN was set. This value will only be set after user authenticates himself successfully with Twitter. If it isn’t set, user will be asked to sign in to Twitter by executing TwitterAuthenticateTask().

class TwitterAuthenticateTask extends AsyncTask<String, String, RequestToken> {

	@Override
	protected void onPostExecute(RequestToken requestToken) {
		Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(requestToken.getAuthenticationURL()));
		startActivity(intent);
	}

	@Override
	protected RequestToken doInBackground(String... params) {
		return TwitterUtil.getInstance().getRequestToken();
	}
}

TwitterAuthenticateTask will redirect user to authentication URL of Twitter by creating a request token and get authentication URL from it. Please take a note that the intent, that call Twitter authentication URL, was defined with Intent.ACTION_VIEW. That is an activity action to display the data to the user. This is the most common action performed on data — it is the generic action you can use on a piece of data to get the most reasonable thing to occur. For example, when used on a contacts entry it will view the entry; when used on a mailto: URI it will bring up a compose window filled with the information supplied by the URI; when used with a tel: URI it will invoke the dialer (From Google). In our case, the generated URI will invoke web browser.

Authorize app with Twitter

Click on “Authorize app”, you will be asked for username and password. Enter your Twitter log in information. If authentication is successful, Twitter will bring you back to app. If not you’ll be brought to somewhere else. ;).

Twitter redirects back to app

It is pretty simple but how request code was generated and how Twitter knows which activity he should redirect user to after successful authentication? Let’s analyze the code further. In TwitterUtil class, you’ll see that I define a singleton pattern for executing all actions relevant to Twitter such as setOAuthConsumerKey, setOAuthConsumerSecret,getRequestToken…

public final class TwitterUtil {

    private RequestToken requestToken = null;
    private TwitterFactory twitterFactory = null;
    private Twitter twitter;

    public TwitterUtil() {
        ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
        configurationBuilder.setOAuthConsumerKey(ConstantValues.TWITTER_CONSUMER_KEY);
        configurationBuilder.setOAuthConsumerSecret(ConstantValues.TWITTER_CONSUMER_SECRET);
        Configuration configuration = configurationBuilder.build();
        twitterFactory = new TwitterFactory(configuration);
        twitter = twitterFactory.getInstance();
    }

    public TwitterFactory getTwitterFactory()
    {
        return twitterFactory;
    }

    public void setTwitterFactory(AccessToken accessToken)
    {
        twitter = twitterFactory.getInstance(accessToken);
    }

    public Twitter getTwitter()
    {
        return twitter;
    }
    public RequestToken getRequestToken() {
        if (requestToken == null) {
            try {
                requestToken = twitterFactory.getInstance().getOAuthRequestToken(ConstantValues.TWITTER_CALLBACK_URL);
            } catch (TwitterException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        }
        return requestToken;
    }

    static TwitterUtil instance = new TwitterUtil();

    public static TwitterUtil getInstance() {
        return instance;
    }


    public void reset() {
        instance = new TwitterUtil();
    }
}

This class is only place where you need to put your Consumer Key and Consumer Secret Key so that a valid request token can be created. A callback URL is also necessary for creating request token, it is the “commander” who defines where Twitter redirects user when authentication is successful. In my demo, I would like to redirect user to TwitterActivity after signing in. So the TWITTER_CALLBACK_URL looks like

public static String TWITTER_CALLBACK_URL = "oauth://com.hintdesk.Twitter_oAuth";

Oh, it seems that URL has nothing to do with TwitterActivity. Yes, we still need to define one more setting in AndroidManifest.xml like following

<activity android:name=".TwitterActivity"
		  android:label="@string/app_name">
	<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="oauth" android:host="com.hintdesk.Twitter_oAuth"  />
	</intent-filter>
</activity>

Ah ha, here in the manifest, we say that TwitterActivity can be invoked by browser with data of format “oauth://com.hintdesk.Twitter_oAuth”. When Twitter is finish with his authentication, he just says “Hey browser, I’m done, invoke this data scheme for me”. When this data scheme was invoked by browser, TwitterActivity will be notified and be invoked too. But can we post a tweet right now after authentication? Unfortunately, no. We still don’t have enough information to authorize our app to make a tweet in Twitter. Therefore, when TwitterActivity starts, we have to do one more step. We have to take the access token.

private void initControl() {
	Uri uri = getIntent().getData();
	if (uri != null && uri.toString().startsWith(ConstantValues.TWITTER_CALLBACK_URL)) {
		String verifier = uri.getQueryParameter(ConstantValues.URL_PARAMETER_TWITTER_OAUTH_VERIFIER);
		new TwitterGetAccessTokenTask().execute(verifier);
	} else
		new TwitterGetAccessTokenTask().execute("");
}

Only with this access token, we can make a tweet in Twitter like this

 if (!StringUtil.isNullOrWhitespace(accessTokenString) && !StringUtil.isNullOrWhitespace(accessTokenSecret)) {
	AccessToken accessToken = new AccessToken(accessTokenString, accessTokenSecret);
	twitter4j.Status status = TwitterUtil.getInstance().getTwitterFactory().getInstance(accessToken).updateStatus(params[0]);
	return true;
}

This access token is only available after Twitter redirects user to our app after authentication. Therefore try to get access token after authentication and store it as app setting so that you can use it later without authenticating again with Twitter.

try {

	AccessToken accessToken = twitter.getOAuthAccessToken(requestToken, params[0]);
	SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
	SharedPreferences.Editor editor = sharedPreferences.edit();
	editor.putString(ConstantValues.PREFERENCE_TWITTER_OAUTH_TOKEN, accessToken.getToken());
	editor.putString(ConstantValues.PREFERENCE_TWITTER_OAUTH_TOKEN_SECRET, accessToken.getTokenSecret());
	editor.putBoolean(ConstantValues.PREFERENCE_TWITTER_IS_LOGGED_IN, true);
	editor.commit();
	return twitter.showUser(accessToken.getUserId()).getName();
} catch (TwitterException e) {
	e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
}

params[0] is the value of parameter “oauth_verifier” of URL after authentication at Twitter where you can find it in function initControl() above.

3. Conclusion

So far so good, I hope that this demo will help you to build up one more feature in your app by linking it to Twitter social network.
Source code: https://bitbucket.org/hintdesk/android-how-to-tweet-in-twitter-within-android-client
Source code of util class: https://bitbucket.org/hintdesk/android-hintdesk-core

4. Updates

4.1 Update 22.03.2014

– Update to twitter4j-core-4.0.1

4.2 Update 01.05.2014

– If you receive following error

Received authentication challenge is null
Relevant discussions can be on the Internet at
http://www.google.co.jp/search?q=6c607809 or
http://www.google.co.jp/search?q=0f1d8134
...

then in your emulator, go to Settings –> System –> Date & time and set time correctly

Android Set Date Time

4.3 Update 04.05.2014

– If you want to customize your OAuth view instead of using the default one, you can follow these steps below to create a custom WebView for OAuth.
– Create an Activity for hosting an OAuthWebViewFragment

public class OAuthActivity extends FragmentActivity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        String authenticationUrl = getIntent().getStringExtra(ConstantValues.STRING_EXTRA_AUTHENCATION_URL);
        FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
        OAuthWebViewFragment oAuthWebViewFragment = new OAuthWebViewFragment(authenticationUrl);
        fragmentTransaction.add(android.R.id.content,oAuthWebViewFragment);
        fragmentTransaction.commit();
    }
}

– The OAuthWebViewFragment will be generated by custom layout oauth_webview. After user enters correct log in data, he will be redirected to TwitterActivity like normal way.

public class OAuthWebViewFragment extends Fragment {
    private WebView webView;
    private String authenticationUrl;

    public OAuthWebViewFragment(String authenticationUrl) {
        this.authenticationUrl = authenticationUrl;
    }

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

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        webView.loadUrl(authenticationUrl);
        webView.setWebViewClient(new WebViewClient()
        {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                if (url.contains("oauth_verifier="))
                {
                    Intent intent = new Intent(getActivity().getApplicationContext(), TwitterActivity.class);
                    intent.setData( Uri.parse(url));
                    startActivity(intent);
                }
                view.loadUrl(url);
                return true;
            }
        });
        WebSettings webSettings= webView.getSettings();
        webSettings.setJavaScriptEnabled(true);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.oauth_webview,container,false);
        webView = (WebView)view.findViewById(R.id.webViewOAuth);
        return view;
    }
}

4.4 22.06.2014

A demo video to show how demo app works

90 thoughts on “How to tweet in Twitter within Android client?”

  1. yes but we have to click login button each time we start the app even if already logged in it wont ask to login again but i want that when ever we start the app we dont have to click that button it should automatically redirect us to the main page like in google+ facebook apps once logged in and whenever you start the app your main page is opened.

  2. I figured it out these apps use splash screens but the important thing to note is that google+ uses a splash screen similar to its main screen so it looks like there is no splash screen and another app evernote uses a black splash screen and it looks like there is no splash screen the app is just loading .

  3. @pallen: Maybe I still don’t understand your question. To skip the LogIn activity in the demo, you just extract the method of buttonLoginOnClickListener to a function and then call it after initializeComponent. I think it’s easy. Sample code is below

    private View.OnClickListener buttonLoginOnClickListener = new View.OnClickListener() {
    	@Override
    	public void onClick(View v) {
    		logIn();
    	}
    };
    
    private void logIn() {
    	SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
    	if (!sharedPreferences.getBoolean(ConstantValues.PREFERENCE_TWITTER_IS_LOGGED_IN,false))
    	{
    		new TwitterAuthenticateTask().execute();
    	}
    	else
    	{
    		Intent intent = new Intent(this, TwitterActivity.class);
    		startActivity(intent);
    	}
    }
    
    public void onCreate(Bundle savedInstanceState) {
    	super.onCreate(savedInstanceState);
    	setContentView(R.layout.main);
    	...
    	initializeComponent();
    	logIn();
    }
    
  4. Hi,
    I followed all the above steps.but i am getting the error message “Tweet Failed” after clicking Tweet button and also it showing “Wecome null” in the TwitterActivity.Please help me to solve this.and its urgent.
    Thanks in advance.

  5. Your last update was really good, I think it’s the best twitter integration example online, nevertheless i still have the problem to close the webview automatically at the end of the OAuth.

    Thank you!

  6. @vishwa: Debug the code and check if everything’s correct. I can’t help you with your information.
    @Brad: If you found my post good, then share it to others 😉 .What do you mean with ‘close the webview automatically at the end of the OAuth’?

  7. I made a little change in your code, I put TwtitterActivity and MainActivity in just one Activity called TwitterActivity. My problem is that after the redirection to my TwitterActivity (after the log in) the web view remains open, this is my activitie’s definition:

    Greetings, thank you

  8. @Brad: I delete one duplicate comment. For posting code, you can use the syntax below

    [code lang=java]
    Your code here
    Then close your code block with (all together no space, I have to space them so that editor won't parse them)
    [/code ]
    

    Or you can post your code on Bitbucket/GitHub then link it to your comment.

  9. In the OAuthWebViewFragment, I have an error on the constructor saying the following:
    “This fragment should provide a default constructor (a public constructor with no arguments) (com.example.whoevenknowsyou.OAuthWebViewFragment)”

    Any Ideas on the best way to fix this

  10. @Julian: I don’t know how you use OAuthWebViewFragment so I can’t help you to figure out. I also test my example again and everything is fine. I have no problem with compiling as well as executing code.

  11. whenever I press LOGIN button it takes me to the browser and asks me to “authorize app”.So, how can we skip it because once we have already “AUTHORIZED” that app. After clicking on login button it should directly redirect me to my updatestatus activity. How can we achieve this ?

  12. how can we show the authentication window in the same window in webview instead of redirecting it to browser.

  13. @nikhil: There are two options in code

     private boolean isUseStoredTokenKey = false;
     private boolean isUseWebViewForAuthentication = false;
    

    Activate this options to get what you want.

  14. Dear Sir,Thank you for your brilliant tutorial.This works perfect for me. I need your little help.if you provide me link or guide me.I want user Email address but from your code i get user id user name etc but not get user email address.Please help me

    twitter.showUser(accessToken.getUserId()).getName();

  15. Hi,
    in these lines,
    if (!OSUtil.IsNetworkAvailable(getApplicationContext())) {
    AlertMessageBox.Show(MainActivity.this, “Internet connection”, “A valid internet connection can’t be established”, AlertMessageBox.AlertMessageBoxIcon.Info);
    return;
    }

    if (StringUtil.isNullOrWhitespace(ConstantValues.TWITTER_CONSUMER_KEY) || StringUtil.isNullOrWhitespace(ConstantValues.TWITTER_CONSUMER_SECRET)) {
    AlertMessageBox.Show(MainActivity.this, “Twitter oAuth infos”, “Please set your twitter consumer key and consumer secret”, AlertMessageBox.AlertMessageBoxIcon.Info);
    return;
    }

    what is “StringUtil” ans “OSUtil”?

  16. i am detto copy your code its work but when i logout and login again then its not work properly its display some url and below display message load letter and when i close application come then its work but after immediate logout button press gain login not work
    plz help me
    thnx

  17. @Girish: I can’t help you much because I don’t know how you code looks like. You have the code in your hand, debug and find out what happens.

  18. Hi,I’m stuck with “Whoa there!There is no request token for this page. That’s the special key we need from applications asking to use your Twitter account. Please go back to the site or application that sent you here and try again; it was probably just a mistake.”App is showing this error very recently,this was not the case weeks before,made no changes to the existing working code.Saw some suggestions to adjust system clock,but no luck.This error pops up only the first time,but when running the app for 2nd time,it doesn’t show this error,works perfectly.Any help on this is highly appreciated.Thanks.

  19. When I call the getRequestToken() function from TwitterUtil.java, a TwitterException is thrown (see the code below for more details). I need help with this.

    
    // Callback URL
    public static final String TWITTER_CALLBACK_URL = "oauth://org.codelearn.twitter_oauth";
    // Callback URL for apps.twitter.com
    // http://www.codelearn.org/
    
    // MainActivity.java
    
    private class TwitterAuthenticate extends AsyncTask<Void, Void, RequestToken> {
    
        ...
    
        @Override
        protected RequestToken doInBackground(Void... params) {
            return TwitterUtility.getInstance().getRequestToken();
        } // doInBackground()
    
    } // TwitterAuthenticate
    
    // TwitterUtil.java
    
    public class TwitterUtility {
    
        [...]
    
        public RequestToken getRequestToken() {
            if (myRequestToken == null) {
                try {
                    /* Exception is thrown here
                    E/TwitterUtility: > TwitterException 401:Authentication credentials (https://dev.twitter.com/pages/auth) were missing or incorrect.
                    Ensure that you have set valid consumer key/secret, access token/secret, and the system clock is in sync.
                    E/TwitterUtility: message - Timestamp out of bounds.
                    E/TwitterUtility: code - 135 */
                    myRequestToken = myTwitterFactory.getInstance().getOAuthRequestToken(TwitterAttributes.TWITTER_CALLBACK_URL);
                } catch (TwitterException e) {
                    e.printStackTrace();
                } // catch
            } // if
            return myRequestToken;
        } // getRequestToken()
    
    } // TwitterUtility
    
    
  20. I tweaked the application slighly. Once the user is authenticated, he is redirected to TweetListActivity, where he should see all his tweets. If the user clicks on the menu item “New Tweet”, he is redirected to TweetActivity. And there he should see his name and be able to post a new tweet.

    Here is the requirement explained in more details.

    http://www.codelearn.org/android-tutorial/challenges/android-http-twitter/connecting-real-twitter

    Problem is when the initControl() function is called, the uri is null and this prevents the app from getting the username and posting a new tweet.

    Here is the github repo and sample code.

    https://github.com/charlantfr/twitterchallenge3-2

    package com.hintdesk.Twitter_oAuth;

    import …

    public class TwitterActivity extends Activity {
    String callbackURL = ConstantValues.TWITTER_CALLBACK_URL_LIST;

    public void onCreate(Bundle savedInstanceState) {

    initControl();
    }

    private void initControl() {
    // uri is null
    Uri uri = getIntent().getData();
    if (uri != null && uri.toString().startsWith(callbackURL)) {
    String verifier = uri.getQueryParameter(ConstantValues.URL_PARAMETER_TWITTER_OAUTH_VERIFIER);
    new TwitterGetAccessTokenTask().execute(verifier);
    } else
    new TwitterGetAccessTokenTask().execute(“”);
    }
    }
    [/code ]

Leave a Reply

Your email address will not be published. Required fields are marked *