Problem when performing HTTP request on Android

Asked

Viewed 96 times

1

I can make an HTTPS request normally in an app, but it doesn’t work when it’s HTTP. You would have to configure something in Android Studio to be able to make the HTTP request?

The code of my class responsible for the request is below. I am using Android Studio 3.4.2

Loaded.java ( Httpservice )

package com.projetos.conexaoapi;

import android.os.AsyncTask;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class CarregaDados extends AsyncTask<Void, Void, Void>{
    String dados = "";
    private final String urlParam;

    public CarregaDados(String urlParam) {
        this.urlParam = urlParam;
    }

    @Override
    protected Void doInBackground(Void... voids) {
        try {
            //URL url = new URL("https://brasilapi.com.br/api/feriados/v1/2021");
            //URL url = new URL("https://viacep.com.br/ws/01001000/json");
            URL url = new URL(urlParam);

            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            InputStream inputStream = httpURLConnection.getInputStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));

            String line = "";

            while (line != null){
                line = bufferedReader.readLine();
                dados = dados + line;
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);

        MainActivity.twDados.setText(this.dados);
    }
}

2 answers

2

The Android Manifest has a property called android:usesCleartextTraffic, which allows or blocks (unencrypted) HTTP requests. Starting with API 28, the default value is "not allowed", as quoted here:

Starting with Android 9 (API 28 level), plain text compatibility is disabled by default.

Conform that reply from Soen, we have a few options below. They are sorted from the most recommended to the least recommended option.

1. Use of HTTPS

This is the best option. If the domain allows it, you can (and should) use the HTTPS route instead of HTTP so that the data you traffic is encrypted.

2. Allow HTTP in a specific domain

If the domain does not allow HTTPS requests, you can create a configuration for Android to allow HTTP in that specific domain.

Create a file in res/xml/network_security_config.xml with the following content:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">seudominio.com</domain>
    </domain-config>
</network-security-config>

And modify the AndroidManifest.xml to use the created configuration:

<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        ...
        android:networkSecurityConfig="@xml/network_security_config"
        ...>
        ...
    </application>
</manifest>

3. Allow HTTP requests for any domain

If you don’t know which domain you need to use HTTP at build time (for example, you have a dynamic endpoint set by the user), you can allow HTTP in all domains.

To do this, simply modify the value of the property android:useCleartextTraffic in the AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        ...
        android:usesCleartextTraffic="true"
        ...>
        ...
    </application>
</manifest>

4. Reduce the level of android:targetSandboxVersion

If you set a different level from the standard for android:targetSandboxVersion, it may be necessary to reduce it to 1. As documented:

The higher the number of the sandbox version, the higher the level of security. The default value is 1. You can also set it to 2. Setting this attribute to 2 switches the app to another Selinux sandbox.

The following restrictions apply to a level 2 sandbox:

  • The default value of usesCleartextTraffic in the network security configuration is false.
  • Uid sharing is not allowed.

Then you can remove the property from AndroidManifest.xml or modify it to 1:

<?xml version="1.0" encoding="utf-8"?>
<manifest android:targetSandboxVersion="1">
    <uses-permission android:name="android.permission.INTERNET" />
    ...
</manifest>

1

Good morning. When the request is not secure you need to create special permissions for it. Do the following

create an xml file in res/xml with the name network_config.xml in this format below with the list of domains at http q vc will request:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">viacep.com.br</domain>
        <domain includeSubdomains="true">melhordosgames.com.br</domain>
    </domain-config>
</network-security-config>

after that it goes in your manifest and in your application add 2 parameters:

android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_config"

will look something like this:

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:usesCleartextTraffic="true"
        android:supportsRtl="true"
        android:networkSecurityConfig="@xml/network_config"
        android:theme="@style/AppTheme">

so just test ? with that you authorize unsafe content to be trafficked over the internet

  • Thanks for the personal feedback, I will test here, then comment with was... the Detail is that I am connecting to an Internal Network, a REST API ( Spring Boot ), and by default the Request is http, in a Browse the return works normal, in Postman also works, in a Reactjs application also, but on Android had this detail, it took me a while to realize that the detail was due to the type of http connection that was going, as mentioned.

  • It worked by putting this line on Androidmanifest ( android:usesCleartextTraffic="true" ), then putting the authorizations according to the urls you use. Thank you very much, thank you very much!

  • @Don’t forget to give vote +1 if this answer was useful to you. And also to mark it as a favorite if you judge it as the best solution. Analyze the other answer as well and give feedback. So you help other devs who have the same problem to find and better solution.

  • Hello, when I try to vote, because I post little thing around here, it doesn’t validate... I usually solve what I need to see other posts on the subject, I’ll see how to improve it... thanks!

  • @Just like you can’t vote because of your reputation, but you can still accept the answer, it will mark your question as solved. Read more on How and why to accept an answer?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.