Android Post to Rails Server - android

I'm trying to setup a survey that my app users can take that will post the results to a rails app. The survey/questions/answers are built in the rails app, then displayed in the Android app. After the user answers each question it should post back to the server.
I suspect that it's something to do with my create method (the uncommented line works for creating a choice in the rails app but not for the Android post and the commented line appears to work for neither) but I'm relatively new to Android/Rails so any help would be much appreciated!
Here's my ChoicesController:
class ChoicesController < ApplicationController
# POST /choices
# POST /choices.json
def create
#question = Question.find(params[:question_id])
#choice = #question.choices.build(choice_params)
#choice.answer = Answer.find(params[:choice][:answer_id])
# #choice.answer = Answer.find(params[:answer_id])
respond_to do |format|
if #choice.save
format.html { redirect_to question_choices_path, notice: 'Choice was successfully created.' }
format.json { render action: 'show', status: :created, location: #choice }
else
format.html { render action: 'new' }
format.json { render json: #choice.errors, status: :unprocessable_entity }
end
end
end
My choice model:
class Choice < ActiveRecord::Base
belongs_to :question
belongs_to :answer
belongs_to :user
validates :question_id, presence: true
validates :answer_id, presence: true
end
Here's how I'm creating/posting my json in Android:
public boolean postChoice(String apiKey) {
boolean choicePosted = false;
try {
post();
} catch (Exception e) {
e.printStackTrace();
}
choicePosted = true;
return choicePosted;
}
public static void post() {
Map<String, String> choice = new HashMap<String, String>();
choice.put("question_id", "6");
choice.put("answer_id", "15");
String json = new GsonBuilder().create().toJson(choice, Map.class);
makeRequest("http://localhost:3000/choices/", json);
}
public static HttpResponse makeRequest(String uri, String json) {
try {
HttpPost httpPost = new HttpPost(uri);
httpPost.setEntity(new StringEntity(json));
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Content-type", "application/json");
return new DefaultHttpClient().execute(httpPost);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
Any help is much appreciated!

One big problem with your code is:
} catch (Exception e) {
e.printStackTrace();
}
You are swallowing all exceptions and my guess you are also swallowing the problem exception. You should look into logs what exception is recorded and also not use catch (Exception e) but instead have explicit exception.
Without actual exception it hard to diagnose, but my guess is that you are making this http request inside UI thread and Android framework explicitly forbids it (it makes your app non-responsive) and throws an exception.

Turns out the biggest problem I had was that I was not sending a CSRF token with my POST. including skip_before_action :verify_authenticity_token solved my problem. Since it's an API I have a few other security verification piece in place, but CSRF really only applies to web forms anyway.

Related

How to http post two different json objects in single entity?

#Override
protected Void doInBackground(Void... arg0) {
HttpClient httpClient = new DefaultHttpClient();
// Creating HTTP Post
HttpPost httpPost = new HttpPost("www.somewebsite.com");
httpPost.setHeader("Content-type", "application/json");
try {
httpPost.setEntity(new StringEntity(getJSONString(), "UTF-8"));
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// Making HTTP Request
try {
HttpResponse response = httpClient.execute(httpPost);
System.out.println(response.getStatusLine().getStatusCode());
} catch (ClientProtocolException e) {
// writing exception to log
e.printStackTrace();
} catch (IOException e) {
// writing exception to log
e.printStackTrace();
}
}
This works fine for me. However I want to send other jsonobject with business data to server. How can I do that?
Just merge the 2 JSONObjects into 1.
{
"json_1": {
"a": "1"
},
"json_2": {
"b": "2"
}
}
YOu can only send one entity, so your function getJSONString() will need to be updated to return both objects as one string.
You might want to consider sending a proper JSON list.
[
{ /* object one */ },
{ /* object two */ }
]
I think this is much more preferable over a 'combined object'
{
"object one" : { /* object one */ },
"object two" : { /* object two */ }
}
Using a combined object makes it awkward to parse, as you have to explicitly get each sub object out of the main object. With the array, you can simply loop through each element of the list, which means adding more to the list is as easy as adding more to the list. Your exact usage may mean that the combined object is better, such as if you need to know the exact order the sub-objects should be handled; JSON lists are unordered you see.
Simple! Club both json's using a separator, and then delimit using the separator on the server.
Or build a new json object with both jsons' and send a common json object to the server.
Nithin

How does RequestFactory know what Android user is logged in

I have an Android app that successfully uses RequestFactory to manipulate Entities in AppEngine Datastore.
In my AppEngine service, I want to use
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
to get information about the current Android user, but getCurrentUser() returns null.
How does my Android app let RequestFactory know who is logged in?
This question applies to dev mode and production mode.
Thanks.
There is a not-so-obvious answer found in the old AppEngine Connected Android Eclipse wizard code, which is no longer available in the GPE (see Util.java of this wizard generated code). It includes the following:
T requestFactory = RequestFactorySource.create(factoryClass);
requestFactory.initialize(new SimpleEventBus(),
new AndroidRequestTransport(uri, authCookie));
with
public AndroidRequestTransport(URI uri, String cookie) {
this.uri = uri;
this.cookie = cookie;
}
public void send(String payload, TransportReceiver receiver) {
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost();
post.setHeader("Content-Type", "application/json;charset=UTF-8");
post.setHeader("Cookie", cookie);
post.setURI(uri);
Throwable ex;
try {
post.setEntity(new StringEntity(payload, "UTF-8"));
HttpResponse response = client.execute(post);
if (200 == response.getStatusLine().getStatusCode()) {
String contents = readStreamAsString(response.getEntity().getContent());
receiver.onTransportSuccess(contents);
} else {
receiver.onTransportFailure(new ServerFailure(response.getStatusLine()
.getReasonPhrase()));
}
return;
} catch (UnsupportedEncodingException e) {
ex = e;
} catch (ClientProtocolException e) {
ex = e;
} catch (IOException e) {
ex = e;
}
receiver.onTransportFailure(new ServerFailure(ex.getMessage()));
}
Using that code from the GPE wizard did the trick for me.

Android facebook graph batch api

I am trying to use graph batch api , is there any reference code ? how do we set the
parameters ? Has anyone used batch api with reference to android apps
I am using this link
and I've also have used individual graph apis such as
fbApiObj.request("me/notifications");
fbApiObj.request("me/home");fbApiObj.request("me/friends");
I want to batch them. The explanation provided in the link above is not very clear as to how to convert to api calls.
What you need to do is build a JSONArray for your request, and then convert that JSONArray to a string before you send it to the server using HTTPS POST. For each request, make a JSONObject according to the Facebook API (link previously posted), then add all these JSONObjects to a JSONArray and use the Facebook SDK's built-in "openUrl" method (located in the Util class inside the SDK).
Here's a small example that I built for testing the batch.
JSONObject me_notifications = new JSONObject();
try {
me_notifications.put("method", "GET");
me_notifications.put("relative_url", "me/notifications");
} catch (JSONException e) {
e.printStackTrace();
Log.e(TAG, e.getMessage());
}
JSONObject me_home = new JSONObject();
try {
me_home.put("method", "GET");
me_home.put("relative_url", "me/home");
} catch (JSONException e) {
e.printStackTrace();
Log.e(TAG, e.getMessage());
}
JSONObject me_friends = new JSONObject();
try {
me_friends.put("method", "GET");
me_friends.put("relative_url", "me/friends");
} catch (JSONException e) {
e.printStackTrace();
Log.e(TAG, e.getMessage());
}
JSONArray batch_array = new JSONArray();
batch_array.put(me_home);
batch_array.put(me_notifications);
batch_array.put(me_friends);
new FacebookBatchWorker(this, mHandler, false).execute(batch_array);
And the FacebookBatchWorker is simply an asynctask (just use any threading you want really...). The important part is the HTTPS request, I used the already available ones inside the facebook SDK, like this.
The "params[0].toString()" is the JSONArray I sent to the AsyncTask, we need that converted to a String for the actual post request.
/* URL */
String url = GRAPH_BASE_URL;
/* Arguments */
Bundle args = new Bundle();
args.putString("access_token", FacebookHelper.getFacebook().getAccessToken());
args.putString("batch", params[0].toString());
String ret = "";
try {
ret = Util.openUrl(url, "POST", args);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Hopefully you'll get something out of this...
The batch requests from the facebook graph API are available through HTTP requests. It does not matter whether the request comes from an android phone or not.
It is a quite recent feature and the facebook android sdk has not been updated recently in github, so you will need to handle those requests directly.
Reference: http://developers.facebook.com/docs/reference/api/batch/

Twitter + OAuth Integration

Anybody can please help in Android + Twitter Integration using OAuth.
I already worked on http://github.com/brione/Brion-Learns-OAuth and getting the error listed below, when I am posting status update...
WARN/System.err(190): org.apache.http.client.HttpResponseException: Unauthorized
WARN/System.err(190): at org.apache.http.impl.client.BasicResponseHandler.handleResponse(BasicResponseHandler.java:71)
WARN/System.err(190): at org.apache.http.impl.client.BasicResponseHandler.handleResponse(BasicResponseHandler.java:59)
WARN/System.err(190): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:657)
WARN/System.err(190): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:627)
WARN/System.err(190): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:616)
WARN/System.err(190): at com.test.twitter.BLOA$PostTask.doInBackground(BLOA.java:343)
WARN/System.err(190): at com.test.twitter.BLOA$PostTask.doInBackground(BLOA.java:1)
WARN/System.err(190): at android.os.AsyncTask$2.call(AsyncTask.java:185)
WARN/System.err(190): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:256)
WARN/System.err(190): at java.util.concurrent.FutureTask.run(FutureTask.java:122)
WARN/System.err(190): at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:648)
WARN/System.err(190): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:673)
WARN/System.err(190): at java.lang.Thread.run(Thread.java:1060)
I succeed with OAuth Authentication and getting user_secret and user_token and stored in preferences...
So the issue is with http posting using OAuth header...
and My Http Post Method is as :
private class PostTask extends AsyncTask<String, Void, JSONObject> {
ProgressDialog postDialog;
#Override
protected void onPreExecute() {
postDialog = ProgressDialog.show(BLOA.this,
getText(R.string.tweet_progress_title),
getText(R.string.tweet_progress_text), true, // indeterminate
// duration
false); // not cancel-able
}
#Override
protected JSONObject doInBackground(String... params) {
JSONObject jso = null;
try {
HttpPost post = new HttpPost(
"http://twitter.com/statuses/update.json");
LinkedList<BasicNameValuePair> out = new LinkedList<BasicNameValuePair>();
out.add(new BasicNameValuePair("status", params[0]));
post.setEntity(new UrlEncodedFormEntity(out, HTTP.UTF_8));
post.setParams(getParams());
// sign the request to authenticate
mConsumer.sign(post);
String response = mClient.execute(post,
new BasicResponseHandler());
jso = new JSONObject(response);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (OAuthMessageSignerException e) {
e.printStackTrace();
} catch (OAuthExpectationFailedException e) {
e.printStackTrace();
} catch (OAuthCommunicationException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
} finally {
}
return jso;
}
// This is in the UI thread, so we can mess with the UI
protected void onPostExecute(JSONObject jso) {
postDialog.dismiss();
if (jso != null) { // authorization succeeded, the json object
// contains the user information
mEditor.setText("");
mLast.setText(getCurrentTweet(jso));
} else {
mLast.setText(getText(R.string.tweet_error));
}
}
}
Although you are received the user_secret and user_token successfully in onResume(), are you sure your original objects are still the same? I had this problem in my Android app. I would create the objects, but when onResume() was called it was a totally new instance of the Activity because it was free'd from memory when the browser launched. So when I tried to set the returned secret/token pair it wouldn't work. This is more likely to happen on a device with limited memory. Some people choose to persist the necessary info between calls and others decide to not launch the default browser intent, but rather host an embedded webview so their original signpost-oauth objects don't go out of scope.
OAuth instance state in Android
Not sure if this is the issue, but maybe worth a look.
You need to add the oauth information to the headers of the http request using post.addHeader(). To know which things to add to the headers, take a look here: http://dev.twitter.com/pages/auth
Please describe what Client/Consumer/Provider you are using, they must be DefaultHttpClient/CommonsHttpOAuthConsumer/CommonsHttpOAuthProvider to work properly for sure.
Ensure you call consumer.setTokenWithSecret(oToken, oTokenSecret); before calling this code.
Also, is post.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false); exists in your post params?
What's the reason for using empty BasicResponseHandler, it handles nothing and it can be omitted in execute call, I suppose.
And, may be a dumb question, may be you are overwriting params when calling setParams(...) after setEntity(...)
I have 2 tutorials for 2 different Java libs. First one (dated) is here, and 2nd one here with Scribe. It's for LinkedIn but it would be very easy to switch to Twitter. I would go with #2

Android asynchronus HTTP client problem

I am trying to implement asynchronus http client for Android and I am haveing a trouble with type mismatch:
The method execute(HttpUriRequest) in the type HttpClient is not applicable for the arguments (HttpRequest)
I am doing all based on this tutorial: http://blog.androgames.net/12/retrieving-data-asynchronously/
Have found a type in AsynchronousSender - private HttpRequest request; but I have still problem with above which occurs in:
public void run() {
try {
final HttpResponse response;
synchronized (httpClient) {
response = getClient().execute(request); //<-- here is that problem
}
// process response
wrapper.setResponse(response);
handler.post(wrapper);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Can you suggest anything ?
cheers,
/Marcin
The code snippets on http://blog.androgames.net/12/retrieving-data-asynchronously/ are wrong. To fix it just replace HttpRequest with HttpUriRequest since the method signature is: HttpClient#execute(HttpUriRequest). It shouldn't be any problem since most requests you work with are HttpUriRequest instances.

Categories

Resources