im trying to post status updates to twitter. I am using the Twitter4j lib. My code runs without crashing but in the log cat is says "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.
{"request":"\/1.1\/statuses\/update.json","error":"Read-only application cannot POST."}
any help? I have signed up on twitter and i check the read and write permissions.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Runnable runnable = new Runnable() {
public void run() {
ConfigurationBuilder builder = new ConfigurationBuilder();
builder.setOAuthConsumerKey("kkwfh72794883jjg");
builder.setOAuthConsumerSecret("77j3jgweqwewerrud3434567hgfd");
// Access Token
String access_token = "lokiujyhtgrfedvwn325zckjdhdgeAHGsw23";
// Access Token Secret
String access_token_secret = "QsRgfgHJMsjeh5762JHF2dgswrfMNQljsG";
AccessToken accessToken = new AccessToken(access_token, access_token_secret);
Twitter twitter = new TwitterFactory(builder.build()).getInstance(accessToken);
// Update status
try {
twitter4j.Status response = twitter.updateStatus("updated via myapp");
Log.d("Status", "> " + response.getText());
// Error in updating status
} catch (TwitterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.d("Twitter Update Error", e.getMessage());
}
}
};
Thread mythread = new Thread(runnable);
mythread.start();
}
I was having similar issue. What I did was:
Check if your app has Read and Write permissions
If it doesn't, check the permissions radiobutton, and click Update Settings
After that, you must manually regenerate your access tokens (I regenerated consumer key, too)
Hope this will help other strugglers.
I think you should change your code:
Like this:
ConfigurationBuilder builder = new ConfigurationBuilder();
builder.setOAuthConsumerKey("kkwfh72794883jjg");
builder.setOAuthConsumerSecret("77j3jgweqwewerrud3434567hgfd");
OAuthAuthorization auth = new OAuthAuthorization(builder.build());
// Access Token
String access_token = "lokiujyhtgrfedvwn325zckjdhdgeAHGsw23";
// Access Token Secret
String access_token_secret = "QsRgfgHJMsjeh5762JHF2dgswrfMNQljsG";
Twitter twitter = new TwitterFactory().getInstance(auth);
Related
I am creating an box android app that allows user to upload media files on their account.
I have set up my client id and client secret,it is authenticating my app too.
Uploading part is also done,but the problem i am facing is to save the auth data [which is obviously needed so user is not needed to login again and again]
Load, save and use of authentication data in Box Android API
the solution given above is not working [may b they have removed 'Utils.parseJSONStringIntoObject' method]
i can store the access token and refresh token but whats the point of saving when i cant use them to re authenticate a user
switch (requestCode)
{
case AUTHENTICATE_REQUEST:
if (resultCode == Activity.RESULT_CANCELED)
{
String failMessage = data.getStringExtra(OAuthActivity.ERROR_MESSAGE);
Toast.makeText(this, "Auth fail:" + failMessage, Toast.LENGTH_LONG).show();
// finish();
}
else
{
BoxAndroidOAuthData oauth = data.getParcelableExtra(OAuthActivity.BOX_CLIENT_OAUTH);
BoxAndroidClient client = new BoxAndroidClient(BoxSDKSampleApplication.CLIENT_ID, BoxSDKSampleApplication.CLIENT_SECRET, null, null);
client.authenticate(oauth);
String ACCESS_TOKEN=oauth.getAccessToken();
String REFRESH_TOKEN=oauth.getRefreshToken();
Editor editor = prefs.edit();
editor.putString("ACCESS_TOKEN", ACCESS_TOKEN);
editor.putString("REFRESH_TOKEN", REFRESH_TOKEN);
editor.commit();
BoxSDKSampleApplication app = (BoxSDKSampleApplication) getApplication();
client.addOAuthRefreshListener(new OAuthRefreshListener()
{
#Override
public void onRefresh(IAuthData newAuthData)
{
Log.d("OAuth", "oauth refreshed, new oauth access token is:" + newAuthData.getAccessToken());
//---------------------------------
BoxOAuthToken oauthObj=null;
try
{
oauthObj=getClient().getAuthData();
}
catch (AuthFatalFailureException e)
{
e.printStackTrace();
}
//saving refreshed oauth object in client
BoxAndroidOAuthData newAuthDataObj=new BoxAndroidOAuthData(oauthObj);
getClient().authenticate(newAuthDataObj);
}
});
app.setClient(client);
}
i have referred https://github.com/box/box-android-sdk-v2/tree/master/BoxSDKSample example
can any one tell me what i am doing wrong or any alternative to authenticate user using authdata,access token,refresh token?
UPDATE
refreshing token as they have said
'Our sdk auto refreshes OAuth access token when it expires. You will want to listen to the refresh events and update your stored token after refreshing.'
mClient.addOAuthRefreshListener(new OAuthRefreshListener()
{
#Override
public void onRefresh(IAuthData newAuthData)
{
Log.d("OAuth", "oauth refreshed, new oauth access token is:" + newAuthData.getAccessToken());
try
{
oauthObj=mClient.getAuthData();
mClient.authenticate(newAuthData);
String authToken=null;
//Storing oauth object in json string format
try
{
authToken = new BoxJSONParser(new AndroidBoxResourceHub()).convertBoxObjectToJSONString(newAuthData);
prefs.edit().putString("BOX_TOKEN", authToken).commit();
//saving authToken in shared Preferences
mClient.authenticate(newAuthData);
String ACCESS_TOKEN=newAuthData.getAccessToken();
String REFRESH_TOKEN=newAuthData.getRefreshToken();
Log.v("New Access token ", oauthObj.getAccessToken());
Log.v("New Refresh token ", oauthObj.getRefreshToken());
editor.putString("ACCESS_TOKEN", ACCESS_TOKEN);
editor.putString("REFRESH_TOKEN", REFRESH_TOKEN);
prefs.edit().putString("BOX_TOKEN", authToken).commit();
editor.commit();
}
catch (BoxJSONException e1)
{
e1.printStackTrace();
}
Log.v("Token Refreshed", " ");
}
catch (AuthFatalFailureException e)
{
e.printStackTrace();
}
}
});
app.setClient(mClient);
}
onClientAuthenticated();
In main activity,fetching stored token
try
{
stored_oauth_token=prefs.getString("BOX_TOKEN", null);
authData = new BoxJSONParser(new AndroidBoxResourceHub()).parseIntoBoxObject(stored_oauth_token, BoxAndroidOAuthData.class);
}
catch (BoxJSONException e)
{
e.printStackTrace();
}
mClient = new BoxAndroidClient(BoxSDKSampleApplication.CLIENT_ID, BoxSDKSampleApplication.CLIENT_SECRET, null, null);
mClient.authenticate(authData);
BoxSDKSampleApplication app = (BoxSDKSampleApplication) getApplication();
app.setClient(mClient);
i tried this app to upload a file after existing ,it did work
but after 60-70 odd minutes i couldn't upload file.
is there anything wrong in my code ?
This is how I initialize my Box client:
mClient = new BoxClient(BOX_CLIENT_ID, BOX_CLIENT_SECRET, null, null);
mClient.addOAuthRefreshListener(new OAuthRefreshListener() {
#Override
public void onRefresh(IAuthData newAuthData) {
try {
String authToken = new BoxJSONParser(new AndroidBoxResourceHub()).convertBoxObjectToJSONString(newAuthData);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.edit().putString("box_token", authToken).commit();
} catch (BoxJSONException e) { }
}
});
mAuthToken = prefs.getString("box_token", null);
if (mAuthToken != null) {
BoxAndroidOAuthData authData = new BoxJSONParser(
new AndroidBoxResourceHub()
).parseIntoBoxObject(mAuthToken, BoxAndroidOAuthData.class);
mClient.authenticate(authData);
}
if (!mClient.isAuthenticated()) {
Intent intent = OAuthActivity.createOAuthActivityIntent(context, BOX_CLIENT_ID, BOX_CLIENT_SECRET, false, "https://yoururl.com/");
((Activity) context).startActivityForResult(intent, BOX_AUTH_REQUEST_CODE);
}
So for the auth refresh there are a couple of things to be considered:
box client automatically refreshes OAuth tokens, you'll want to attach a OAuthRefreshListener to listen to the refresh, if you want to persist, persist the oauth data passed into the refresh listener. The listener only update your persisted oauth data, you don't need to re-authenticate in the refresh listener, sdk does the re-authenticate automatically.
When you first initiate box client, you need to authenticate either by persisted auth, or the OAuth UI. The logic should be:
check client.isAuthenticated();
2.1 If authenticated, do nothing.
2.2 if not authenticated, try to check whether there's persisted auth data. If so, authenticate by client.authenticate(oauthdata);
2.3 if 2.2 failed, start OAuth UI flow.
2.4 at last, in case of OAuthFatalFailureException, start OAuth UI flow.
I've wrote some code to allow a user to login to his Twitter account and send Tweet using Twitter4j and following this tutorial.
Now I can also get the tweets of a public account using
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setHttpConnectionTimeout(10000)
.setHttpReadTimeout(10000)
.setOAuthConsumerKey(Config.TWITTER_CONSUMER_KEY)
.setOAuthConsumerSecret(Config.TWITTER_CONSUMER_SECRET)
.setOAuthAccessToken(Utils.getPrefsString(getActivity(),
TwitterPrefsFragment.PREF_KEY_OAUTH_TOKEN, "")) // empty if not authentified
.setOAuthAccessTokenSecret(Utils.getPrefsString(getActivity(),
TwitterPrefsFragment.PREF_KEY_OAUTH_SECRET, "")); // empty if not authentified
TwitterFactory tf = new TwitterFactory(cb.build());
Twitter twitter = tf.getInstance();
List<twitter4j.Status> statuses = twitter.getUserTimeline(SOME_PUBLIC_TWITTER_ACCOUNT, new Paging(1, 50));
but this only works when the user is authenticated and the app has the oauth token and secret in the preferences..
How can I get a Twitter public timeline with no Access Token, i.e. without having the user to authenticate?
EDIT
I'm reformulating my question to make it clearer:
I managed to authenticate my Twitter app and a user with the code given here.
Now, if the user is not logged in, how can I get a public timeline? In that case, there is no OAUTH_TOKEN and OAUTH_SECRET, and the request shown above does not work because an empty string is set to ConfigurationBuilder.setOAuthAccessToken and ConfigurationBuilder.setOAuthAccessTokenSecret.
So what is, if it exists, the request to get a public timeline, with no OAUTH_TOKEN and OAUTH_SECRET?
In your case, you should use Application-only authentication.
To do this with Twitter4J, try the following code
ConfigurationBuilder cb = new ConfigurationBuilder();
cb
.setOAuthConsumerKey(<YOUR_CONSUMER_KEY>)
.setOAuthConsumerSecret(<YOUR_CONSUMER_SECRET>)
.setApplicationOnlyAuthEnabled(true); // IMPORTANT: set T4J to use App-only auth
TwitterFactory tf = new TwitterFactory(cb.build());
Twitter twitter = tf.getInstance();
OAuth2Token token = twitter.getOAuth2Token();
if (token != null) {
System.out.println("Token Type : " + token.getTokenType());
System.out.println("Access Token: " + token.getAccessToken());
}
ResponseList<Status> list = twitter.getUserTimeline(783214); // Load #twitter's timeline without user login.
Key points of the above sample code:
Call setApplicationOnlyAuthEnabled(true) to enable Application-only authentication.
Get the access Token using getOAuth2Token() instead of getOAuthAccessToken()
This is certainly possible and I have already tried it. If your doubt is only regarding the Access Token and Access Token secret being empty, then you should try to use the Access Token provided in the app page. By app page I mean, the link where you have registered your twitter app.
If you go to dev.twitter.com ,and go to your app settings, you can see a consumer key, consumer secret, access token and access token secret. Make use of these and follow my below code and it should work,
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setDebugEnabled(true)
.setOAuthConsumerKey("B*************Q")
.setOAuthConsumerSecret(
"l*************o")
.setOAuthAccessToken(
"1*************s")
.setOAuthAccessTokenSecret(
"s*************s");
TwitterFactory tf = new TwitterFactory(cb.build());
twitter = tf.getInstance();
try {
List<Status> statuses;
String user;
user = "Replace this with the screen name whose feeds you want to fetch";
statuses = twitter.getUserTimeline(user);
Log.i("Status Count", statuses.size() + " Feeds");
} catch (TwitterException te) {
te.printStackTrace();
}
I used twitter 4j 3.03.jar for this.
How can I get a Twitter public timeline with no Access Token and Secret using Twitter4j?
Oh, that is very simple. YOU CAN'T.
Twitter a a data based company. 99% of the property of the company (I mean what the company owns) is data. It would be contra-productive, to give this data for free out to other people/businesses.
If the thing you want, would be possible, then there would be an easy way to backup the whole twitter database.
That is why they let you register an account for each application, that wants to use the API and limit each account to a certain amount of API calls per time frame. Of course they also want to prevent their network from spam etc.
If you want get tweets without user authenticating, you can use Application-only Authentication, because the user doesn´t need to login.
With Application-only authentication Twitter offers applications the ability to issue authenticated requests on behalf of the application itself (as opposed to on behalf of a specific user)
The application-only auth flow follows these steps:
An application encodes its consumer key and secret into a specially encoded set of credentials.
An application makes a request to the POST oauth2/token endpoint to exchange these credentials for a bearer token.
When accessing the REST API, the application uses the bearer token to authenticate.
NOTE: Because twitter4j has added this feature recently, you should use the last snapshot library.
An example using it:
private ConfigurationBuilder builder;
private Twitter twitter;
private TwitterFactory factory;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.init_act_layout);
// setup
builder = new ConfigurationBuilder();
builder.setUseSSL(true);
builder.setApplicationOnlyAuthEnabled(true);
builder.setOAuthConsumerKey(Constants.CONSUMER_KEY);
builder.setOAuthConsumerSecret(Constants.CONSUMER_SECRET);
Configuration configuration = builder.build();
factory = new TwitterFactory(configuration);
((MyApp) (MyApp.getApp())).setTFactory(factory);
if (isNeededTwitterAuth()) {
twitter = factory.getInstance();
//Get the token async and save it
}
//Search tweets
}
/*
* Checks if twitter access token is already saved in preferences
*
* #return true if auth needed
*/
private boolean isNeededTwitterAuth() {
SharedPreferences settings = getSharedPreferences(Constants.TWITTER_PREFERENCES, Context.MODE_PRIVATE);
String twitterAccesToken = settings.getString("bearerAccessToken", "");
String twitterTokenType = settings.getString("bearerTokenType", "");
return ((twitterAccesToken.length() == 0) && (twitterTokenType.length() == 0));
}
}
To get the bearer token, do it out of Main UI thread to avoid Network exception, f.i. using AsyncTask:
#Override
protected OAuth2Token doInBackground(Void... params) {
OAuth2Token bearerToken = null;
try {
bearerToken = twitter.getOAuth2Token();
} catch (TwitterException e) {
e.printStackTrace();
}
return bearerToken;
}
When you obtain the bearer token, save it:
SharedPreferences appSettings = getSharedPreferences(Constants.TWITTER_PREFERENCES, MODE_PRIVATE);
SharedPreferences.Editor prefEditor = appSettings.edit();
prefEditor.putString("bearerAccessToken", result.getAccessToken());
prefEditor.putString("bearerTokenType", result.getTokenType());
prefEditor.commit();
And to use the bearer token:
OAuth2Token bearerToken = new OAuth2Token(bearerTokenType, bearerAccesstoken);
twitter.setOAuth2Token(bearerToken);
And search tweets (always out of Main thread):
#Override
protected QueryResult doInBackground(Void... params) {
twitter.setOAuth2Token(bearerToken);
Query query = new Query();
[...]
result = twitter.search(query);
A complete explanation in the blog (in Spanish...)
And a complete example in the twitter4j github
Hope it helps!
So I'm trying to get a list of status objects from a public Twitter timeline ( not my own Twitter timeline or anything that I have admin access to, just a public one from a local organization ) using the Twitter4J library in Android Studio, but I'm getting a little confused by the documentation. I'm running into this error: "Invalid access token format."
I did create a developers account with Twitter and got a consumer key and token, as well as an access token and secret numbers. Those values are saved in a set of private static strings for now. TWITTER_ZOO_ID is a private long with the Twitter ID number for the feed that I want to display. Here's the applicable code that I currently have:
Twitter twitter;
List<Status> statuses = null;
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setDebugEnabled(true)
.setOAuthConsumerKey( TWITTER_CONSUMER_KEY )
.setOAuthConsumerSecret( TWITTER_CONSUMER_SECRET )
.setOAuthAccessToken( TWITTER_AUTH_TOKEN )
.setOAuthAccessTokenSecret( TWITTER_AUTH_TOKEN_SECRET );
try {
TwitterFactory tf = new TwitterFactory(cb.build());
twitter = tf.getInstance();
twitter.setOAuthConsumer( TWITTER_CONSUMER_KEY, TWITTER_CONSUMER_SECRET );
statuses = twitter.getUserTimeline( TWITTER_ZOO_ID );
}
catch( TwitterException e ) {
Log.e( "TwitterListFragment", "Twitter Exception" );
return;
}
for( Status status : statuses )
mAdapter.add( status );
If anyone has a link to a good example for Twitter 1.1 using Twitter4J, or can provide an example of how to get those statuses, I'd really appreciate it. I'm currently using Android Studio and including Twitter4J in Gradle from MavenCentral.
Thank you!
EDIT:
Upon further reading, I've added this additional code without success:
twitter.setOAuthConsumer( TWITTER_CONSUMER_KEY, TWITTER_CONSUMER_SECRET );
AccessToken token = new AccessToken( TWITTER_AUTH_TOKEN, TWITTER_AUTH_TOKEN_SECRET );
twitter.setOAuthAccessToken( token );
If you want to get info from a public Twitter timeline, you can use Application-only Authentication, because the user doesn´t need to login, I think it fits you because you don´t use admin rights.
The application-only auth flow follows these steps:
An application encodes its consumer key and secret into a specially
encoded set of credentials.
An application makes a request to the POST
oauth2/token endpoint to exchange these credentials for a bearer token.
When accessing the REST API, the application uses the bearer token to authenticate.
Because twitter4j has added this feature recently, you should use the last snapshot library.
An example using it:
private ConfigurationBuilder builder;
private Twitter twitter;
private TwitterFactory factory;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.init_act_layout);
// setup
builder = new ConfigurationBuilder();
builder.setUseSSL(true);
builder.setApplicationOnlyAuthEnabled(true);
builder.setOAuthConsumerKey(Constants.CONSUMER_KEY);
builder.setOAuthConsumerSecret(Constants.CONSUMER_SECRET);
Configuration configuration = builder.build();
factory = new TwitterFactory(configuration);
((MyApp) (MyApp.getApp())).setTFactory(factory);
if (isNeededTwitterAuth()) {
twitter = factory.getInstance();
//Get the token async and save it
}
//Search tweets
}
/*
* Checks if twitter access token is already saved in preferences
*
* #return true if auth needed
*/
private boolean isNeededTwitterAuth() {
SharedPreferences settings = getSharedPreferences(Constants.TWITTER_PREFERENCES, Context.MODE_PRIVATE);
String twitterAccesToken = settings.getString("bearerAccessToken", "");
String twitterTokenType = settings.getString("bearerTokenType", "");
return ((twitterAccesToken.length() == 0) && (twitterTokenType.length() == 0));
}
}
To get the bearer token, do it out of Main UI thread to avoid Network exception, f.i. using AsyncTask:
#Override
protected OAuth2Token doInBackground(Void... params) {
OAuth2Token bearerToken = null;
try {
bearerToken = twitter.getOAuth2Token();
} catch (TwitterException e) {
e.printStackTrace();
}
return bearerToken;
}
When you obtain the bearer token, save it:
SharedPreferences appSettings = getSharedPreferences(Constants.TWITTER_PREFERENCES, MODE_PRIVATE);
SharedPreferences.Editor prefEditor = appSettings.edit();
prefEditor.putString("bearerAccessToken", result.getAccessToken());
prefEditor.putString("bearerTokenType", result.getTokenType());
prefEditor.commit();
And to use the bearer token:
OAuth2Token bearerToken = new OAuth2Token(bearerTokenType, bearerAccesstoken);
twitter.setOAuth2Token(bearerToken);
And search tweets (always out of Main thread):
#Override
protected QueryResult doInBackground(Void... params) {
twitter.setOAuth2Token(bearerToken);
Query query = new Query();
[...]
result = twitter.search(query);
A complete explanation in the blog (in Spanish...)
And a complete example in the twitter4j github
Hope it helps!
I would recommend using the recently updated Twitter SDK (Fabric).
https://docs.fabric.io/android/twitter/twitter.html
I have been at this since the weekend and I am at an impasse. I am pretty new to programming and suspect I am in over my head because I have read every link under "Similar Questions" and it either does not apply or confuses me more.
I am using the Twitter4j API and I worked from code sample no. 7 on the twitter4j website on OAuth support at http://twitter4j.org/en/code-examples.html.
As a skill-building project, I want to make an Android celebrity fan app that will download the timeline from the celebrity's public account. The goal is to execute a timeline download of all the tweets. I do not want the user to login to Twitter with this app or post tweets. The app just downloads a timeline in the background and displays the tweets, probably in a list view.
My code is not executing the following line. It seems to just hang there waiting for something to happen.
RequestToken requestToken = twitter.getOAuthRequestToken();
I have internet permissions in manifest. At this point, I am so confused, I do not even know if I have registered my app correctly. I have the four keys (consumer, consumer secret, access, and access secret).
Settings
-Website: made something up
-Application Type: Read Only
-Callback URL: left it blank
-I did not opt in to "Sign In With Twitter."
OAuth Tool
-Request Type: GET
-Request URI: https://api.twitter.com/1/ (probably wrong)
This is my code:
public class TwitterActivity extends Activity
{
Button mButtonTweets;
String JSONString = null;
TextView JSONContent;
class GetTwitterTimeline extends AsyncTask<Void, String, String>
{
#Override
protected String doInBackground(Void... params)
{
try
{
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setDebugEnabled(true)
.setOAuthConsumerKey("")
.setOAuthConsumerSecret("")
.setOAuthAccessToken("")
.setOAuthAccessTokenSecret("");
TwitterFactory tf = new TwitterFactory(cb.build());
Twitter twitter = tf.getInstance();
try
{
RequestToken requestToken = twitter.getOAuthRequestToken();
AccessToken accessToken = null;
while (accessToken == null)
{
onProgressUpdate(requestToken.getAuthenticationURL());
try
{
accessToken = twitter.getOAuthAccessToken();
}//try
catch(TwitterException te)
{
if (te.getStatusCode() == 401)
{
onProgressUpdate("Unable to get the access token");
}//if
else
{
te.printStackTrace();
}//else
}//catch
}//while
onProgressUpdate("Got Access Token");
onProgressUpdate("Access Token: " + accessToken.getToken());
onProgressUpdate("Access Token Secret: " + accessToken.getTokenSecret());
}//try
catch (IllegalStateException ie)
{
if(!twitter.getAuthorization().isEnabled())
{
onProgressUpdate("OAuth consumer key/secret is not set.");
}//if
}//catch
}//try
catch (TwitterException te)
{
te.printStackTrace();
onProgressUpdate("Failed to get timeline");
}//catch
String JSONString = "JSON content will go here";
return JSONString;
}//doInBackground
protected void onProgressUpdate(String logEntry)
{
Log.d("twitter4j", logEntry);
}
#Override
protected void onPostExecute(String jsonString)
{
JSONString = jsonString;
}
}//end inner class
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_twitter);
new GetTwitterTimeline().execute();
JSONContent = (TextView) findViewById(R.id.textview_tweets);
mButtonTweets = (Button) findViewById(R.id.button_tweets);
mButtonTweets.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
JSONContent.setText(JSONString);
}
});
}
}
Twitter API has been updated. So Request URI: https://api.twitter.com/1/ won't work.
Also AFAIK the way you are trying to make the app won't work out. You need some kind of authentication. I also dumped one of my app after this API change. :(
Read the following link:
https://dev.twitter.com/docs/api/1.1/overview
I am having a hard time trying to figure out what's going on. I have the typical app structure that spawns one OAuthActivity that takes care of getting a twitter token, then my main application activity uses that token for various twitter-related operations.
My OAuthActivity works. I get an auth token, and the Twitter web screen correctly shows my application name, etc.... Besides, inside that activity, I can send a tweet and it gets published. . This means the OAuthActivity works, the clock is in sync, the token is valid, etc...
But when this OAuthActivity finishes and returns to the calling activity, whenever I try to use that token (recreating it from the persisted key/secret), no matter for what, the operation always fails with a 401, complaining that AuthChallenge reported null... just like if I provided an empty token, but i haven't !!!
Please find attached the source of my OAuthActivity, and the source of how I initialize Twitter Objects in the main activity. Please tell me if you see something wrong.
PD - I have obviously checked that the token values I assign are the same I get !! Also tried different ways of instantiating Twitter, via properties, via builder, via sets .... and nothing changes :(
EDIT-> I found around I have to call "verifyCredentials()" on the new twitter object if I want to reuse a token, but .... no luck! (please find posted exception at the end)
EDIT-2> If I use on both the child activity and the parent
mTwitter=TwitterFactory.getSingleton()
then the twitter object works, but this is not really acceptable for me because It doesnt use persistance, and I would need to authorize the application everytime. Besides, only Twitter object is authorized, TwitterStream keeps throwing exceptions.
Cheers!
Source code of the parent activity, where I try to use an access token obtained in the child activity, listed below. Whatever I try to do with this token always gets the 401.
private void init_twitter(String tok, String sec) {
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setDebugEnabled(true)
.setOAuthConsumerKey(Conf.OAUTH_CONSUMER_KEY)
.setOAuthConsumerSecret(Conf.OAUTH_CONSUMER_SECRET)
.setOAuthAccessToken(tok)
.setOAuthAccessTokenSecret(sec);
TwitterFactory tf = new TwitterFactory(cb.build());
mTwitter=tf.getInstance();
/** This always fails, even though I call this routine with the
correct token & secret !!! See at the enf of message for an alternate
routine like this one that makes use of verifyCredentials and
also fails. */
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
try {
mTwitter.updateStatus("yello 2");
} catch (TwitterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}}).start();
}
SOurce Code of the child OAuthActivity, it apparently works as I get an access token & am able to tweet:
import a lot;
public class TwitterLogin extends Activity {
private final String TAG = "TwitterLogin";
public final static String PREF_KEY_OAUTH_TOKEN="twitter.oauth.token", PREF_KEY_OAUTH_SECRET="twitter.oauth.secret", PREF_KEY_TWITTER_LOGIN="twitter.oauth.login";
private SharedPreferences mPreferences;
private Twitter twitter = new TwitterFactory().getInstance();
#Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "Starting task to retrieve request token.");
this.mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
super.onCreate(savedInstanceState);
getActionBar().setTitle("TWITTER AUTHENTICATION");
}
private void returnParent(boolean result) {
setResult(result?Activity.RESULT_OK:Activity.RESULT_CANCELED, null);
if (Conf.LOG_ON) Log.d(TAG, "TWITTER AUTH: END PROCESS , GLOBAL RESULT "+result);
/** THE FOLLOWING THING WORKS !!!!! IT SUCCESSFULLY TWEETS */
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
try {
twitter.updateStatus("yello");
} catch (TwitterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}}).start();
finish();
}
/**
* Uses TWITTER4J to get the Request URL. It gets something like
* AUTH URL TWITTER4J IS http://api.twitter.com/oauth/authorize?oauth_token=xxxxxxxxxxxxxxxxxxxxx
*
* #return The Request URL to open in webview and get the Verifier
*/
private String oauth_twitter4j_getRequestUrl() throws TwitterException {
twitter.setOAuthConsumer(Constants.CONSUMER_KEY, Constants.CONSUMER_SECRET);
RequestToken tempToken = twitter.getOAuthRequestToken(Constants.OAUTH_CALLBACK_URL);
return tempToken.getAuthorizationURL();
}
#Override
protected void onResume() {
super.onResume();
WebView webview = new WebView(this);
webview.getSettings().setJavaScriptEnabled(true);
webview.setVisibility(View.VISIBLE);
setContentView(webview);
Log.i(TAG, "Retrieving request token from Google servers");
try {
StrictMode.ThreadPolicy policy = new StrictMode. ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy);
String authorizationUrl=oauth_twitter4j_getRequestUrl();
Log.d(TAG, "AUTH URL TWITTER4J IS "+authorizationUrl_t);
webview.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView webView, String url) {
if (Conf.LOG_ON) Log.d(TAG,"WebView: "+url);
if (url != null && url.startsWith(Constants.OAUTH_CALLBACK_URL)) try {
System.out.println("TWEET TWEET TWEET");
retrieveAccessToken(url); //added this
webView.setVisibility(View.GONE); //added this
return true;
} catch (Exception e) {
e.printStackTrace();
returnParent(false);
return true;
} else return false;
}
private void saveAccessToken(AccessToken accessToken) {
// Shared Preferences
Editor e = mPreferences.edit();
// After getting access token, access token secret
// store them in application preferences
e.putString(PREF_KEY_OAUTH_TOKEN, accessToken.getToken());
e.putString(PREF_KEY_OAUTH_SECRET,accessToken.getTokenSecret());
e.putBoolean(PREF_KEY_TWITTER_LOGIN, true);
e.commit();
Log.e("Twitter OAuth Token", "> " + accessToken.getToken()+"-"+accessToken.getScreenName());
}
private void retrieveAccessToken(String url) throws Exception {
String requestToken = extractParamFromUrl(url,"oauth_token");
String verifier= extractParamFromUrl(url,"oauth_verifier");
if (Conf.LOG_ON) Log.d(TAG, "Tenemos ACCESS TOKEN y VERIFIER :"+requestToken+","+verifier+","+(new Date().toString()));
if (ONLY_TWITTER4J)
retrieveAccessToken_with4j(verifier);
else
retrieveAccessToken_signpost(verifier);
}
private void retrieveAccessToken_with4j(String verifier) throws TwitterException {
AccessToken a=twitter.getOAuthAccessToken(verifier);
saveAccessToken(a);
returnParent(true);
}
private String extractParamFromUrl(String url,String paramName) {
String queryString = url.substring(url.indexOf("?", 0)+1,url.length());
QueryStringParser queryStringParser = new QueryStringParser(queryString);
return queryStringParser.getQueryParamValue(paramName);
}
});
webview.loadUrl(authorizationUrl);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Exception I get when calling VerifyCredentials with the token I'm sure is right:
Received authentication challenge is null
W/System.err(24915): Relevant discussions can be found on the Internet at:
W/System.err(24915): http://www.google.co.jp/search?q=6f0f59ca or
W/System.err(24915): http://www.google.co.jp/search?q=20d0f74e
W/System.err(24915): TwitterException{exceptionCode=[6f0f59ca-20d0f74e 1de2170b-f94dee38], statusCode=-1, message=null, code=-1, retryAfter=-1, rateLimitStatus=null, version=3.0.3}
W/System.err(24915): at twitter4j.internal.http.HttpClientImpl.request(HttpClientImpl.java:192)
W/System.err(24915): at twitter4j.internal.http.HttpClientWrapper.request(HttpClientWrapper.java:61)
W/System.err(24915): at twitter4j.internal.http.HttpClientWrapper.get(HttpClientWrapper.java:89)
W/System.err(24915): at twitter4j.TwitterBaseImpl.fillInIDAndScreenName(TwitterBaseImpl.java:126)
W/System.err(24915): at twitter4j.TwitterImpl.verifyCredentials(TwitterImpl.java:592)
W/System.err(24915): at com.regaliz.helpers.TwitterManager$2.run(TwitterManager.java:140)
W/System.err(24915): at java.lang.Thread.run(Thread.java:856)
W/System.err(24915): Caused by: java.io.IOException: Received authentication challenge is null
W/System.err(24915): at libcore.net.http.HttpURLConnectionImpl.processAuthHeader(HttpURLConnectionImpl.java:397)
W/System.err(24915): at libcore.net.http.HttpURLConnectionImpl.processResponseHeaders(HttpURLConnectionImpl.java:345)
W/System.err(24915): at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:276)
W/System.err(24915): at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:479)
W/System.err(24915): at twitter4j.internal.http.HttpResponseImpl.<init>(HttpResponseImpl.java:34)
W/System.err(24915): at twitter4j.internal.http.HttpClientImpl.request(HttpClientImpl.java:156)
W/System.err(24915): ... 6 more
This is the function modified to make use of verifyCredentials:
private void init_twitter_2(final String tok, final String sec) throws TwitterException {
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setDebugEnabled(true)
.setOAuthConsumerKey(Conf.OAUTH_CONSUMER_KEY)
.setOAuthConsumerSecret(Conf.OAUTH_CONSUMER_SECRET);
// .setOAuthAccessToken(tok)
// .setOAuthAccessTokenSecret(sec);
TwitterFactory tf = new TwitterFactory(cb.build());
mTwitter=tf.getInstance();
Log.d(TAG, "init_twitter_2 "+tok+","+sec);
new Thread(new Runnable(){
#Override
public void run() {
// TODO Auto-generated method stub
User u;
try {
/** also tried setting token&secret like this, instead of in the builder-->no success */
mTwitter.setOAuthAccessToken(new AccessToken(tok,sec));
u = mTwitter.verifyCredentials();
Log.d(TAG, "User: "+u.getName());
} catch (TwitterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}}).start();
}
There are stupid people, stupid people, stupid people, and then it's me. For one week I've been struggling with the code, tracing Twitter4j, replicating oauths with curl, suspecting of garbage-collected activities, tracing DDMS, calculating hashes on tokens .... only to find I had 2 instances of Conf.OAUTH_CONSUMER_xxxxx with different values.
As the stuff came from constants, and the names were similar, I didn't realized that.
sigh -- 50 reputation points down the toilet!