I am using Rhomobile (for Android) to post status update on Twitter. For that, following the steps of Oauth implementation I am able to get logged in with Twitter but after login, when trying to post the status update everytime I got HTTP Response as {"errors":[{"message":"Could not authenticate you","code":32}]}.
Below is the relevant code for making the request to post status update.
def post_to_twitter(comment)
$rnd = rand(36**32).to_s(36)
$post_status_url = "https://api.twitter.com/1.1/statuses/update.json"
$oauth_token1 = #account_set.tt_oauth_token
$oauth_token_secret1 = #account_set.tt_oauth_token_secret
#oauth_nonce = $rnd
#oauth_timestamp = Time.now.to_i.to_s
#http_port = System.get_property('rhodes_port')
#url_param = "oauth_consumer_key="+ $oauth_consumer_key + "&" +
"oauth_nonce=" + #oauth_nonce + "&" +
"oauth_signature_method=" + $oauth_signature_method + "&" +
"oauth_timestamp=" + #oauth_timestamp + "&" +
"oauth_token=" + $oauth_token1 + "&" +
"oauth_version="+ $oauth_version + "&" +
"status=" + Rho::RhoSupport.url_encode("Test")
$oauth_sign = get_auth_signature($post_status_url, #url_param, "")
#auth_header = "OAuth oauth_consumer_key="+ $oauth_consumer_key + ", " +
"oauth_nonce=" + #oauth_nonce + ", " +
"oauth_signature=" + $oauth_sign + ", " +
"oauth_signature_method=" + $oauth_signature_method + ", " +
"oauth_timestamp=" + #oauth_timestamp + ", " +
"oauth_token=" + $oauth_token1 + ", " +
"oauth_version="+ $oauth_version + ", " +
"status=" + Rho::RhoSupport.url_encode("Test")
postTTres = Rho::AsyncHttp.post(
:url => $post_status_url,
:headers =>{"Content-Type" => "application/x-www-form-urlencoded", "Authorization" => #auth_header }
)
p postTTres
end
The signature generation function is as follows:
def get_auth_signature (url, url_param, secret)
signature = "POST&" + Rho::RhoSupport.url_encode(url).to_s +
"&" + Rho::RhoSupport.url_encode(url_param).to_s
key = $oauth_consumer_secret + "&" + secret
hmac = HMAC::SHA1.new(key)
hmac.update(signature)
$signature = Base64.encode64("#{hmac.digest}")
$signature = Rho::RhoSupport.url_encode("#{$signature.gsub(/\n/,'')}")
return $signature
end
The parameters values when traced are as follows:
#url_param before generating signature ---------
oauth_consumer_key=2ChmEzWBe5Y9hMYODqA1IQ&oauth_non
ce=iyb9502vspjnhj9orb87sriych16678b&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1380117614&oauth_token=244586214-M6A2jMlR7vZiqwAMrfuSj7I7XFzFTRd4
6nV6aTLK&oauth_version=1.0&status=Test`
Passing #url_param to get_auth_signature() to generate signature.
Generated signature url and signature is
Signature string ----------
POST&https%3A%2F%2Fapi.twitter.com%2F1.1%2Fstatuses%2Fupdate.
json&oauth_consumer_key%3D2ChmEzWBe5Y9hMYODqA1IQ%26oauth_nonce%3Diyb9502vspjnhj9orb87sriych16678b%26oauth_signature_method%3DHMAC-SHA1%26oauth_timesta
mp%3D1380117614%26oauth_token%3D244586214-M6A2jMlR7vZiqwAMrfuSj7I7XFzFTRd46nV6aTLK%26oauth_version%3D1.0%26status%3DTest"`
Base64 string -------
gjdXuU3qoGNt90Q2dRhNM3IXaBI%3D
Passing all these values as header Authorization to https://api.twitter.com/1.1/statuses/update.json
and got
Http Response as {"errors":[{"message":"Could not authenticate you","code":32}]}.
Also tried passing it as post parameters in :body but no luck.
postTTres = Rho::AsyncHttp.post(
:url => $post_status_url,
:headers =>{"Content-Type" => "application/x-www-form-urlencoded"},
:body => #url_param + "&oauth_signature=" + $oauth_sign
)
Checked the system timings with Twitter server timings and thats fine.
Also tried with static oauth_token that we can get from Twitter account but then too same response.
Please help me to fix this. I am unable to trace what I am missing or where I am going wrong.
Thanks
Two things:
The "status" parameter is a normal post data parameter, should not be in the authorization header, see https://dev.twitter.com/docs/api/1.1/post/statuses/update
There is a strange issue with API 1.1, with encoding special chars (like %20 for " "). The following did it for me: url encode the content of "status" for the input of the signature and do not encode it in the post data itself.
EDIT:
You forgot to supply the secret that corresponds to the user_token:
$oauth_sign = get_auth_signature($post_status_url, #url_param, "")
When you gain an access token from Twitter via https://api.twitter.com/oauth/access_token , twitter replies with an auth_token and an auth_token_secret (and the id and screen_name). You correctly supplied the auth_token in the params (and thereby to the signature), but you should supply the auth_token_secret where you currently put "".
EDIT 2:
Above edit makes me wonder: did you gain an access token using https://api.twitter.com/oauth/access_token ? Because for that you should use the oauth_token_secret that is a parameter in a call from twitter to the callback url supplied to https://api.twitter.com/oauth/request_token . This callback url is called as a response to confirmation of a user via https://api.twitter.com/oauth/authorize. For https://api.twitter.com/oauth/request_token you could use "" as a secret, since there is no auth_token yet in that phase (and thereby no corresponding secret).
Related
I am working on an application that sends an e-mail with several information. Among the information is a link to the location of the user to Google Maps. A sample of the link would be:
http://www.google.com.ph/maps/place/14°39'3.8952"N121°2'57.4116"E/#14.651082,121.049281,17z
The code looks like this:
"Google Maps Link: http://www.google.com.ph/maps/place/" +
degToDMS(location.getLatitude()) + "\"N" +
degToDMS(location.getLongitude()) + "\"E/#" +
location.getLatitude() + "," + location.getLongitude() + ",17z");
I converted the degrees longitude and latitude to DMS using a formula I found online and it seemed to be returning good data. However, when I go check the email, the link looks like:
http://www.google.com.ph/maps/place/14°39'3.8952"N121°2'57.4116"E/#14.651082,121.049281,17z
and the hyperlink ends at the first double quote (") right before the N. This is actually a bit irritating and troubling because it doesn't link the entire link properly and it is cut.
How can I escape a double quote in a link? Or is there a better way to link to Google Maps?
I used URLEncode, thanks to for3st for the lead, as such:
final String urlRaw = degToDMS(location.getLatitude()) + "\"N" +
degToDMS(location.getLongitude()) + "\"E/#" +
location.getLatitude() + "," + location.getLongitude() + ",17z";
String encodedURL = "";
try {
encodedURL = URLEncoder.encode(urlRaw, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
where urlRaw is the "problematic' part of your url (where characters don't get escaped properly or something). You DON'T put in the http://.... because it will appear as such http%3A%2F%2Fwww.google.com.ph and yeah you don't want that.
Hence, I only escaped the latter part of my url, the one that starts with the DMS coordinates.
Once I have my encodedURL variable, I simply concat it to the rest of the starting URL as such:
String link = "Google Maps Link: http://www.google.com.ph/maps/place/" + encodedURL;
and not it works.
i have a question to Google Fit.
I am creating a step counter (oh wonder g). This i have already done so far and it not really hard.
But now we come to my problem. I am only reading the steps with the Sensor API. The issue is, i can add new data via for example the Google Fit app and it will be counted in my app too. This introduces cheating and i do not want this.
So i need to have a way to only read "device created" data and not manually added data. Is there a nice way to to this?
From the SDK documentation it is not really clear how to proceed here.
So i need to have a way to only read "device created" data and not
manually added data. Is there a nice way to to this?
You will want to use Private Custom Data Types to achieve that. Read about the different types of Fitness data you can upload to Google Fit here.
1. Public data types
Standard data types provided by the platform, like com.google.step_count.delta. Any app can read and write data of
these types. For more information, see Public Data Types.
2. Private custom data types
Custom data types defined by an specific app. Only the app that defines the data type can read and write data
of this type. For more information, see Custom Data Types.
3. Shareable data types
Custom data types submitted to the platform by an app developer. Once approved, any app can read data of a
shareable type, but only whitelisted apps as specified by the
developer can write data of that shareable type. For more information,
see Shareable Data Types.
I was able to do this with the help of this alogrithm. But remember due to Android fragmentation this code still removes some of the user's data and count it as penalty
private String dumpDataSet(DataSet dataSet, int x) {
List<String> days = new ArrayList<>();
days.add("Monday");
days.add("Tuesday");
days.add("Wednesday");
days.add("Thursday");
days.add("Friday");
days.add("Saturday");
days.add("Sunday");
String day = days.get(Math.round(x / 24));
Log.d(TAG, "\tDay: " + day);
Log.i(TAG, "Data returned for Data type: " + dataSet.getDataType().getName());
DateFormat dateFormat = getTimeInstance();
String text = "";
try {
for (DataPoint dp : dataSet.getDataPoints()) {
Log.i(TAG, "\tStepCount getStreamName: " + dp.getOriginalDataSource().getStreamName());
Log.i(TAG, "\tStepCount getStreamIdentifier: " + dp.getOriginalDataSource().getStreamIdentifier());
Log.i(TAG, "\tStepCount App Type: " + dp.getDataType().getName());
Log.i(TAG, "\tStepCount Type: " + dp.getOriginalDataSource().getType());
for (Field field : dp.getDataType().getFields()) {
Log.i(TAG, "\tField: " + field.getName() + " Value: " + dp.getValue(field));
text += dp.getValue(field);
String si[] = dp.getOriginalDataSource().getStreamIdentifier().toLowerCase().split(":");
if ((((si[si.length - 1].contains("soft")) || (si[si.length - 1].contains("step"))) && si[si.length - 1].contains("counter"))) {
totalSteps += Integer.parseInt(dp.getValue(field).toString());
Log.d(TAG, "\tStepCount" + " Added Steps -> " + dp.getValue(field) + " steps");
text += "\n\n";
} else {
Log.e(TAG, "\tStepCount PENALTY ---------------------------------------------------------------");
Log.e(TAG, "\tDay = " + day + " | Hour Number = " + x + " | StepCount" + " PENALTY DEDUCTED -> " + dp.getValue(field) + " steps");
Log.e(TAG, "\tStepCount PENALTY getStreamIdentifier: " + dp.getOriginalDataSource().getStreamIdentifier());
Log.e(TAG, "\tStepCount PENALTY getStreamName: " + dp.getOriginalDataSource().getStreamName());
Log.e(TAG, "\tStepCount PENALTY App Type: " + dp.getDataType().getName());
Log.e(TAG, "\tStepCount PENALTY Type: " + dp.getOriginalDataSource().getType());
Log.e(TAG, "\tStepCount PENALTY ---------------------------------------------------------------");
}
}
}
} catch (Exception ex) {
ex.getStackTrace();
}
return text;
}
----- UPDATE -----
You can also call
DataPoint.getOriginalDataSource().getAppPackageName()
to filter out smartwatches and other apps.
I tried as suggested by Ali Shah lakhani but
DataPoint.getOriginalDataSource().getAppPackageName();
/*I also tried but could not achieve what I wanted*/
DataPoint.getOriginalDataSource().getStreamName();
DataPoint.getOriginalDataSource().getStreamIdentifier();
did not work at least for me while retrieving data. I ended up using readDailyTotalFromLocalDevice() as shown below in order to capture steps captured by device only.
Fitness.HistoryApi.readDailyTotalFromLocalDevice(mApiClient, DataType.TYPE_STEP_COUNT_DELTA).await(1, TimeUnit.MINUTES)
I cross checked the same with some of the apps that avoids manual entries in their app and the count provided by the function above is exactly the same.
Note: If a user is having multiple devices and is using the app on all of them, readDailyTotalFromLocalDevice() will have different value for each and every device since the function is responsible for returning device specific data only.
I used browser key and android key only but it will not working....
what number of different key do i need to used for autouggestion and get LatLng from that will placs name in suggestion.
private String getAutoCompleteUrl(String place) {
// Obtain browser key from https://code.google.com/apis/console
String key = "key=AIzaSyAVYq6kcBUABAtMIDil-8GDoDvWMi3QLnE";
// place to be be searched
String input = "input=" + place;
// place type to be searched
String types = "types=geocode";
// Sensor enabled
String sensor = "sensor=false";
// Building the parameters to the web service
String parameters = input + "&" + types + "&" + sensor + "&" + key;
// Output format
String output = "json";
// Building the url to the web service
String url = "https://maps.googleapis.com/maps/api/place/autocomplete/"
+ output + "?" + parameters;
return url;
}
private String getPlaceDetailsUrl(String ref) {
// Obtain browser key from https://code.google.com/apis/console
String key = "key=AIzaSyAVYq6kcBUABAtMIDil-8GDoDvWMi3QLnE";
// reference of place
String reference = "reference=" + ref;
// Sensor enabled
String sensor = "sensor=false";
// Building the parameters to the web service
String parameters = reference + "&" + sensor + "&" + key;
// Output format
String output = "json";
// Building the url to the web service
String url = "https://maps.googleapis.com/maps/api/place/details/"
+ output + "?" + parameters;
Log.d("url:",url);
return url;
}
You just need browser api key to get autocomplete place suggestions using the above method..
Below 2 tutorials will help you understand it in better way:
http://wptrafficanalyzer.in/blog/android-autocompletetextview-with-google-places-autocomplete-api/
OR
http://codetheory.in/google-place-api-autocomplete-service-in-android-application/
But if you are looking to use Google Places API for Android below tutorial explains it very clearly:
http://www.truiton.com/2015/04/android-places-api-autocomplete-getplacebyid/
And if you are looking for the difference between the two [browser and Android key]
this SO Answer pretty much explains it.
Hope it helps !!
I am not 100% sure if this works in all cases, but afaik you don't need a key anymore. So try this:
String parameters = input + "&" + types + "&" + sensor;
I'm developing a game with Unity3D for Android. I'm using Facebook App for sharing game score in Facebook. But I receive a error message ;
My codes are here ;
//facebook share start
public static void share(string link, string pictureLink, string name,string caption, string description, string redirectUri){
Application.OpenURL(ShareUrl +
"?app_id=" + AppId +
"&link=" + WWW.EscapeURL( link )+
"&picture=" + WWW.EscapeURL(pictureLink) +
"&name=" + WWW.EscapeURL(name) +
"&caption=" + WWW.EscapeURL(caption) +
"&description=" + WWW.EscapeURL(description) +
"&redirect_uri=" + WWW.EscapeURL(redirectUri));
}//facebook share end
if(GUI.Button(new Rect(Screen.width/2,(Screen.height/2-30),80,20), "Share")){
print("Share");
share("http://www.halilcosgun.com","https://24.media.tumblr.com/avatar_ce3a5b939737_64.png","Facebook skor paylaşma denemesi " + score,"Skor da mı paylaşmıyah?","oyun çok yakında!","http://facebook.com");
}
I tried to write many adresses (many many configurations) intead of "http://facebook.com", but I can't find the true one.
If you know the solution, can you halp me please?
I would like to thank you for your interest.
there must me an invalid parameter that you have provided . try to find it out and make the change it will solve your issue
try the share with first s in caps example
Share("http://www.halilcosgun.com","https://24.media.tumblr.com/avatar_ce3a5b939737_64.png","Facebook skor paylaşma denemesi " + score,"Skor da mı paylaşmıyah?","oyun çok yakında!","http://facebook.com");
}
I construct a URL with the following bit of code:
String login = rootActivity.getString(R.string.url_authentication);
login = login + "user=" + mySharedPreferences.getString("username", "invalid") + "&" + "key=" + mySharedPreferences.getString("key", "invalid");
login = login.toLowerCase(Locale.US);
System.out.println("Logging in at " + login);
new HttpConnection(handler).get(login);
The URL is valid, as far as I can see visually, but the HttpConnection fails because there's an illegal character in the URL at the index of the ampersand. What really flummoxes me is, the app has between 1,000 and 5,000 installs, and we have a total of two reports of this over the past year – both from American users using Samsung devices, so I doubt it's a character encoding issue.
Don't forget to urlEncode your parameters.
login = login + "user=" + URLEncoder.encode( mySharedPreferences.getString("username", "invalid") ) + "&" + "key=" + URLEncoder.encode( mySharedPreferences.getString("key", "invalid") );
Don't know what login is, but is there a question mark on the end of it? If you're don't something like www.example.comuser="something"&key="somethingElse" then that won't work.
Having a raw & (amplisand) will lead to an error, you should encode your special characters.
Do this:
String login = URLEncoder.encode(login);
http://developer.android.com/reference/java/net/URLEncoder.html#encode(java.lang.String)