Cleartext HTTP traffic to localhost not permitted

Cleartext HTTP traffic to localhost not permitted

Android 9(API 28)开始,系统默认 禁止所有非信任域名的明文 HTTP

{System.Net.Http.HttpRequestException: Connection failure ---> Java.IO.IOException: Cleartext HTTP traffic to 192.168.2.107 not permitted at Java.Interop.JniEnvironment.InstanceMethods.CallVoidMethod(JniObjectReference instance, JniMethodInfo method, JniArgumentValue* args) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/obj/Release/net7.0/JniEnvironment.g.cs:line 20370 at Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractVoidMethod(String encodedMember, IJavaPeerable self, JniArgumentValue* parameters) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs:line 47 at Java.Net.HttpURLConnectionInvoker.Connect() in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net8.0/android-34/mcw/Java.Net.HttpURLConnection.cs:line 735 at Xamarin.Android.Net.AndroidMessageHandler.<>c__DisplayClass133_0.b__0() in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs:line 526 --- End of managed Java.IO.IOException stack trace --- java.io.IOException: Cleartext HTTP traffic to 192.168.2.107 not permitted at com.android.okhttp.HttpHandler$CleartextURLFilter.checkURLPermitted(HttpHandler.java:127) at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:462) at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:131)

--- End of managed Java.IO.IOException stack trace --- java.io.IOException: Cleartext HTTP traffic to 192.168.2.107 not permitted at com.android.okhttp.HttpHandler$CleartextURLFilter.checkURLPermitted(HttpHandler.java:127) at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:462) at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:131)

--- End of inner exception stack trace --- at Xamarin.Android.Net.AndroidMessageHandler.<>c__DisplayClass133_0.b__0() in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs:line 536 at System.Threading.Tasks.Task.InnerInvoke() at System.Threading.Tasks.Task.<>c.<.cctor>b__281_0(Object obj) at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state) --- End of stack trace from previous location --- at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) --- End of stack trace from previous location --- at Xamarin.Android.Net.AndroidMessageHandler.DoProcessRequest(HttpRequestMessage request, URL javaUrl, HttpURLConnection httpConnection, CancellationToken cancellationToken, RequestRedirectionState redirectState) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs:line 591 at Xamarin.Android.Net.AndroidMessageHandler.DoSendAsync(HttpRequestMessage request, CancellationToken cancellationToken) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs:line 456 at System.Net.Http.HttpClient.g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken) at TodoReminderApp.Services.ApiService.d__61[[TodoReminderApp.Models.ApiResponse1[[TodoReminderApp.Models.LoginResponse, TodoReminderApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], TodoReminderApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext() in F:\Merchant\project\todotask\TodoReminderApp\TodoReminderApp\Services\ApiService.cs:line 71}

✅ 根本原因

Android 9(API 28)开始,系统默认 禁止所有非信任域名的明文 HTTP。 你虽然在 network_security_config.xml 里放行了 localhost,但没有把 192.168.2.107 也加进去,于是继续报错。


✅ 快速修复(开发阶段)

1️⃣ 修改 network_security_config.xml

把局域网地址也放进白名单(推荐用通配写法,避免 IP 经常变):

Platforms/Android/Resources/xml/network_security_config.xml

xml

复制

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <!-- 全局允许明文流量(仅调试用) -->
  <base-config cleartextTrafficPermitted="true" />

  <!-- 或者精确白名单 -->
  <!--
  <domain-config cleartextTrafficPermitted="true">
    <domain includeSubdomains="true">192.168.2.107</domain>
    <domain includeSubdomains="true">10.0.2.2</domain>
  </domain-config>
  -->
</network-security-config>

2️⃣ 确认 AndroidManifest.xml 已引用

xml

复制

<application
    android:networkSecurityConfig="@xml/network_security_config"
    ...
>

3️⃣ 彻底卸载 App 再重装

(或 adb uninstall <your.package.id>) —— 否则旧的 manifest 会缓存。


✅ 更“干净”的做法(长期方案)

  • 给后端加一张 自签名证书dotnet dev-certs https --trust),客户端用 https://192.168.2.107:5001
  • 或者在 Android 端使用 AndroidClientHandler + 自定义 ServerCertificateCustomValidationCallback 来信任自签名证书。

✅ 验证

如果报错

严重性 代码 说明 项目 文件 行 禁止显示状态 错误 APT2260: resource xml/network_security_config (aka com.companyname.todoreminderapp:xml/network_security_config) not found. This error is likely caused by an issue with the AndroidManifest.xml file or an Android manifest generation attribute in a source code file. 0

设置“生成操作”为 AndroidResource

  1. 右键 network_security_config.xml 文件
  2. 选择 属性
  3. 生成操作(Build Action) 设置为:AndroidResource

✅ 这是关键!否则文件不会被打包进 APK

🔍 常见错误排查

问题 解决方法
❌ 文件夹叫 XmlXML 改为全小写 xml
❌ 文件生成操作是 NoneC# 编译 改为 AndroidResource
❌ 文件在 AssetsResources 根目录 必须在 Resources/xml/
❌ 文件名是 NetworkSecurityConfig.xml 改为 network_security_config.xml
❌ 文件编码不是 UTF-8 用 VS 右键 → 高级保存选项 → UTF-8

✅ 如果你还想简化(可选)

如果你只是开发调试,可以 只保留 usesCleartextTraffic="true",去掉 networkSecurityConfig 引用

xml浅色版本

<application
    android:usesCleartextTraffic="true"
    ... >
</application>

这样就不需要 xml 文件了,也能解决 HTTP 被禁止的问题。

✅ 适合快速调试,但不如 network_security_config 安全可控