Web request not 404 proof and crashes app - android

I have an app where i read some data from online api every 30sec. I have somewhat secured my app so that it will check if the device is connected to network and data can be trasfered.
private boolean isNetworkAvailable() {
ConnectivityManager connectivityManager
= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
But this does not include situations when i am connected to a network which needs authentification for internet access. Or when you have only local connectivity enabled.
The app tries to get data from that api and it crashes. Here is the request code:
public static JSONObject requestWebService(String serviceUrl) {
disableConnectionReuseIfNecessary();
HttpURLConnection urlConnection = null;
try {
// create connection
URL urlToRequest = new URL(serviceUrl);
urlConnection = (HttpURLConnection)urlToRequest.openConnection();
urlConnection.setConnectTimeout(10000);
urlConnection.setReadTimeout(10000);
// handle issues
int statusCode = urlConnection.getResponseCode();
if (statusCode == HttpURLConnection.HTTP_UNAUTHORIZED) {
// handle unauthorized (if service requires user login)
} else if (statusCode != HttpURLConnection.HTTP_OK) {
// handle any other errors, like 404, 500,..
}
// create JSON object from content
InputStream in = new BufferedInputStream(
urlConnection.getInputStream());
return new JSONObject(getResponseText(in));
} catch (MalformedURLException e) {
// URL is invalid
} catch (SocketTimeoutException e) {
// data retrieval or connection timed out
} catch (IOException e) {
// could not read response body
// (could not create input stream)
} catch (JSONException e) {
// response body is no valid JSON string
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
return null;
}
All i need is that this app will not crash. How can i achieve this?
SOLUTION: it needed null check before reading JSON object... it was in different method:
public void check(){
JSONArray jsonArray = null;
if(isNetworkAvailable()) {
JSONObject dataZNetu = requestWebService("http://census.soe.com/get/ps2:v2/world_event?type=METAGAME");
if(dataZNetu != null) { //THIS WAS THE SOLUTION TO MY PROBLEM
try {
jsonArray = dataZNetu.getJSONArray("world_event_list");
for (int i = jsonArray.length() - 1; i >= 0; i--) {
JSONObject tempObj = jsonArray.getJSONObject(i);
int worldId = tempObj.getInt("world_id");
int stateID = tempObj.getInt("metagame_event_state");
int eventType = tempObj.getInt("metagame_event_id");
int instanceId = tempObj.getInt("instance_id");
checkUIchange(worldId, stateID, eventType, instanceId);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}

Since it looks like you are catching the appropriate exceptions, I'm guessing that the crash is in the code that calls this method.
If it tries to do something with the result, without checking for null, that's the problem.
But of course, knowing exactly where it crashes would help.

Related

How to cancel http request in broadcast receiver?

In my app, I am using broadcast receiver to capture the internet connect and disconnect state. Its working fine. Here is the code:
public class CheckConnectivity extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent arg1) {
boolean isNotConnected = arg1.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
if(isNotConnected){
Toast.makeText(context, "Disconnected", Toast.LENGTH_LONG).show();
}
else
{
Toast.makeText(context, "Connected", Toast.LENGTH_LONG).show();
}
}
}
I am using http web services in my app. I wrote them in different class.
HttpConnect.java:
public class HttpConnect {
public static String finalResponse;
public static HttpURLConnection con = null;
public static String sendGet(String url) {
try {
StringBuffer response = null;
//String urlEncode = URLEncoder.encode(url, "UTF-8");
URL obj = new URL(url);
Log.e("url", obj.toString());
con = (HttpURLConnection) obj.openConnection();
// optional default is GET
con.setRequestMethod("GET");
//add request header
con.setConnectTimeout(10000);
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
finalResponse = response.toString();
} catch (IOException e) {
e.printStackTrace();
}
//print result
return finalResponse;
}
}
My problem is, how to disconnect or cancel http request when broadcast receiver says no connectivity.
I have tried this code below:
if(isNotConnected){
Toast.makeText(context, "Disconnected", Toast.LENGTH_LONG).show();
if(HttpConnect.con != null)
{
HttpConnect.con.disconnect();
}
}
But its not working. Can anybody tell me how to cancel http request when broadcast receiver captures lost connection?
You should create one method like as below:
public static boolean isOnline(Context mContext) {
ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnectedOrConnecting()) {
return true;
}
return false;
}
And before your http call, you should just check, if it returns true, it means internet is available and if it is false, it means internet not available and you can stop your http call.
Also, if your call is already initiated, you should set request timeout value there like 30 seconds, if there is no internet, you will get exception of TimeoutError

checking internet connection on android programming

I try to write an android program to check internet connection with two different methods. The first one is the most common method, CheckInternetConnection(), and the second method is through connecting to a website, ConnectGoogleTest().
The first one work perfectly, but in the second one my tablet hang! anybody knows why ?
The codes are:
public class myITClass {
private Context ctx ;
public myITClass(Context context){
this.ctx = context;
}
public boolean CheckInternetConnection() {
ConnectivityManager cm = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
//NetworkInfo ni = cm.getActiveNetworkInfo();
if (cm.getActiveNetworkInfo() == null) {
// There are no active networks.
return false;
} else {
return true;
}
}
public boolean googlePingTest(){
boolean res = false ;
try {
URL url = new URL("http://www.google.com/");
HttpURLConnection urlc = (HttpURLConnection) url.openConnection();
urlc.setConnectTimeout(15000);
urlc.connect();
if (urlc.getResponseCode() == 200) { res = true; }
} catch (MalformedURLException e1) {
res = false;
} catch (IOException e) {
res = false ;
}catch (Exception e){
res = false ;
}
return res;
}
}
You can send a ping to http://www.google.com/ through HttpURLConnection. Please make sure that you doing it in the background thread. Creating a network task must be run in the background. There are 3 options to do that:
Using AsyncTask
Using IntentService
Using Service
In this time, we will use AsyncTask. So create a private class inside your Activity:
private boolean res = false;
private class PingTask extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... urlSite) {
HttpURLConnection urlc = null;
try {
URL url = new URL("http://www.google.com/");
urlc = (HttpURLConnection) url.openConnection();
urlc.setConnectTimeout(15000);
urlc.setRequestMethod("GET");
urlc.connect();
if (urlc.getResponseCode() == 200) { res = true; }
} catch (MalformedURLException e1) {
res = false;
} catch (IOException e) {
res = false ;
}catch (Exception e){
res = false ;
}finally{
if (urlc != null) {
try{
// close the connection
urlc.disconnect();
}catch (Exception e){
e.printStackTrace();
}
}
}
return null;
}
}
Don't forget to add this field in your class:
private boolean res = false;
Create a method to get the status:
public boolean getStatus(){
return status;
}
How to use?
Execute the PingTask first to check the status:
PingTask ping = new PingTask();
ping.execute();
Get the status:
// if the connection is available
if(getStatus()==true){
// do your thing here.
}
The second method calls network synchronously on main thread, and that blocks the UI. Try using AsyncTask for it.

How to get a working HttpsUrlConnection with Steam Web API?

im currently trying to implement the Steam Web API using the given code in the following repository -> https://github.com/Overv/SteamWebAPI/blob/master/SteamAPISession.cs into my Android app and im getting different exceptions dependend on using the given wep api ip ( 63.228.223.110 ) or the adress ( https://api.steampowered.com/ ) itself.
my code actually looks like this in the given method when building up a connection to the web api:
private String steamRequest( String get, String post ) {
final int MAX_RETRIES = 3;
int numberOfTries = 0;
HttpsURLConnection request = null;
while(numberOfTries < MAX_RETRIES) {
if (numberOfTries != 0) {
Log.d(TAG, "Retry -> " + numberOfTries);
}
try {
request = (HttpsURLConnection) new URL("https://api.steampowered.com/" + get).openConnection(); //or 63.228.223.110/ ???
SSLSocketFactory socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
String host = "api.steampowered.com";
int port = 443;
int header = 0;
socketFactory.createSocket(new Socket(host, port), host, port, false);
request.setHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
});
request.setSSLSocketFactory(socketFactory);
request.setDoOutput(false);
// request.setRequestProperty("Host", "api.steampowered.com:443");
// request.setRequestProperty("Protocol-Version", "httpVersion");
request.setRequestProperty("Accept", "*/*");
request.setRequestProperty("Accept-Encoding", "gzip, deflate");
request.setRequestProperty("Accept-Language", "en-us");
request.setRequestProperty("User-Agent", "Steam 1291812 / iPhone");
request.setRequestProperty("Connection", "close");
if (post != null) {
byte[] postBytes;
try {
request.setRequestMethod("POST");
postBytes = post.getBytes("US-ASCII");
// request.setRequestProperty("Content-Length", Integer.toString(postBytes.length));
request.setFixedLengthStreamingMode(postBytes.length);
request.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
PrintWriter out = new PrintWriter(request.getOutputStream());
out.print(post);
out.close();
// DataOutputStream requestStream = new DataOutputStream(request.getOutputStream());
//// OutputStreamWriter stream = new OutputStreamWriter(request.getOutputStream());
//// stream.write(postBytes, 0, postBytes.length);
// requestStream.write(postBytes, 0, postBytes.length);
// requestStream.close();
message++;
} catch (ProtocolException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
int statusCode = request.getResponseCode();
InputStream is;
Log.d(TAG, "The response code of the status code is" + statusCode);
if (statusCode != 200) {
is = request.getErrorStream();
Log.d(TAG, String.valueOf(is));
}
// String src = null;
// OutputStreamWriter out = new OutputStreamWriter(request.getOutputStream());
// out.write(src);
// out.close();
Scanner inStream = new Scanner(request.getInputStream());
String response = "";
while (inStream.hasNextLine()) {
response += (inStream.nextLine());
}
// String src;
// BufferedReader in = new BufferedReader(new InputStreamReader(request.getInputStream()));
// StringBuilder builder = new StringBuilder();
// while ((src = in.readLine()) != null) {
// builder.append(src);
// }
// String jsonData = builder.toString();
Log.d(TAG, response); //jsonData
// in.close();
return response; //jsonData
} catch (MalformedURLException ex) {
Toast.makeText(getActivity(), ex.toString(), Toast.LENGTH_LONG).show();
ex.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (request != null) {
request.disconnect();
}
}
numberOfTries++;
}
Log.d(TAG, "Max retries reached. Giving up on connecting to Steam Web API...");
return null;
}
following exception occurs when using https://api.steampowered.com/ as url:
W/System.err﹕ java.io.FileNotFoundException: https://api.steampowered.com/ISteamOAuth2/GetTokenWithCredentials/v0001
D/OptionsFragment﹕ Failed to log in!
i've really tried and researched on those issues, but i just can't get a solution. If someone got a good hint on helping to solve these exceptions please let me know!
EDIT:
I've researched some more!
Looking up on https://partner.steamgames.com/documentation/webapi#creating the direct ip adress shouldn't be used and therefore only the DNS name itself (for further clarification look on the given link). Hence, looking up on the API interface list itself -> http://api.steampowered.com/ISteamWebAPIUtil/GetSupportedAPIList/v0001/?format=json there doesn't seem to be a given Interface with a method called ISteamOAuth2/GetTokenWithCredentials.(Or not anymore!) Only ISteamUserAuth and ISteamUserOAuth which seem to handle Authentication stuff.
I will update this post again if i should get a working connection and handling with the steam web api.
Cheers!

HttpUrlConnection issue when tablet is inactive

I'm having an issue on multiple devices where when the device isn't interacted with for a period of time, my HttpUrlConnection's don't operate as expected. The projects target platform is Android 4.0.3.
Below is an example of how I'm using HttpUrlConnection.
new AsyncRequestDTOBaseItemArray(callback).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url);
The actual AsyncTask
public class AsyncRequestDTOBaseItem extends AsyncTask<String,String,Object> {
HttpURLConnection connection;
InputStream inStream;
IApiCallback callback;
public AsyncRequestDTOBaseItem(IApiCallback callback) {
this.callback = callback;
}
#Override
protected Object doInBackground(String... uri) {
try {
URL url = new URL(uri[0]);
connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(5000);
connection.addRequestProperty("Accept-Encoding", "gzip");
connection.setInstanceFollowRedirects(false);
connection.connect();
String encoding = connection.getContentEncoding();
// Determine if the stream is compressed and uncompress it if needed.
if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
inStream = new GZIPInputStream(connection.getInputStream());
} else {
inStream = connection.getInputStream();
}
if (inStream != null) {
InputStreamReader isr = new InputStreamReader(inStream);
Gson gson = new Gson();
try {
DTOBaseItem item = gson.fromJson(isr, DTOBaseItem.class);
return item;
} catch (Exception e) {
Log.i("AsyncRequestDTOBaseItem", "Exception");
if (e != null && e.getMessage() != null) {
Log.e("AsyncRequestDTOBaseItem", e.getMessage());
}
} finally {
inStream.close();
}
}
} catch (SocketTimeoutException e) {
Log.i("AsyncRequestDTOBaseItem", "Socket Timeout occured");
} catch (IOException e) {
Log.i("AsyncRequestDTOBaseItem","IOException");
if (e != null && e.getMessage() != null) {
Log.i("AsyncRequestDTOBaseItem",e.getMessage());
}
} finally {
if (connection != null)
connection.disconnect();
}
return null;
}
#Override
protected void onPostExecute(Object result) {
callback.Execute(result);
}
}
I don't see any issues with the above code unless the device has been inactive. When the device has been inactive the last code line that executes is
String encoding = connection.getContentEncoding();
I've also gone into the wifi settings and made sure that my wifi doesn't sleep. I thought at first it might be that the wifi reconnecting was creating this issue.
It looks like the issue may have been the server not sending data back.
I added connection.setReadTimeout(5000); and now the issue seems to have gone away.

How to be sure that downloaded HTML source code is from specific website?

I have a service that downloads HTML source code of certain website and then compares it to the previously downloaded one from the same website, to see if any changes have occured.
The problem I had yesterday: I was connected to WiFi in public and my service started downloading the code, since it wasn't showing that there's no connection. But you first have to login when using public WiFi so it was redirected to their login page and my service downloaded the HTML code of a login page.
How can I surely get the source code of the site I want?
Here's the source code (btw I turn source code into md5 for easier comparison but it's not important):
public class DownloadHandler{
public String getMd5(String url){
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(url);
HttpResponse response = null;
try {
response = client.execute(request);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
InputStream in = null;
try {
in = response.getEntity().getContent();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder str = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
str.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
String HTML = str.toString();
try {
String md5 = stringToMd5(html);
return md5;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
public String stringToMd5(String s) throws NoSuchAlgorithmException {
MessageDigest md5 = MessageDigest.getInstance("MD5");stringa
md5.update(s.getBytes(), 0, s.length());
String md5String = new BigInteger(1, md5.digest()).toString(16);
return md5String;
}
And the function to check connection:
boolean isNetworkAvailable() {
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager
.getActiveNetworkInfo();
return activeNetworkInfo != null;
}
you can disable redirects using
HttpGet httpGet = new HttpGet("www.google.com");
HttpParams params = httpGet.getParams();
params.setParameter(ClientPNames.HANDLE_REDIRECTS, Boolean.FALSE);
httpGet.setParams(params);
but you should still check for http status code which should be 200
HttpResponse httpResp = client.execute(response);
int code = httpResp.getStatusLine().getStatusCode();
Access the website using SSL and check the identity of the certificate.

Categories

Resources