Reputation: 619
Am trying to integrate twitter with my application to share message and image on my twitter wall. But displaying following exception:
05-17 01:06:28.151: D/Twitter Update Error(22720): 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.
05-17 01:06:28.151: D/Twitter Update Error(22720): {"request":"\/1.1\/statuses\/update.json","error":"Read-only application cannot POST."}
05-17 01:06:28.161: W/System.err(22720): 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.
05-17 01:06:28.161: W/System.err(22720): {"request":"\/1.1\/statuses\/update.json","error":"Read-only application cannot POST."}
05-17 01:06:28.161: W/System.err(22720): Relevant discussions can be found on the Internet at:
05-17 01:06:28.161: W/System.err(22720): http://www.google.co.jp/search?q=2fc5b7cb or
05-17 01:06:28.161: W/System.err(22720): http://www.google.co.jp/search?q=11613e08
05-17 01:06:28.161: W/System.err(22720): TwitterException{exceptionCode=[2fc5b7cb-11613e08], statusCode=401, message=null, code=-1, retryAfter=-1, rateLimitStatus=null, version=4.0.1}
05-17 01:06:28.161: W/System.err(22720): at twitter4j.HttpClientImpl.handleRequest(HttpClientImpl.java:164)
05-17 01:06:28.161: W/System.err(22720): at twitter4j.HttpClientBase.request(HttpClientBase.java:53)
05-17 01:06:28.161: W/System.err(22720): at twitter4j.HttpClientBase.post(HttpClientBase.java:82)
05-17 01:06:28.166: W/System.err(22720): at twitter4j.TwitterImpl.post(TwitterImpl.java:2004)
05-17 01:06:28.166: W/System.err(22720): at twitter4j.TwitterImpl.updateStatus(TwitterImpl.java:251)
05-17 01:06:28.166: W/System.err(22720): at com.android.twitterapi.Item$updateTwitterStatus.doInBackground(Item.java:64)
05-17 01:06:28.171: W/System.err(22720): at com.android.twitterapi.Item$updateTwitterStatus.doInBackground(Item.java:1)
05-17 01:06:28.171: W/System.err(22720): at android.os.AsyncTask$2.call(AsyncTask.java:288)
05-17 01:06:28.171: W/System.err(22720): at java.util.concurrent.FutureTask.run(FutureTask.java:237)
05-17 01:06:28.176: W/System.err(22720): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
05-17 01:06:28.176: W/System.err(22720): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
05-17 01:06:28.176: W/System.err(22720): at java.lang.Thread.run(Thread.java:841)
Can anyone please help me? Following is my code:
MainActivity:
package com.android.twitterapi;
import me.grantland.twitter.Twitter;
import me.grantland.twitter.Twitter.DialogListener;
import me.grantland.twitter.TwitterError;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity implements OnClickListener {
public static final String CONSUMER_KEY = "fZRZJcNrFbg55dmr4rLVA";
public static final String CONSUMER_SECRET = "Xbxmn2hlT91mzydcmbnGRqOIYg8Ohipd9F8HfQYhHg";
private Twitter mTwitter;
private Button mTwitterButton;
String access_token ;
// Access Token Secret
String access_token_secret ;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
mTwitter = new Twitter(CONSUMER_KEY, CONSUMER_SECRET);
mTwitterButton = (Button)findViewById(R.id.twitter_login);
mTwitterButton.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.equals(mTwitterButton)) {
mTwitter.authorize(this, new DialogListener() {
@Override
public void onComplete(String accessKey, String accessSecret) {
access_token = accessKey;
access_token_secret = accessSecret;
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("Success")
.setMessage("access_key: " + accessKey
+ "\naccess_secret: " + accessSecret)
.setPositiveButton("Ok", null);
AlertDialog alert = builder.create();
alert.show();
new Item(MainActivity.this, accessKey, accessSecret);
}
@Override
public void onCancel() {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("Canceled")
.setMessage("Twitter Login Canceled")
.setPositiveButton("Ok", null);
AlertDialog alert = builder.create();
alert.show();
}
@Override
public void onError(TwitterError error) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("Error")
.setMessage(error.getMessage())
.setPositiveButton("Ok", null);
AlertDialog alert = builder.create();
alert.show();
}
});
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Twitter Auth Callback
mTwitter.authorizeCallback(requestCode, resultCode, data);
}
}
Item.java:
package com.android.twitterapi;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.api.TweetsResources;
import twitter4j.auth.AccessToken;
import twitter4j.conf.ConfigurationBuilder;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;
public class Item {
Activity mActivity;
String access_token;
String access_token_secret;
public Item(Activity activity, String key, String secret ) {
mActivity = activity;
access_token = key;
access_token_secret = secret;
new updateTwitterStatus().execute("Om Sri Sri Sri Veerabhadra Swamy");
}
/**
* Function to update status
* */
class updateTwitterStatus extends AsyncTask<String, String, String> {
ProgressDialog pDialog;
/**
* Before starting background thread Show Progress Dialog
* */
@Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(mActivity);
pDialog.setMessage("Updating to twitter...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
/**
* getting Places JSON
* */
protected String doInBackground(String... args) {
Log.d("Tweet Text", "> " + args[0]);
String status = args[0];
try {
ConfigurationBuilder builder = new ConfigurationBuilder();
builder.setOAuthConsumerKey(MainActivity.CONSUMER_KEY);
builder.setOAuthConsumerSecret(MainActivity.CONSUMER_SECRET);
// Access Token
AccessToken accessToken = new AccessToken(access_token, access_token_secret);
Twitter twitter = new TwitterFactory(builder.build()).getInstance(accessToken);
// Update status
twitter4j.Status response = ((TweetsResources) twitter).updateStatus(status);
Log.d("Status", "> " + response.getText());
} catch (TwitterException e) {
// Error in updating status
Log.d("Twitter Update Error", e.getMessage());
e.printStackTrace();
}
return null;
}
/**
* After completing background task Dismiss the progress dialog and show
* the data in UI Always use runOnUiThread(new Runnable()) to update UI
* from background thread, otherwise you will get error
* **/
protected void onPostExecute(String file_url) {
// dismiss the dialog after getting all products
pDialog.dismiss();
// // updating UI from Background Thread
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
Toast.makeText(mActivity,
"Status tweeted successfully", Toast.LENGTH_SHORT)
.show();
// Clearing EditText field
//// txtUpdate.setText("");
// }
// });
}
}
}
Twitter.java:
package me.grantland.twitter;
import oauth.signpost.OAuthConsumer;
import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer;
import android.app.Activity;
import android.content.Intent;
import android.util.Log;
/**
* @author Grantland Chew
*/
public class Twitter {
public static final String TAG = "me.grantland.twitter";
public static final boolean DEBUG = false;
public static final String REQUEST_TOKEN = "https://twitter.com/oauth/request_token";
public static final String ACCESS_TOKEN = "https://twitter.com/oauth/access_token";
public static final String AUTHORIZE = "https://twitter.com/oauth/authorize";
public static final String DENIED = "denied";
public static final String CALLBACK_SCHEME = "gc";
public static final String CALLBACK_URI = CALLBACK_SCHEME + "://twitt";
public static final String EXTRA_ERROR = "error";
public static final String EXTRA_CONSUMER = "consumer";
public static final String EXTRA_AUTHORIZE_PARAMS = "params";
public static final String EXTRA_ACCESS_KEY = "access_key";
public static final String EXTRA_ACCESS_SECRET = "access_secret";
// Used as default activityCode by authorize(). See authorize() below.
public static final int DEFAULT_AUTH_ACTIVITY_CODE = 4242;
private OAuthConsumer mConsumer = null;
private int mRequestCode;
private DialogListener mListener = null;
public Twitter(String consumerKey, String consumerSecret) {
if (consumerKey == null || consumerSecret == null) {
throw new IllegalArgumentException(
"You must specify your consumer key and secret when instantiating " +
"a Twitter object. See README for details.");
}
mConsumer = new CommonsHttpOAuthConsumer(consumerKey, consumerSecret);
}
/**
* Short authorize method that uses default settings.
*
* Starts either an activity or dialog that a user will use to enter their credentials
* to authorize your application with Twitter.
*
* @param activity
* The Activity to display the authorization window on.
* @param listener
* The callback for Twitter authentication responses.
* @return
*/
public boolean authorize(Activity activity, final DialogListener listener) {
return authorize(activity, false, null, DEFAULT_AUTH_ACTIVITY_CODE, listener);
}
/**
* Short authorize method that uses the default activityCode.
*
* Starts either an activity or dialog that a user will use to enter their credentials
* to authorize your application with Twitter.
*
* @param activity
* The Activity to display the authorization window on.
* @param forceLogin
* Forces the user to enter their credentials to ensure the correct users account
* is authorized.
* @param screenName
* Prefills the username input box of the OAuth login screen with the given value.
* @param listener
* The callback for Twitter authentication responses.
* @return
*/
public boolean authorize(Activity activity, boolean forceLogin, String screenName, DialogListener listener) {
return authorize(activity, forceLogin, screenName, DEFAULT_AUTH_ACTIVITY_CODE, listener);
}
/**
* Full authorize method.
*
* Starts either an activity or dialog that a user will use to enter their credentials
* to authorize your application with Twitter.
*
* @param activity
* The Activity to display the authorization window on.
* @param forceLogin
* Forces the user to enter their credentials to ensure the correct users account
* is authorized.
* @param screenName
* Prefills the username input box of the OAuth login screen with the given value.
* @param activityCode
* The requestCode used in Activity#onActivityResult. Can be changed if the default
* conflicts with another Activity in your application.
* @param listener
* The callback for Twitter authentication responses.
* @return
*/
public boolean authorize(Activity activity, boolean forceLogin, String screenName, int activityCode, DialogListener listener) {
// Optional params
String authorizeParams = "";
if (forceLogin) {
authorizeParams += "?force_login=" + forceLogin;
}
if (screenName != null) {
authorizeParams += (authorizeParams.length() == 0 ? "&" : "?") + "screen_name=" + screenName;
}
if (DEBUG) Log.d(TAG, "authorize params: " + authorizeParams);
// We could check if the activity exists in the manifest and fallback on
// the dialog, but if a user wants to use the dialog they can.
if (activityCode > 0) {
startTwitterActivity(activity, authorizeParams, activityCode, listener);
} else {
startTwitterDialog(activity, authorizeParams, listener);
}
return true;
}
private boolean startTwitterActivity(Activity activity, String authorizeParams, int activityCode, DialogListener listener) {
mRequestCode = activityCode;
mListener = listener;
Intent intent = new Intent(activity, TwitterActivity.class);
intent.putExtra(EXTRA_CONSUMER, mConsumer);
intent.putExtra(EXTRA_AUTHORIZE_PARAMS, authorizeParams);
activity.startActivityForResult(intent, DEFAULT_AUTH_ACTIVITY_CODE);
return true;
}
private boolean startTwitterDialog(Activity activity, String authorizeParams, final DialogListener listener) {
TwitterDialog dialog = new TwitterDialog(activity, mConsumer, authorizeParams, new DialogListener() {
@Override
public void onComplete(String token, String secret) {
if (DEBUG) Log.d(TAG, "access_key: " + token);
if (DEBUG) Log.d(TAG, "access_secret: " + secret);
mConsumer.setTokenWithSecret(token, secret);
listener.onComplete(token, token);
}
@Override
public void onError(TwitterError error) {
listener.onError(error);
}
@Override
public void onCancel() {
listener.onCancel();
}
});
dialog.show();
return true;
}
/**
* Callback for Twitter authorize. Should be called in any Activity that calls
* Twitter#authorize.
*
* @param requestCode
* The integer request code originally supplied to
* startActivityForResult(), allowing you to identify who this
* result came from.
* @param resultCode
* The integer result code returned by the child activity
* through its setResult().
* @param data
* An Intent, which can return result data to the caller
* (various data can be attached to Intent "extras").
*/
public void authorizeCallback(int requestCode, int resultCode, Intent data) {
if (mRequestCode != requestCode) {
return;
}
String accessKey, accessSecret;
if (Activity.RESULT_OK == resultCode) {
String error = data.getStringExtra(EXTRA_ERROR);
if (error != null) {
mListener.onError(new TwitterError(error));
} else {
accessKey = data.getStringExtra(EXTRA_ACCESS_KEY);
accessSecret = data.getStringExtra(EXTRA_ACCESS_SECRET);
if (DEBUG) Log.d(TAG, "access_key: " + accessKey);
if (DEBUG) Log.d(TAG, "access_secret: " + accessSecret);
mConsumer.setTokenWithSecret(accessKey, accessSecret);
if (mListener != null) {
mListener.onComplete(accessKey, accessSecret);
return;
}
}
} else if (Activity.RESULT_CANCELED == resultCode) {
if (mListener != null) {
mListener.onCancel();
}
}
}
//==============================================================================================
// Properties
//==============================================================================================
/**
* @return boolean - whether this object has an non-expired session token.
*/
public boolean isSessionValid() {
return mConsumer != null && (getAccessToken() != null && getAccessTokenSecret() != null);
}
/**
* @return String - the consumer_key.
*/
public String getConsumerKey() {
return mConsumer.getConsumerKey();
}
/**
* @return String - the consumer_secret.
*/
public String getConsumerSecret() {
return mConsumer.getConsumerSecret();
}
/**
* Sets the consumer_key and consumer_secret.
* @param consumerKey
* @param consumerSecret
*/
public void setConsumerKeyAndSecret(String consumerKey, String consumerSecret) {
mConsumer = new CommonsHttpOAuthConsumer(consumerKey, consumerSecret);
}
/**
* @return String - the access_token.
*/
public String getAccessToken() {
return mConsumer.getToken();
}
/**
* @return String - the access_token_secret.
*/
public String getAccessTokenSecret() {
return mConsumer.getTokenSecret();
}
/**
* Sets the access_token and access_token_secret.
* @param token
* @param secret
*/
public void setTokenWithSecret(String token, String secret) {
mConsumer.setTokenWithSecret(token, secret);
}
/**
* Callback interface for dialog requests.
*/
public static interface DialogListener {
/**
* Called when a dialog completes.
*
* Executed by the thread that initiated the dialog.
*
* @param values
* Key-value string pairs extracted from the response.
*/
public void onComplete(String accessKey, String accessSecret);
/**
* Called when a dialog has an error.
*
* Executed by the thread that initiated the dialog.
*/
public void onError(TwitterError error);
/**
* Called when a dialog is canceled by the user.
*
* Executed by the thread that initiated the dialog.
*/
public void onCancel();
}
}
TwitterActivity.java:
package me.grantland.twitter;
import oauth.signpost.OAuth;
import oauth.signpost.OAuthConsumer;
import oauth.signpost.OAuthProvider;
import oauth.signpost.commonshttp.CommonsHttpOAuthProvider;
import oauth.signpost.exception.OAuthException;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import com.android.twitterapi.R;
public class TwitterActivity extends Activity {
private static final String TAG = Twitter.TAG;
private static final boolean DEBUG = Twitter.DEBUG;
private static final int RETRIEVE_REQUEST_TOKEN = 1;
private static final int RETRIEVE_ACCESS_TOKEN = 2;
private static final String KEY_URL = "url";
private H mMainThreadHandler;
private OAuthConsumer mConsumer;
private OAuthProvider mProvider;
private ProgressDialog mSpinner;
private WebView mWebView;
/**
* Handler to run shit on the UI thread
*
* @author Grantland Chew
*/
private class H extends Handler {
@Override
public void handleMessage (Message msg) {
Bundle data = msg.getData();
switch (msg.what) {
case RETRIEVE_REQUEST_TOKEN: {
mWebView.loadUrl(data.getString(KEY_URL));
} break;
case RETRIEVE_ACCESS_TOKEN: {
} break;
default: {
}
}
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.twitter_layout);
Intent intent = getIntent();
mConsumer = (OAuthConsumer)intent.getSerializableExtra(Twitter.EXTRA_CONSUMER);
String authorizeParams = intent.getStringExtra(Twitter.EXTRA_AUTHORIZE_PARAMS);
mMainThreadHandler = new H();
mProvider = new CommonsHttpOAuthProvider(
Twitter.REQUEST_TOKEN,
Twitter.ACCESS_TOKEN,
Twitter.AUTHORIZE + authorizeParams);
mProvider.setOAuth10a(true);
mSpinner = new ProgressDialog(this);
mSpinner.setMessage(getResources().getString(R.string.loading_loading));
mSpinner.setOnCancelListener(new OnCancelListener() {
@Override public void onCancel(DialogInterface dialog) {
cancel();
}
});
mWebView = (WebView)findViewById(R.id.twitter_webview);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setSaveFormData(false);
mWebView.getSettings().setSavePassword(false);
mWebView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);
mWebView.setWebViewClient(new TwitterWebViewClient());
// Retrieve request_token on background thread
Thread thread = new Thread() {
@Override
public void run() {
try {
Message msg = new Message();
msg.what = RETRIEVE_REQUEST_TOKEN;
Bundle bundle = new Bundle();
bundle.putString(KEY_URL, mProvider.retrieveRequestToken(mConsumer, Twitter.CALLBACK_URI));
msg.setData(bundle);
if (DEBUG) Log.d(TAG, "url: " + bundle.getString(KEY_URL));
mMainThreadHandler.sendMessage(msg);
} catch (OAuthException e) {
error(e);
}
}
};
thread.start();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (KeyEvent.KEYCODE_BACK == keyCode) {
cancel();
return true; // consume event
}
return false; // don't consume event
}
private void error(Throwable error) {
Intent intent = this.getIntent();
intent.putExtra(Twitter.EXTRA_ERROR, error.getMessage());
this.setResult(RESULT_OK, intent);
finish();
}
private void cancel() {
Intent intent = this.getIntent();
this.setResult(RESULT_CANCELED, intent);
finish();
}
private void complete(String accessKey, String accessSecret) {
Intent intent = this.getIntent();
intent.putExtra(Twitter.EXTRA_ACCESS_KEY, accessKey);
intent.putExtra(Twitter.EXTRA_ACCESS_SECRET, accessSecret);
this.setResult(RESULT_OK, intent);
finish();
}
private void retrieveAccessToken(final Uri uri) {
Thread thread = new Thread() {
@Override
public void run() {
try {
if (DEBUG) Log.d(TAG, uri.toString());
String oauth_token = uri.getQueryParameter(OAuth.OAUTH_TOKEN);
String verifier = uri.getQueryParameter(OAuth.OAUTH_VERIFIER);
if (DEBUG) Log.d(TAG, oauth_token);
if (DEBUG) Log.d(TAG, verifier);
mConsumer.setTokenWithSecret(oauth_token, mConsumer.getConsumerSecret());
mProvider.retrieveAccessToken(mConsumer, verifier);
complete(mConsumer.getToken(), mConsumer.getTokenSecret());
} catch (OAuthException e) {
error(e);
}
}
};
thread.start();
}
private class TwitterWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (DEBUG) Log.d(TAG, url);
Uri uri = Uri.parse(url);
if (uri != null && Twitter.CALLBACK_SCHEME.equals(uri.getScheme())) {
String denied = uri.getQueryParameter(Twitter.DENIED);
if (denied != null) {
cancel();
} else {
retrieveAccessToken(uri);
}
return true;
}
return false;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
if (DEBUG) Log.d(TAG, "Webview loading URL: " + url);
if (view.getVisibility() != View.INVISIBLE && !mSpinner.isShowing()) {
mSpinner.show();
}
}
@Override
public void onPageFinished(WebView view, String url) {
mSpinner.dismiss();
view.setVisibility(View.VISIBLE);
}
@Override
public void onReceivedError(WebView view, int errorCode,
String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
error(new TwitterError(description, errorCode, failingUrl));
}
};
}
Upvotes: 0
Views: 1507
Reputation: 124
I can recommend you this library - https://github.com/antonkrasov/AndroidSocialNetworks
But your issue in permission of your app. Open your app settings and go to permissions tab:
Then select Read and Write and save:
Now all should work.
Upvotes: 2
Reputation: 66
I recommend you use this library. This library as explained in the book "Learning Android, 2nd Edition": It has been stripped down to the bare essentials, making it easy for you to peek at it's source code and see it's inner workings, if you care to do so. It also supports Twitter’s older API that allows for simple authentication (username and password) versus the new OAuth authentication. is much simpler to integrate and use than the one you are using. Again it depends what you want to actually do. if your purpose is to learn and you are new to Java and Android this is recommended due to focus on learning the concept rather than library and API.
Upvotes: 2