I'm working on an Android app for a client, and I'm calling their API to get the info for various parts of my app. There is one call that results on SocketTimeoutException if I set a timeout, or infinitely hangs if I don't; however, it works just fine on the web client(React), so it can't be the server.
Code:
package io.voluntu.voluntu;
import android.os.AsyncTask;
import android.os.Bundle;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
public class SendApproveHours extends AsyncTask<Bundle, Void, String>{
private StringBuilder sb = new StringBuilder();
private String result;
private ApproveHours approveHours;
public SendApproveHours(ApproveHours approveHours){
this.approveHours = approveHours;
}
protected String doInBackground(Bundle... params){
Bundle b = params[0];
String jwt = b.getString("JWT");
System.out.println(jwt);
boolean approve = b.getBoolean("APPROVE");
int[] id = b.getIntArray("ID");
try {
URL url = new URL("http://voluntu.io/api/hour/update");
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setConnectTimeout(2500 /* milliseconds */); //if i don't do this, it will hang indefinitely
httpURLConnection.setReadTimeout(1500 /* milliseconds */);
httpURLConnection.setDoOutput(true);
httpURLConnection.setRequestProperty("Content-Type", "application/json");
httpURLConnection.setRequestProperty("Host", "voluntu.io");
httpURLConnection.setRequestProperty("Origin", "http://voluntu.io");
httpURLConnection.setRequestProperty("Referer", "http://voluntu.io/hours/approve");
httpURLConnection.setRequestProperty("Cookie", "sessionJWT=" + jwt);
httpURLConnection.connect();
JSONObject jsonObject = new JSONObject();
jsonObject.put("approveOrReject", approve);
jsonObject.put("hourIDs", Arrays.toString(id));
System.out.println(jsonObject);
DataOutputStream wr = new DataOutputStream(httpURLConnection.getOutputStream());
wr.writeBytes(jsonObject.toString());
wr.flush();
wr.close();
int HttpResult = httpURLConnection.getResponseCode(); //hangs here
System.out.println("HTTP RESULT: " + HttpResult);
if(HttpResult == HttpURLConnection.HTTP_OK){
BufferedReader in = new BufferedReader(new InputStreamReader(
httpURLConnection.getInputStream(), "utf-8"
));
String line;
while((line = in.readLine()) != null){
sb.append(line);
}
in.close();
}
System.out.println("RESPONSE: " + sb.toString());
httpURLConnection.disconnect();
}
catch (MalformedURLException e){
e.printStackTrace();
}
catch (IOException e){
e.printStackTrace();
}
catch (JSONException e){
e.printStackTrace();
}
return sb.toString();
}
protected void onPostExecute(String result){
approveHours.refreshHours();
}
}
It hangs on getting the HTTP response code for some reason. I checked the headers and body and they are identical to what the web version is sending, so I have no idea why it's not working. Also, calling other parts of their API works just fine, and in fact this code is mostly copy pasted from other parts of my app that call the API. Help is appreciated!
I fixed it. Instead of an array, you must use JSONArray, or the array gets wrapped in quotes when it gets put in the JSON object.
Related
i am using asynctask to fetch data from my hosted web page using the default java httpurlconnection library and apparently the doinbackground method does not execute on my android 9 device but i can receive the json response when tested with emulator api 24. also i declared internet permission in the manifest and i have firebase woking fine, so no internet problem. is there any explanation for this situation? is there any solution while keep using asynctask with httpurlconnection? please help, i have to present my app in two days.
sendDataAsync.class
package com.example.control;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.MalformedURLException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import android.os.AsyncTask;
class sendDataAsync extends AsyncTask<String , Void , String>{
private AsyncResponse delegate = null;
private String serverURL, responsemsg = "Not connected to host",entries;
public sendDataAsync(String name, String prename, String email, String gender, String password, String cfirmpassword) {
entries = "name="+name+"&prename="+prename+"&email="+email+"&gender="+gender+"&password="+password+"&cfirmpassword="+cfirmpassword;
serverURL = "http://iotcontrol.atwebpages.com/Register.php";
}
public sendDataAsync(String email, String password) {
entries = "password="+password+"&email="+email;
serverURL = "http://iotcontrol.atwebpages.com/Login.php";
}
public void setDelegate(AsyncResponse del){
this.delegate = del;
}
#Override
protected String doInBackground(String... params) {
try {
//entries = URLEncoder.encode(entries,"utf-8");
URL url = new URL(serverURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000);
conn.setConnectTimeout(15000);
conn.setRequestMethod("POST");
conn.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty( "charset", "utf-8");
conn.setDoInput(true);
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8));
writer.write(entries);
writer.flush();
writer.close();
os.close();
InputStream is = conn.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
String inputLine;
StringBuilder sb = new StringBuilder();
while ((inputLine = reader.readLine()) != null) {
sb.append(inputLine);
}
reader.close();
is.close();
conn.disconnect();
responsemsg = sb.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return responsemsg;
}
#Override
protected void onPostExecute(String result) {
delegate.processFinish(result);
}
}
in my activity i have this
public void insertData() {
sendDataAsync sendPostReqAsyncTask = new sendDataAsync(nameValue, prenameValue, emailValue, genderValue,passwordValue,cfirmpasswordValue);
sendPostReqAsyncTask.setDelegate(this);
sendPostReqAsyncTask.execute();
}
/*
for some reason i cant access logcat so i just have a textview and print the response to it
and while on the emulator api24 i have the text view: {"ok":false,"message":"invalide data"}
but on my android 9 phone i have the text: Not connected to host
*/
public void processFinish(String output) {
TextView txt = (TextView)findViewById(R.id.textView3);
txt.setText(output);
}
Starting with Android 9, cleartext traffic such as http is not permitted by default.
If the server supports it, use https instead.
If the server does not support https, you need to specifically opt in for cleartext traffic. You can do it app-wide with manifest but it's better to enable it only for one host with network security config.
Mostly looks like an issue of Cleartext. Please follow the below shared link
https://medium.com/#son.rommer/fix-cleartext-traffic-error-in-android-9-pie-2f4e9e2235e6
If it's cleartext issue, check your logcat, it will throw an error in logcat.
Plus please note that Async Task has been deprecated from API 30. Since you are using Java you can start looking into RXJAVA for this and retrofit to make API calls.
I'm trying to perform a simple query in PHP which takes parameters from a Java class. The Java Class is part of an Android phone app I am working on. I am able to make a connection and receive an input stream from the PHP file, which I have been using to see the exact error that my app receives. The error is "Undefined index: username".
I have tested the PHP file by typing the parameters directly into the URL, which has worked, and using a URL with the parameters hard-coded in also works. However, I want to perform different queries, not the same one every time, so I need to be able to pass my parameters in my output stream.
Here is my code:
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import android.os.AsyncTask;
import android.widget.TextView;
public class LoginSupport extends AsyncTask<String, Void, String>{
private TextView progress;
public LoginSupport(TextView progress) {
this.progress = progress;
}
protected void onPreExecute() {
}
#Override
protected String doInBackground(String... arg0) {
try {
//get login values
String username = arg0[0];
//add login values to string
String data = URLEncoder.encode("username", "UTF-8") + "=" + URLEncoder.encode(username, "UTF-8");
//pass login values to PHP file
String urlString = "http://192.**.**.**/App.php?"; //IP address hidden
URL urlForLogin = new URL(urlString);
URLConnection UrlConn = urlForLogin.openConnection();
HttpURLConnection httpConn = (HttpURLConnection) UrlConn;
httpConn.setDoOutput(true);
httpConn.setDoInput(true);
httpConn.setAllowUserInteraction(true);
httpConn.setRequestMethod("POST");
httpConn.setRequestProperty("Content-Type", "application/text; charset=utf-8");
//The OutputStreamWriter wr passes the string containing encoded parameters to the php file.
OutputStreamWriter wr = new OutputStreamWriter(httpConn.getOutputStream());
/*This is another methods, which hasnt worked...
OutputStream os = new BufferedOutputStream(httpConn.getOutputStream());
BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(os, "utf-8"));
...and here is another that didnt work...
PrintWriter wr = new PrintWriter(httpConn.getOutputStream(), true);
wr.print(data); */
wr.write(data);
System.out.println(data); //I used this to check that what was being sent to the server was what I expected. (it is)
//Opens a stream to receive the query response.
BufferedReader reader = new BufferedReader(new InputStreamReader(httpConn.getInputStream()));
//Read query response.
String line = null;
while ((line = reader.readLine()) != null){
System.out.println(line);
}
//the following if statement gets ignored for some reason, unless I use "==".
if (line.equals("Connected")){
this.progress.setText("It worked!");
}else{
this.progress.setText("Failed");
}
wr.close();
reader.close();
httpConn.disconnect();
return "true";
}
catch (Exception e) {
e.printStackTrace();
return new String("Exception: " + e.getMessage());
}
}
#Override
protected void onPostExecute(String result){
}
}
My PHP file uses $username = $_POST['username']; to read the parameter.
Sources I have used:
https://docs.oracle.com/javase/tutorial/networking/urls/readingWriting.html
HTTPURLConnection - Outputstream POST to php on webserver
How to pass an argument with POST using HttpUrlConnection
https://www.blackbaud.com/files/support/guides/infinitydevguide/content/java/cocreateaconnectionwithurlconnection.htm
https://www.tutorialspoint.com/android/android_php_mysql.htm
Days of Googling
rickdenhaan's comment helped me solve this.
I changed
httpConn.setRequestProperty("Content-Type", "application/text; charset=utf-8");
to
httpConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
I am new to android programming, and I was following this tutorial
to create a GCM server program. However, I came across a frustrating bug and would greatly appreciate any help.
This is my POST2GCM class:
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import com.fasterxml.jackson.databind.ObjectMapper;
public class POST2GCM extends Content {
private static final long serialVersionUID = 1L;
public static void post(String apiKey, Content content){
try{
// 1. URL
URL url = new URL("https://android.googleapis.com/gcm/send");
// 2. Open connection
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 3. Specify POST method
conn.setRequestMethod("POST");
// 4. Set the headers
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Authorization", "key="+apiKey);
conn.setDoOutput(true);
// 5. Add JSON data into POST request body
//`5.1 Use Jackson object mapper to convert Contnet object into JSON
ObjectMapper mapper = new ObjectMapper();
// 5.2 Get connection output stream
DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
// 5.3 Copy Content "JSON" into
mapper.writeValue(wr, content);
// 5.4 Send the request
wr.flush();
// 5.5 close
wr.close();
// 6. Get the response
int responseCode = conn.getResponseCode();
System.out.println("\nSending 'POST' request to URL : " + url);
System.out.println("Response Code : " + responseCode);
BufferedReader in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
// 7. Print result
System.out.println(response.toString());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
I have included the "jackson-databind-2.5.1.jar" file but I get the error:
Unhandled Exception: com.fasterxml.jackson.databind.JsonMappingException
on the line mapper.writeValue(wr, content);
What is causing this exception, and how can I fix it?
jackson-databind is a general data-binding package which works on streaming API (jackson-core) implementations. That's why you need to add jackson-core and catch 3 exceptions. writeValue method throws IOException, JsonGenerationException and JsonMappingException.
try {
mapper.writeValue(wr, content);
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Hope it will be useful for you.
I've followed the UA tutorials and got my APID , and successfully recieved test push message on my android device.
Now the next thing that I like to do is to target my device using JAVA and send push messaged.
From what I've seen so far the best way to achieve this is using their web API.
However When I'm trying to send a post message I always get the following error :
java.io.IOException: Server returned HTTP response code: 401 for URL: https://go.urbanairship.com/api/push/
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(Unknown Source)
at com.Sender.Sender.main(Sender.java:56)
This is the code that I use :
package com.Sender;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
public class Sender {
/**
* #param args
*/
public static void main(String[] args) {
try {
String responseString = "";
String outputString = "";
String username = "MWMoRVhmRXOG6IrvhMm-BA";
String password = "ebsJS2iXR5aMJcOKe4rCcA";
MyAuthenticator ma= new MyAuthenticator(username, password);
Authenticator.setDefault(ma);
URL url = new URL("https://go.urbanairship.com/api/push/");
URLConnection urlConnection = url.openConnection();
HttpURLConnection httpConn = (HttpURLConnection) urlConnection;
ByteArrayOutputStream bout = new ByteArrayOutputStream();
String APID = "23eef280-19c8-40fc-b798-788f50e255a2";
String postdata = "{\"android\": {\"alert\": \"Hello from JAVA!\"}, \"apids\": [\""+APID+"\"]}";
byte[] buffer = new byte[postdata.length()];
buffer = postdata.getBytes("UTF8");
bout.write(buffer);
byte[] b = bout.toByteArray();
httpConn.setRequestProperty("Content-Length",
String.valueOf(b.length));
httpConn.setRequestProperty("Content-Type", "application/json");
httpConn.setRequestMethod("POST");
httpConn.setDoOutput(true);
httpConn.setDoInput(true);
OutputStream out = httpConn.getOutputStream();
out.write(b);
out.close();
InputStreamReader isr = new InputStreamReader(
httpConn.getInputStream());
BufferedReader in = new BufferedReader(isr);
while ((responseString = in.readLine()) != null) {
outputString = outputString + responseString;
}
System.out.println(outputString);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
Can you help me please ?
HTTP 401 represent Unauthorized access. In your code even though your created Authenticator, you didn't provide it as part of post request header. Here is tutorial on how to set authenticator for a URLConnection.
I'm trying to retrive some data from a web site.
I wrote a java class which seems to work pretty fine with many sites but it doesn't work with this particular site, which use extensive javascript in the input fomr.
As you can see from the code I specified the input fields taking the name from the HTML source, but maybe this website doesn't accept POST request of this kind?
How can I simulate an user-interaction to retrieve the generated HTML?
package com.transport.urlRetriver;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
public class UrlRetriver {
String stationPoller (String url, ArrayList<NameValuePair> params) {
HttpPost postRequest;
HttpResponse response;
HttpEntity entity;
String result = null;
DefaultHttpClient httpClient = new DefaultHttpClient();
try {
postRequest = new HttpPost(url);
postRequest.setEntity((HttpEntity) new UrlEncodedFormEntity(params));
response = httpClient.execute(postRequest);
entity = response.getEntity();
if(entity != null){
InputStream inputStream = entity.getContent();
result = convertStreamToString(inputStream);
}
} catch (Exception e) {
result = "We had a problem";
} finally {
httpClient.getConnectionManager().shutdown();
}
return result;
}
void ATMtravelPoller () {
ArrayList<NameValuePair> params = new ArrayList<NameValuePair>(2);
String url = "http://www.atm-mi.it/it/Pagine/default.aspx";
params.add(new BasicNameValuePair("ctl00$SPWebPartManager1$g_afa5adbb_5b60_4e50_8da2_212a1d36e49c$txt_address_s", "Viale romagna 1"));
params.add(new BasicNameValuePair("ctl00$SPWebPartManager1$g_afa5adbb_5b60_4e50_8da2_212a1d36e49c$txt_address_e", "Viale Toscana 20"));
params.add(new BasicNameValuePair("sf_method", "POST"));
String result = stationPoller(url, params);
saveToFile(result, "/home/rachele/Documents/atm/out4.html");
}
static void saveToFile(String toFile, String pos){
try{
// Create file
FileWriter fstream = new FileWriter(pos);
BufferedWriter out = new BufferedWriter(fstream);
out.write(toFile);
//Close the output stream
out.close();
}catch (Exception e){//Catch exception if any
System.err.println("Error: " + e.getMessage());
}
}
private static String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder stringBuilder = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
stringBuilder.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return stringBuilder.toString();
}
}
At my point of view, there could be javascript generated field with dynamic value for preventing automated code to crawl the site. Send concrete site you want to download.