Cannot reach Rails-API-Server from Android Emulator - android

I have an Rails-api running on localhost:3000. I have an android app setup to authenticate the user (login). I am using Retrofit. This is the setup:
`
String BASE_URL = "http://192.168.0.104:3000";
if(retrofit == null){
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
`
I can make the calls from my actual device. Works perfect.
I want to do the same thing using the Android Emulator. And, it is not working. I went through some android documentations and other Stack Overflow questions. I found out that you cannot reach host using the actual IP i.e. 192.168.0.104 in my case. I have to use 10.0.2.2. Then I did this:
`
String BASE_URL = "http://10.0.2.2:3000";
`
Still, it is not working.
This is how I am making the call.
`
Call<User> call = apiInterface.performUserLogin(mEmail, mPassword);
call.enqueue(new Callback<User>() {
#Override
public void onResponse(Call<User> call, Response<User> response) {
...
...
});
`
The execution seems to be failing from the call.enqueue(new Callback(). The callback is not being executed at all. And, I have no clue why.
Just found out this in the Log
`
08-08 18:46:12.659 13835-13835/com.example.gist.toasms E/Exception: java.net.UnknownServiceException: CLEARTEXT communication to 10.0.2.2 not permitted by network security policy
One of the solution was to addandroid:usesCleartextTraffic="true"` in manifest but that is only available from minSdkVersion 23. Mine is 22
Thank you!

To directly answer your question, there is no issue adding an attribute that is introduced at a higher SDK level than your minimum. It will be ignored by devices earlier than its introduction. You do get a warning in AndroidStudio, but that can be suppressed if you prefer. Simply add: tools:ignore="UnusedAttribute"
For a more complete answer, Android 9.0 (SDK 28) started disabling cleartext network communications by default. See Android 9.0 (SDK 28) cleartext disabled
You have several options, in order of security preference:
Change all network access to use HTTPS.
Add a network security config file to your project to allow cleartext to particular domains that don't support HTTPS.
Enable Cleartext support for the app by adding android:usesCleartextTraffic="true" to the application in the manifest.
To add a Network Security File to your project, you need to do two things. You need to add the file specification to the manifest:
<application android:networkSecurityConfig="#xml/network_security_config" .../>
Secondly, create file res/xml/network_security_config.xml and specify your security desires:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">192.168.0.10</domain>
</domain-config>
</network-security-config>

Related

Insecure HTTP connections are disabled by default on iOS and Android Flutter

I need to allow all HTTP for all requests in my code.
The code works fine in debug and release mode for the apk, but it doesn't work when I upload it to Google play as bundle.aab
1- I created network_security_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
</trust-anchors>
</base-config>
</network-security-config>
2- add to AndroidManifest/application
<application
android:usesCleartextTraffic="true"
android:networkSecurityConfig="#xml/network_security_config"
......
>
3- add meta-data to application
<application
......>
.....
<meta-data android:name="io.flutter.network-policy"
android:resource="#xml/network_security_config"/>
</application>
4- add the permission
<uses-permission android:name="android.permission.INTERNET"/>
You should https but if you still want to use http protocol then add the following to your Info.plist file in iOS:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Also for android add this entry in AndroidManifest.xml file:
<application
...
android:usesCleartextTraffic="true">
...
</application>
By default, Flutter disables insecure HTTP connections on iOS and Android to improve security and prevent man-in-the-middle attacks. However, if you need to allow insecure HTTP connections for testing or other purposes, you can do so by using the http package's BadCertificateCallback function.
To allow insecure HTTP connections in your Flutter app, you can do the following:
Import the http package and the dart:io library:
import 'package:http/http.dart' as http;
import 'dart:io';
Create a function that returns true for any certificate that should be allowed. For example, the following function allows any certificate:
bool allowInsecureCertificates(X509Certificate cert, String host, int port) {
return true;
}
Use the http.Client constructor and pass the allowInsecureCertificates function as the onBadCertificate parameter to create an HTTP client that allows insecure certificates:
final client = http.Client(onBadCertificate: allowInsecureCertificates);
Use the client to make HTTP requests as needed. For example:
final response = await client.get('http://insecure-server.com/data');
Keep in mind that allowing insecure HTTP connections can compromise the security of your app and the data it handles. It is generally not recommended to allow insecure HTTP connections in production environments. Instead, you should use secure HTTPS connections to protect the integrity and confidentiality of your data.
Is it any specific domain you are trying to call?
You can try adding the <domain-config> tag, if you know which domain you might be using. There is a section on Android documentation, if you want to force the system to use only secure connections here.
But you can try changing some values in that to see if disabling those force items can solve your problem.
Try something like this.
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">network.domain.com</domain>
</domain-config>
</network-security-config>
But this is only for Android.

Golang API + Android: cannot access API on Android

I developed a Golang API to communicate with my Android app. My API is located on my "server" (currently an old laptop) and I can access my API on my Android device when both are connected on the same network, use the android:usesCleartextTraffic="true" in the manifest and use the IP (192.168.X.XX:XXX) of my server on my Android app. Cool so far :)
But now I want to access using different networks, for this, I created a Dynu account with DDNS with a built-in domain (test.freeddns.org). On my Android log displays:
No Network Security Config specified, using platform default
So I tried using network_security_config.xml:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config xmlns:android="http://schemas.android.com/apk/res/android">
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">test.freeddns.org</domain>
</domain-config>
</network-security-config>
but it gives me the following message:
2022-11-10 12:08:53.518 30659-30745 NetworkSecurityConfig D Using Network Security Config from resource network_security_config debugBuild: true
I tried using the public IP of my server with no success :( I still get the same error
I use the
RequestQueue queue = Volley.newRequestQueue(context); on my Android App to send a POST request to my server.
Any ideas will be more than welcome
Thanks in advance
Best regards

.Net MAUI Android can't talk to API localhost

I've downloaded the latest sample MAUI here: https://github.com/microsoft/dotnet-podcasts and copied the exact way they make requests but I can't get passed an 'unexpected end of stream error':
System.Net.WebException: unexpected end of stream on com.android.okhttp.Address#4c288121
---> Java.IO.IOException: unexpected end of stream on com.android.okhttp.Address#4c288121
I'm initialising the HttpClient in the MauiProgram.cs via the AddHttpClient factory method like so (note the different IP address for Andorid):
public static string Base = DeviceInfo.Platform == DevicePlatform.Android ? "http://10.0.2.2" : "https://localhost";
public static string APIUrl = $"{Base}:7096/api/";
builder.Services.AddHttpClient<DishClient>(client => { client.BaseAddress = new Uri(APIUrl); });
I've included the following android:networkSecurityConfig in the AndroidManifest.xml (which allows http traffic):
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
</trust-anchors>
</base-config>
</network-security-config>
The solution in Xamarin it seems is to use AndroidClientHandler but this is in a deprecated library that I can't use in MAUI, and there's no reference to it in the linked solution that works.
Things I've tried:
using Https: I've followed the guide here: https://learn.microsoft.com/en-us/xamarin/cross-platform/deploy-test/connect-to-local-web-services#bypass-the-certificate-security-check but I still get certificate errors:
System.Net.WebException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
---> Javax.Net.Ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
I've also tried this
handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
but get an error
System.PlatformNotSupportedException: Operation is not supported on this platform
It's been 4 days non-stop and i've gone through every conceivable setting in the working solution and can't find any differences. Any ideas?
#Jimmy in your code, you're changing the URL from "https://localhost" to "http://10.0.2.2" when you're running on android. In both cases, you're calling the API at port 7096:
public static string APIUrl = $"{Base}:7096/api/";. In the case of android, you're using the HTTP protocol, and in all other cases, you're using HTTPS.
I assume that your server listens to HTTPS only on port 7096 and not to HTTP. Maybe this causes your issue.
Another problem could be that your service is only bound to localhost but not to your IP address (you can look this up in the launchsettings.json of your API).
Another issue can be that your firewall doesn't allow incoming traffic on port 7096. You should check that, too, because you're not crossing machine borders when you're running on Windows. However, you have a cross-machine communication when running on the Android emulator.

Fix APIs connection problem with old Android OS (Android 7 or less) in React Native using axios

I used 'axios' library to fetch the data. It is working perfect on new Android devices (Android 9 & 10) but on old devices (Android 7 or less) it always gives Network Error like this: [ Error: Network Error] it seems like the devices could not establish a connection with the https URL.
Solution-1:
Try adding bellow code in AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Solution-2:
Problem with http and https request. SO to enable https request try the one below :
The easy way to implement this is to use this attribute to your AndroidManifest.xml where you allow all http for all requests:
android:usesCleartextTraffic="true"

Android app can't send request through NGROK on real device

I know there are a lot of similar question but mine is particular.
I have Android app using a NodeJS Back-end on localhost:3000. In order to test my app on my real device (and other friend so far from me), I'm using Ngrok to redirect requests.
Then, on Postman, I can reach the BackEnd through Ngrok. When I run my App on Android Studio emulator, requests sent from the app can reach the BackEnd through Ngrok. On my real device, when I open a browser and send /GET I can also reach BackEnd through Ngrok. But, when I run my app on my real device (I installed the apk-debug generated from Android Studio), the request doesn't have any response and I can't see Ngrok receiving it in the logs, neither the Back-end.
Retrofit retrofit = new Retrofit.Builder()
//.baseUrl("http://10.0.2.2:3000/")
.baseUrl("http://1e2b8b83.ngrok.io/")
.addConverterFactory(GsonConverterFactory.create())
.build();
I found it :
Android P version is blocking requests to HTTP servers. We should either communicate to an HTTPS server or to use a quick fix. The fix then is to create an xml file with the following content :
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">2b8e18b3.ngrok.io</domain>
<domain includeSubdomains="true">localhost</domain>
</domain-config>
then add it in the MANIFEST Application balise as follow :
<application
...
android:networkSecurityConfig="#xml/network_security_config"
... />
Big thanks to the guy who wrote this article :
https://medium.com/mindorks/my-network-requests-are-not-working-in-android-pie-7c7a31e33330

Categories

Resources