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
Related
I'm developing an app using the ArcGIS Runtime SDK for Android. I'm accessing tiled basemaps from arcgis.com using the following code which works fine.
UserCredentials creds = new UserCredentials();
creds.setUserToken("token", "referer");
String mapUrlUsaTopo = "https://services.arcgisonline.com/arcgis/rest/services/USA_Topo_Maps/MapServer";
mBasemapLayer = new ArcGISTiledMapServiceLayer(mapUrlUsaTopo, creds);
But... when I attempt to download the map tiles for offline use I get the following error:
com.esri.core.io.EsriSecurityException: Message: Unable to generate token. Details: 'username' must be specified., 'password' must be specified.
Here's the download code:
String tileUrlUsaTopo = "https://tiledbasemaps.arcgis.com/arcgis/rest/services/USA_Topo_Maps/MapServer";
final ExportTileCacheTask exportTileCacheTask = new ExportTileCacheTask(tileUrlUsaTopo, creds);
Is the only option hard coding the username and password?
Andrew from Esri support was very helpful. To do "application" authentication (without a user name and password) using your app id and secret key you need something like the code below. However, there is a bug (BUG-000092420) in the android sdk and the code below does not work at the present time. I'm being told that the fix may make in into the Quartz final release.
private class AppLoginTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
Log.d("MyApp", "AppLoginTask");
Portal p = new Portal("https://www.arcgis.com", null);
try {
p.doOAuthAppAuthenticate(APP_SECRET, APP_ID, new CallbackListener<Portal>() {
#Override
public void onCallback(Portal portal) {
Log.d("MyApp", "login callback");
//mCreds = new UserCredentials();
mCreds = portal.getCredentials();
setMapDataMode(MapDataMode.ONLINE);
}
#Override
public void onError(Throwable throwable) {
Log.e("MyApp", "login error");
}
});
} catch (Exception e) {
Log.d("MyApp", "login exception");
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void results) {
Log.d("MyApp", "login post execute");
//setMapDataMode(MapDataMode.ONLINE);
}
}
I know how to login:
ParseTwitterUtils.logIn(loginView.getCurrentContext(), new LogInCallback() {
#Override
public void done(ParseUser parseUser, ParseException e) {
if (e == null) {
String welcomeMessage = "";
if (parseUser.isNew()) {
welcomeMessage = "Hello new guy!";
} else {
welcomeMessage = "Welcome back!";
}
loginView.showLoginSuccess(parseUser, welcomeMessage);
} else {
String errorMessage = "Seems we have a problem : " + e.getLocalizedMessage();
loginView.showLoginFail(errorMessage);
}
}
});
And to logout :
ParseUser.logOutInBackground(new LogOutCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
homeView.goLogin(true, "See you soon");
} else {
homeView.goLogin(false, "Error detected : " + e.getLocalizedMessage());
}
}
});
But when I want to log in again, I don't have the alert dialog asking me to choose accounts (i use the webview since Twitter app is not installed on the emulator).
How to truly logout from Parse using Twitter login?
In iOS, you can revise the source code of Parse in PFOauth1FlowDialog.m
- (void)loadURL:(NSURL *)url queryParameters:(NSDictionary *)parameters {
NSMutableDictionary *_parameter = [[NSMutableDictionary alloc] init];
[_parameter setObject:#"true" forKey:#"force_login"];
[_parameter addEntriesFromDictionary:parameters];
_loadingURL = [[self class] _urlFromBaseURL:url queryParameters:_parameter];
NSURLRequest *request = [NSURLRequest requestWithURL:_loadingURL];
[_webView loadRequest:request];
}
Then everything should work fine, And this should also work in Android.
Use the unlink functions from ParseTwitterUtils:
https://parse.com/docs/android/api/com/parse/ParseTwitterUtils.html#unlink(com.parse.ParseUser)
This will remove the link between the twitter account and the parse user.
The confusion seems to stem from the fact that the api is so straightforward.
What you're doing in the login is associating a twitter account with a parse user and logging in as that parse user. Then when you are logging out, you are only logging out of the parse user, and the twitter account is still linked to the parse user. Therefore when you go to log in again it automatically uses the twitter account to log in as the parse user.
I am new to android and i started with importing sample app from GooglePlayServices in the android SDK.
The app "Plus" allows me to sign-in using G+ credentials. The Sample code is using GoogleApiClient.
This authenticates the App only on client. How do i send access token to my server Or store the access token in to my shared preferences??
Someone please Explain me which file i should add access token code to.?
I am assuming that you are able to login to GooglePlus successfully.Do something like below to get the AccessToken and store it using SharedPreference,
SharedPreferences SharedPreference;
Editor editor;
private class GetGoogleAuthTask extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
String token = null;
try {
token=GoogleAuthUtil.getToken(User_SignUp.this,Plus.AccountApi.getAccountName(mGoogleApiClient),"oauth2:"+Scopes.PLUS_LOGIN+" "+Scopes.PLUS_ME); //Change the permissions as per your need.
} catch (IOException transientEx) {
// Network or server error, try later
Log.e(TAG, transientEx.toString());
} catch (UserRecoverableAuthException e) {
// Recover (with e.getIntent())
Log.e(TAG, e.toString());
// Intent recover = e.getIntent();
// startActivityForResult(recover, REQUEST_CODE_TOKEN_AUTH);
} catch (GoogleAuthException authEx) {
// The call is not ever expected to succeed
// assuming you have already verified that
// Google Play services is installed.
Log.e(TAG, authEx.toString());
}
return token;
}
#Override
protected void onPostExecute(String token) {
if(token!=null)
{
Log.i(TAG, "Access token retrieved:" + token);
SharedPreference = getApplicationContext().getSharedPreferences("TokenPreference", 0);
editor = SharedPreference.edit();
editor.putString("access_token",token);
editor.commit();
}
}
}
Use below snippet where you need to get the accesstoken,
new GetGoogleAuthTask().execute();
I am trying to retrieve status with Twitter4j, but I get a Unfortunately TestProject has stopped error and my app closes. I am also not getting anything in logcat so I do not know where to start troubleshooting.
This is the method executed when a button is pressed, I am basically making an instance of the class which contains all the oAuth setup and the call to the twitter API for the status. I know this should probably be done with an Async call since it deals with network, but for now I just wanted to retrieve a status even if the UI is blocked:
public void onGetStatus(View v){
if(v.getId()==R.id.button1){
GetUserStatus status = new GetUserStatus();
ResponseList<Status> a = status.twitterSettings();
for(Status s: a){
editText.setText(s.getText());
}
}
}
This is the class with all the twitter configurations for my account.
public class GetUserStatus {
public ResponseList<Status> twitterSettings(){
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setDebugEnabled(true);
cb.setOAuthConsumerKey("xxxxxx");
cb.setOAuthConsumerSecret("xxxx");
cb.setOAuthAccessToken("xxxxx");
cb.setOAuthAccessTokenSecret("xxxx");
TwitterFactory tf = new TwitterFactory(cb.build());
Twitter twitter = tf.getInstance();
try {
ResponseList<Status> a = twitter.getUserTimeline(new Paging(1,5));
return a;
} catch (TwitterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
Research I have done
I have been mostly going off twitter4j's website code examples and it seems everything is up to date so I dont think twitter4j is deprecated. I have also looked through other twitter4j questions on StackOverflow.com but most deal with 404 error or some other type of error, while I am not getting any errors.
The issue was StrictMode.ThreadPolicy was introduced since API Level 9 and the default thread policy had been changed since API Level 11, which in short, does not allow network operation
(eg: HttpClient and HttpUrlConnection) get executed on UI thread. If you do this, you get NetworkOnMainThreadException.
Using AsyncTask fixed the issue. I added a nested class within my activity
class GetUserStatus extends AsyncTask < Void, Void, ResponseList < twitter4j.Status >> {
#
Override
protected ResponseList < twitter4j.Status > doInBackground(Void...params) {
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setDebugEnabled(true);
cb.setOAuthConsumerKey("XXXX");
cb.setOAuthConsumerSecret("XXXXX");
cb.setOAuthAccessToken("XXXXX");
cb.setOAuthAccessTokenSecret("XXXXXXX");
TwitterFactory tf = new TwitterFactory(cb.build());
Twitter twitter = tf.getInstance();
try {
ResponseList < twitter4j.Status > a = twitter.getUserTimeline(new Paging(1, 5));
return a;
} catch (TwitterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
protected void onPostExecute(ResponseList < twitter4j.Status > stats) {
for (twitter4j.Status a: stats) {
editText.setText(a.getText());
}
}
}
The other issue I was having with logcat not displaying exceptions, was because Eclipse automatically selected a filter, when I chose the option "all messages (no filter)" I was able to see the stack trace.
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!