Implemented this myself so thought I would share.
This isn’t the prettiest solution but it gives you all the facts and is nice an quick.
I’ve kept it all in one Activity to try and give you the overview you can deal with the OO later yourself.
Source file downloads are at the bottom of this post.
Ok What we are going to do:
Authorise your app to use a users twitter account.
Send a tweet from this account.
Workflow:
User presses Login Button
Checks if user has logged in before
Twitter webpage is opened
User logins in to twitter
App is then allowed to post tweets
Users presses Tweet Button
Tweet is sent to Twitter
Simple!
A sneak preview of what it’ll look like:
Setup:
You need to create a Twitter Application (takes 2 mins) on the Twitter site: https://dev.twitter.com/apps/
Ensure
Application Type: Browser
Permissions: Read & Write
Callback URL; doesnt matter put anything https://google.com
Next you need the Twitter4j Jar, this does all the hard work behind the scenes.
You can download it here: Twitter4J jar
Unzip it.
You then have to add it to your project.
Eclipse:
Right Click on your project > Properties > Java Build Path > Add External Jars > twitter4j-core-android-2.2.3.jar> OK
Easy!
Ok now to the coding!
First your manifest needs to be able to receive the twitter call back from the browser, it also needs the activity to be single instance:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="https://schemas.android.com/apk/res/android" package="com.blundell.tut.ttt" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="4" /> <!-- used by twitter integration --> <uses-permission android:name="android.permission.INTERNET" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".TweetToTwitterActivity" android:label="@string/app_name" android:launchMode="singleInstance"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </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="tweet-to-twitter-blundell-01-android" /> </intent-filter> </activity> </application> </manifest>
Then I’ve compacted it all into a single Activity with comments so you should be able to understand what is going on:
package com.blundell.tut.ttt; import twitter4j.Twitter; import twitter4j.TwitterException; import twitter4j.TwitterFactory; import twitter4j.auth.AccessToken; import twitter4j.auth.RequestToken; import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.View; import android.webkit.WebView; import android.widget.Button; import android.widget.Toast; public class TweetToTwitterActivity extends Activity { private static final String TAG = "Blundell.TweetToTwitterActivity"; /** Name to store the users access token */ private static final String PREF_ACCESS_TOKEN = "accessToken"; /** Name to store the users access token secret */ private static final String PREF_ACCESS_TOKEN_SECRET = "accessTokenSecret"; /** Consumer Key generated when you registered your app at https://dev.twitter.com/apps/ */ private static final String CONSUMER_KEY = "yourConsumerKey"; /** Consumer Secret generated when you registered your app at https://dev.twitter.com/apps/ */ private static final String CONSUMER_SECRET = "yourConsumerSecret"; // XXX Encode in your app /** The url that Twitter will redirect to after a user log's in - this will be picked up by your app manifest and redirected into this activity */ private static final String CALLBACK_URL = "tweet-to-twitter-blundell-01-android:///"; /** Preferences to store a logged in users credentials */ private SharedPreferences mPrefs; /** Twitter4j object */ private Twitter mTwitter; /** The request token signifies the unique ID of the request you are sending to twitter */ private RequestToken mReqToken; private Button mLoginButton; private Button mTweetButton; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.i(TAG, "Loading TweetToTwitterActivity"); setContentView(R.layout.main); // Create a new shared preference object to remember if the user has // already given us permission mPrefs = getSharedPreferences("twitterPrefs", MODE_PRIVATE); Log.i(TAG, "Got Preferences"); // Load the twitter4j helper mTwitter = new TwitterFactory().getInstance(); Log.i(TAG, "Got Twitter4j"); // Tell twitter4j that we want to use it with our app mTwitter.setOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET); Log.i(TAG, "Inflated Twitter4j"); mLoginButton = (Button) findViewById(R.id.login_button); mTweetButton = (Button) findViewById(R.id.tweet_button); } /** * Button clickables are declared in XML as this projects min SDK is 1.6</br> </br> * Checks if the user has given this app permission to use twitter * before</br> If so login and enable tweeting</br> * Otherwise redirect to Twitter for permission * * @param v the clicked button */ public void buttonLogin(View v) { Log.i(TAG, "Login Pressed"); if (mPrefs.contains(PREF_ACCESS_TOKEN)) { Log.i(TAG, "Repeat User"); loginAuthorisedUser(); } else { Log.i(TAG, "New User"); loginNewUser(); } } /** * Button clickables are declared in XML as this projects min SDK is 1.6</br> </br> * * @param v the clicked button */ public void buttonTweet(View v) { Log.i(TAG, "Tweet Pressed"); tweetMessage(); } /** * Create a request that is sent to Twitter asking 'can our app have permission to use Twitter for this user'</br> * We are given back the {@link mReqToken} * that is a unique indetifier to this request</br> * The browser then pops up on the twitter website and the user logins in ( we never see this informaton * )</br> Twitter then redirects us to {@link CALLBACK_URL} if the login was a success</br> * */ private void loginNewUser() { try { Log.i(TAG, "Request App Authentication"); mReqToken = mTwitter.getOAuthRequestToken(CALLBACK_URL); Log.i(TAG, "Starting Webview to login to twitter"); WebView twitterSite = new WebView(this); twitterSite.loadUrl(mReqToken.getAuthenticationURL()); setContentView(twitterSite); } catch (TwitterException e) { Toast.makeText(this, "Twitter Login error, try again later", Toast.LENGTH_SHORT).show(); } } /** * The user had previously given our app permission to use Twitter</br> * Therefore we retrieve these credentials and fill out the Twitter4j helper */ private void loginAuthorisedUser() { String token = mPrefs.getString(PREF_ACCESS_TOKEN, null); String secret = mPrefs.getString(PREF_ACCESS_TOKEN_SECRET, null); // Create the twitter access token from the credentials we got previously AccessToken at = new AccessToken(token, secret); mTwitter.setOAuthAccessToken(at); Toast.makeText(this, "Welcome back", Toast.LENGTH_SHORT).show(); enableTweetButton(); } /** * Catch when Twitter redirects back to our {@link CALLBACK_URL}</br> * We use onNewIntent as in our manifest we have singleInstance="true" if we did not the * getOAuthAccessToken() call would fail */ @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); Log.i(TAG, "New Intent Arrived"); dealWithTwitterResponse(intent); } @Override protected void onResume() { super.onResume(); Log.i(TAG, "Arrived at onResume"); } /** * Twitter has sent us back into our app</br> * Within the intent it set back we have a 'key' we can use to authenticate the user * * @param intent */ private void dealWithTwitterResponse(Intent intent) { Uri uri = intent.getData(); if (uri != null && uri.toString().startsWith(CALLBACK_URL)) { // If the user has just logged in String oauthVerifier = uri.getQueryParameter("oauth_verifier"); authoriseNewUser(oauthVerifier); } } /** * Create an access token for this new user</br> * Fill out the Twitter4j helper</br> * And save these credentials so we can log the user straight in next time * * @param oauthVerifier */ private void authoriseNewUser(String oauthVerifier) { try { AccessToken at = mTwitter.getOAuthAccessToken(mReqToken, oauthVerifier); mTwitter.setOAuthAccessToken(at); saveAccessToken(at); // Set the content view back after we changed to a webview setContentView(R.layout.main); enableTweetButton(); } catch (TwitterException e) { Toast.makeText(this, "Twitter auth error x01, try again later", Toast.LENGTH_SHORT).show(); } } /** * Allow the user to Tweet */ private void enableTweetButton() { Log.i(TAG, "User logged in - allowing to tweet"); mLoginButton.setEnabled(false); mTweetButton.setEnabled(true); } /** * Send a tweet on your timeline, with a Toast msg for success or failure */ private void tweetMessage() { try { mTwitter.updateStatus("Test - Tweeting with @Blundell_apps #AndroidDev Tutorial using #Twitter4j https://blog.blundellapps.co.uk/sending-a-tweet"); Toast.makeText(this, "Tweet Successful!", Toast.LENGTH_SHORT).show(); } catch (TwitterException e) { Toast.makeText(this, "Tweet error, try again later", Toast.LENGTH_SHORT).show(); } } private void saveAccessToken(AccessToken at) { String token = at.getToken(); String secret = at.getTokenSecret(); Editor editor = mPrefs.edit(); editor.putString(PREF_ACCESS_TOKEN, token); editor.putString(PREF_ACCESS_TOKEN_SECRET, secret); editor.commit(); } }
If you find this helpful please say thanks 🙂 Happy Coding
And any questions just ask!
The eclipse project src as promised:
—> TweetToTwitter <---
I am getting “Twitter Login error, try again later”. In my case it’s giving me problem in this line.
mReqToken = mTwitter.getOAuthRequestToken(CALLBACK_URL);
It’s crashing from here. it directly goes to catch didn’t even execute the webview part. I found this may be because of wrong time in device. But I double checked that’s not a problem. Cay any one guide me what could be issue behind this?
Thanks in advance.
HI ! I’ve followed your code, and it works! But i have a problem: I want that after the Twitter name/passw step,instead of returning to the mainActivity, I need to go to another Activity…how can I do that?
Thanks in advance!
I believe you just need to edit the intent filter in your AndroidMAnifest
thanks million times. This works perfectly.