Im new to Android development but Im trying to do an application for Opencart to allow users to enter in their own store to administrate it.
Lets go to the point. In order to get the information from the store i created a page where all the information is presented in XML, so the idea is that the user login, and then redirects to this page and with the http response, parse the xml and voilá!.
I have already the xml parser, but Im having some difficulties with the http connection. Let me explain a little bit more:
Basically, to log into any store, you need to go to www.example.com/admin (I will be using my testing online address to see if someone is able to help me), in this case http://www.onlineshop.davisanchezplaza.com/admin . Once we arrive to the page we arrive to the login system. The login system uses post to send the username: admin and password:admin and redirects to http://onlineshop.davidsanchezplaza.com/admin/index.php?route=common/login and once it verify your identity, it gives you a Token (here I start having some problems). http://onlineshop.davidsanchezplaza.com/admin/index.php?route=common/home&token=8e64583e003a4eedf54aa07cb3e48150 . Well, till here, im very okay, and actually developed an app that can do till here, actually i can "hardcode" read the token from the http response it sends me (what is actually not very good).
Here comes my first question: HOW TO GET FROM THE HTTPresponse the token value? (by now, as I said, I can only get the token by reading all the response, and if we find the string token=, take what comes next ... not good).
HttpClient httpClient = new DefaultHttpClient();
HttpConnectionParams.setConnectionTimeout(httpClient.getParams(), TIMEOUT_MS);
HttpConnectionParams.setSoTimeout(httpClient.getParams(), TIMEOUT_MS);
HttpPost httpPost = new HttpPost("http://onlineshop.davidsanchezplaza.com/admin/index.php?route=common/login");
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("username", "admin"));
nameValuePairs.add(new BasicNameValuePair("password", "admin"));
try{
Log.d(DEBUG_TAG, "Try ");
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpClient.execute(httpPost);
BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()), 8096);
Log.d(DEBUG_TAG, "br :" + br);
String line;
while ((line = br.readLine()) != null) {
Log.d(DEBUG_TAG, "br :" + line);
if(line.contains("token=")){
int index = line.indexOf("token=");
String aux = line.substring(index + "token=".length(), index + 32 + "token=".length());
token = aux; //Yes, I know, its not the best way.
break;
}
}
} catch (IOException e) {
Log.d(DEBUG_TAG, "Finally");
}
Second question, (and more important), now having the token (in the example 8e64583e003a4eedf54aa07cb3e48150), I need to go to the route android/home where is the xml information generated. (http://onlineshop.davidsanchezplaza.com/admin/index.php?route=android/home2&token=8e64583e003a4eedf54aa07cb3e48150). As I was reading, in httpget, we can either set the parameters, or directly send the url with the parameters already inside the url. Is in this step where it stops. Maybe is the internet connexion in China, maybe (most sure) im doing something wrong. Sometimes it just come the timeout connexion, others it just send me back to the login page.
Here is the code how i do (edit: I was a noob, and didnt create the httpclient to receive the answer, sorry!):
String s = "http://onlineshop.davidsanchezplaza.com/admin/index.php?route=common/home&token=";
String tot = s.concat(token);
HttpClient httpClient = new DefaultHttpClient();
HttpConnectionParams.setConnectionTimeout(httpClient.getParams(), TIMEOUT_MS);
HttpConnectionParams.setSoTimeout(httpClient.getParams(), TIMEOUT_MS);
HttpGet httpget = new HttpGet(tot);
try{
Log.d(DEBUG_TAG, "Try ");
HttpResponse response = httpClient.execute(httpget);
BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()), 8096);
Log.d(DEBUG_TAG, "br :" + br);
} catch (IOException e) {
Log.d(DEBUG_TAG, "Finally");
}
I dont need someone to tell me how to do it, just need a little guidance to solve the issue, I really appreciate any comment or help you can offer, or extra documentation :).
As a bonus, if someone can give me further details about how can I test the http get, I will appreciate, I only know how to write it in the web browser, and works fine.
It's a while since I last did something for Android, but here is my advice:
for the login purpose from Android application into the OpenCart administration I recommend creating a new mobile login page, e.g. instead of accessing http://yourstore.com/admin/ which redirects You to http://.../admin/index.php?route=common/login create Your own action e.g. androidLogin() within this controller (admin/controller/common/login.php and You will access it directly via http://yourstore.com/admin/index.php?route=common/login/androidLogin. Why special action? Because the default login action redirects the user (using normal browser) to the home while setting the security token into the URL within the query string part. In Your own action You won't redirect but respond with XML containing this security token so that You can easily extract that token using Your XML parser.
I cannot address second problem exactly but from what I remember I was passing a query string in different way (now I cannot find any similar solution on the internet).
Here is my 5 cents for the second question :
After playing a bit with the browser I realized :
Set Cookies
Your request to ...?route=android/home2&token= seems to be rejected if you are missing cookies. That is, you probably need to extract cookies from first server response and set them for further requests either manually (via conn.setRequestProperty("Cookie", cookie); or using Android CookieManager
User agent
Some server may reject your request just because you are missing "User-Agent" property in request header. To be safe, you could set it to something like conn.setRequestProperty("User-Agent", "Mozilla/5.0");
Extra note - I suggest that you also handle redirects correctly, as for example when you POST your admin/admin credentials you get 302 response and redirected to ...?route=common/home page
Also, you don't need to set conn.setDoInput(true) for UrlConnection while doing GET request.
Hope that helps.
I don't see any catch statement for the try in the second question, this catch may have the info you need to know what's going on.
For the first question try to convert InputStreamReader to a String, and use the String for a
url constructor, with the url (or uri i'm not sure right now, and can't test it) object try .getQueryParameter("parameter").
For your second question when i tried to login using the token that you have provided, the web page replied with invalid token. Can you login with the token that you have provided? If not, try to get a new token. Maybe the token have expired.
This question already has answers here:
Handling HttpClient Redirects
(5 answers)
Closed 9 years ago.
I had an issue a few weeks ago in a WebView where it wasn't following redirects as a normal browser would. I used the following suggestion given in many SO answers:
String newUrl = response.getFirstHeader("Location").getValue();
but it only gave 1 step of redirection, but not more, which it needed to. I got around it by repeatedly listening for redirects and manually going through each step.
Now I'm using the following code:
HttpClient httpClient = MyApp.getHttpClient();
HttpPost httpPost = new HttpPost(con.getString(R.string.platform_url_getBalances));
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
nameValuePairs.add(new BasicNameValuePair("sid", String.valueOf(sessionKey)));
ResponseHandler<String> responseHandler = new BasicResponseHandler();
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
String response = null;
// Execute HTTP Post Request. Response body returned as a string
response = httpClient.execute(httpPost, responseHandler);
Recently the end-point for the R.string.platform_url_getBalances changed but we put in a 302 redirect to a different URL. It works fine in a browser and on the iPad version of the app but for Android I get org.apache.http.client.HttpResponseException: Not Found.
I find it very strange that Android is such a pain when it comes to redirecting. Why does it behave like this and is there a reasonable way around it?
Actually, the answer I linked to in my comment is for HttpClient 4.1, near as I can tell, and Android's is older.
My guess is that the equivalent process in Android's version of HttpClient would be do:
Create a subclass of DefaultRedirectHandler that overrides isRedirectRequested() as appropriate for your app
Create a subclass of DefaultHttpClient and override createRedirectHandler() to return an instance of the subclass you created in the previous step
Use your subclass of DefaultHttpClient as a replacement for DefaultHttpClient itself wherever you are creating that instance
I am using the HttpPut to communicate with server in Android, the response code I am getting is 500.After talking with the server guy he said prepare the string like below and send.
{"key":"value","key":"value"}
now I am completely confused that where should i add this string in my request.
Please help me out .
I recently had to figure out a way to get my android app to communicate with a WCF service and update a particular record. At first this was really giving me a hard time figuring it out, mainly due to me not knowing enough about HTTP protocols, but I was able to create a PUT by using the following:
URL url = new URL("http://(...your service...).svc/(...your table name...)(...ID of record trying to update...)");
//--This code works for updating a record from the feed--
HttpPut httpPut = new HttpPut(url.toString());
JSONStringer json = new JSONStringer()
.object()
.key("your tables column name...").value("...updated value...")
.endObject();
StringEntity entity = new StringEntity(json.toString());
entity.setContentType("application/json;charset=UTF-8");//text/plain;charset=UTF-8
entity.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE,"application/json;charset=UTF-8"));
httpPut.setEntity(entity);
// Send request to WCF service
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(httpPut);
HttpEntity entity1 = response.getEntity();
if(entity1 != null&&(response.getStatusLine().getStatusCode()==201||response.getStatusLine().getStatusCode()==200))
{
//--just so that you can view the response, this is optional--
int sc = response.getStatusLine().getStatusCode();
String sl = response.getStatusLine().getReasonPhrase();
}
else
{
int sc = response.getStatusLine().getStatusCode();
String sl = response.getStatusLine().getReasonPhrase();
}
With this being said there is an easier option by using a library that will generate the update methods for you to allow for you to update a record without having to manually write the code like I did above. The 2 libraries that seem to be common are odata4j and restlet. Although I haven't been able to find a clear easy tutorial for odata4j there is one for restlet that is really nice: http://weblogs.asp.net/uruit/archive/2011/09/13/accessing-odata-from-android-using-restlet.aspx?CommentPosted=true#commentmessage
Error 500 is Internal Server error. Not sure if this answers your question but I personally encountered it when trying to send a data URI for an animated gif in a PUT request formatted in JSON but the data URI was too long. You may be sending too much information at once.
I'm taking a mobile development class, which focuses on Android, and for my term project I thought it would be cool if I made a little application that returns a list of cancer-related events and fundraisers. Basically what I have to do is programmatically fill in a webform given criteria that is input from my application, and parse the returned results to give a list of events, because for some reason the American Cancer Society doesn't keep a public list of all events. This is my first real experience with android, and I have almost zero experience with network programming. If I really wanted to, I could just change the URL I go to based on the paramaters given to me, because the ACS event search URLs all look almost exactly the same, but I want to do it "right". I looked at this post and this one for guidance, which led me to the MultipartEntity. They've been very helpful, but I really am not sure what to do next. Code is below:
//Base case, creates entity based on Entered ZIP Code
public void sendRequest()
{
EditText MyEditText = (EditText)findViewById(R.id.zip_edit_text);
String ZIP = MyEditText.getText().toString();
HttpClient defaultClient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://www.cancer.org/Involved/Participate/app/event-search");
try{
MultipartEntity entity = new MultipartEntity();
entity.addPart("ZIP",new StringBody(ZIP));
httppost.setEntity(entity);
HttpResponse response = defaultClient.execute(httppost);
HttpEntity result = response.getEntity();
InputStream stream = result.getContent();
String s = new Scanner(stream).useDelimiter("\\A").next();
Intent intent = new Intent(HomeScreen.this, ListResults.class);
startActivity(intent);
AlertDialog dialog = new AlertDialog.Builder(this).create();
dialog.setMessage(s);
dialog.show();
}catch (ClientProtocolException e){
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
}
}
It's pretty bare-bones right now, as you can see. The AlertDialog is used just to see what the HttpResponse looks like, and it seems like it does the POST correctly, and the ZIP code ends up in the right text field, but it doesn't actually "click" the search button. Personally, I think either:
1.) My HttpPost object's URL was incorrect
2.) I used POST instead of GET, or i should POST then GET
I really have tried to work this out myself, and have searched StackOverflow, but I've really come to a rough patch, and as I said before, my network programming experience is near nonexistent. Any help would be appreciated.
I would suggest that you do a printout the URL that was sent through your multipart method, do a search via the web browser, and see if both URL matches. If the URL doesn't match, it means that there's something wrong while setting your entity, etc.
I am able to use the example here: http://www.androidsnippets.org/snippets/36/index.html and successfully get the "HTTP/1.1 OK" response for a webesite I am sending the HttpPost along with the user credentials. However, I am unable to use an HttpGet to further browse other pages on this site.
Can anyone please let me know, what's going wrong. I am sorry - I am very new to Java.
My guess would be that when the website gets the Post and logs the user in, it sets cookies on the response to indicate that the user is logged in, and then requires those cookies on subsequent Get's.
You will need to do something like the following (this is borrowed from a bigger app so may not compile right out of the box)
DefaultHttpClient mHttpClient = new DefaultHttpClient();
BasicHttpContext mHttpContext = new BasicHttpContext();
CookieStore mCookieStore = new BasicCookieStore();
mHttpContext.setAttribute(ClientContext.COOKIE_STORE, mCookieStore);
This sets up a cookie store within the HTTP context, and you then use that context on Get's and Post's. For example...
HttpResponse response = mHttpClient.execute(mRequest, mHttpContext);
Under the covers the HTTP client will store cookies from responses, and add them to requests.