Android 8: Cleartext HTTP traffic not permitted

Android 8: Cleartext HTTP traffic not permitted

技术背景

从 Android 9(API 级别 28)开始,默认情况下禁用了明文(Cleartext)支持。当应用尝试使用 HTTP 进行网络通信时,就会出现 “Cleartext HTTP traffic not permitted” 错误。这是出于安全考虑,因为明文通信容易受到中间人攻击,导致数据泄露和篡改。

实现步骤

方案一:使用 HTTPS 代替 HTTP

首先尝试将请求的 URL 从 http:// 替换为 https://。例如:

1
webView.loadUrl("https://www.example.com");

方案二:配置网络安全文件

  1. 创建 res/xml/network_security_config.xml 文件:
1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">api.example.com</domain>
</domain-config>
</network-security-config>
  1. AndroidManifest.xml 中引用该配置文件:
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
<uses-permission android:name="android.permission.INTERNET" />
<application
...
android:networkSecurityConfig="@xml/network_security_config"
...>
...
</application>
</manifest>

方案三:在 AndroidManifest.xml 中设置 android:usesCleartextTraffic

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
<uses-permission android:name="android.permission.INTERNET" />
<application
...
android:usesCleartextTraffic="true"
...>
...
</application>
</manifest>

方案四:降低 android:targetSandboxVersion

如果 AndroidManifest.xml 中设置了 android:targetSandboxVersion="2",将其降低为 1

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

针对不同环境的配置

开发和生产环境使用不同配置

  1. 创建 res/xml/network_security_config_dev.xmlres/xml/network_security_config_prod.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- res/xml/network_security_config_dev.xml -->
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">10.0.2.2</domain>
</domain-config>
</network-security-config>

<!-- res/xml/network_security_config_prod.xml -->
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">yourdomain.com</domain>
</domain-config>
</network-security-config>
  1. build.gradle 中配置不同环境的配置文件:
1
2
3
4
5
6
7
8
9
buildTypes {
release {
minifyEnabled false
manifestPlaceholders.securityConfig = "@xml/network_security_config_prod"
}
debug {
manifestPlaceholders.securityConfig = "@xml/network_security_config_dev"
}
}
  1. AndroidManifest.xml 中使用占位符:
1
2
3
4
5
6
7
8
9
10
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:networkSecurityConfig="${securityConfig}"
...>
...
</application>

仅在调试时允许明文通信

build.gradle 中配置:

1
2
3
4
5
6
7
8
9
10
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
manifestPlaceholders = [usesCleartextTraffic:"false"]
}
debug {
manifestPlaceholders = [usesCleartextTraffic:"true"]
}
}

AndroidManifest.xml 中使用占位符:

1
2
3
4
5
6
<application
...
android:usesCleartextTraffic="${usesCleartextTraffic}"
...>
...
</application>

针对不同框架的解决方案

React Native 项目

创建 android/app/src/debug/res/xml/react_native_config.xml

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="false">localhost</domain>
<domain includeSubdomains="false">10.0.2.2</domain>
<domain includeSubdomains="false">10.0.3.2</domain>
</domain-config>
</network-security-config>

创建 android/app/src/debug/AndroidManifest.xml

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

<application tools:targetApi="28"
tools:ignore="GoogleAppIndexingWarning"
android:networkSecurityConfig="@xml/react_native_config" />
</manifest>

Xamarin Form 项目

Android:在 AssemblyInfo.cs 中添加:

1
[assembly: Application(UsesCleartextTraffic = true)]

iOS:在 info.plist 中添加:

1
2
3
4
5
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>

Ionic 项目

config.xml 中添加:

1
2
3
4
<edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application" xmlns:android="http://schemas.android.com/apk/res/android">
<application android:networkSecurityConfig="@xml/network_security_config" />
<application android:usesCleartextTraffic="true" />
</edit-config>

network_security_config.xml 中添加:

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">xxx.yyyy.com</domain>
</domain-config>
</network-security-config>

.NET 8 Maui 项目

AndroidManifest.xmlapplication 标签中添加:

1
2
3
<application ... android:usesCleartextTraffic="true">
...
</application>

核心代码

以下是一个使用 OkHttp 进行网络请求的示例代码,同时允许明文和 TLS 连接:

1
2
3
4
5
6
7
8
9
10
11
import okhttp3.ConnectionSpec;
import okhttp3.OkHttpClient;
import java.util.Collections;
import java.util.concurrent.TimeUnit;

OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(10, TimeUnit.SECONDS)
.connectTimeout(10, TimeUnit.SECONDS)
.cache(null)
.connectionSpecs(Collections.singletonList(ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT))
.build();

最佳实践

  • 优先使用 HTTPS 进行网络通信,因为 HTTPS 提供了数据加密和身份验证,能有效提高通信的安全性。
  • 如果必须使用 HTTP,可以针对特定的开发环境允许明文通信,而在生产环境中禁止,以平衡开发的便利性和安全性。
  • 定期检查服务器的 SSL 证书链,确保其完整性和有效性。

常见问题

配置后仍然出现错误

  • 检查 network_security_config.xml 中的域名配置是否正确,确保包含了所有需要访问的域名。
  • 检查 AndroidManifest.xml 中是否正确引用了配置文件或设置了 android:usesCleartextTraffic 属性。

性能问题

使用 HTTPS 可能会带来一定的性能开销,因为需要进行加密和解密操作。可以通过优化服务器配置和使用 HTTP/2 等协议来提高性能。

兼容性问题

不同版本的 Android 系统可能对网络安全配置有不同的要求,需要确保配置在目标设备上兼容。


Android 8: Cleartext HTTP traffic not permitted
https://119291.xyz/posts/android-8-cleartext-http-traffic-not-permitted/
作者
ww
发布于
2025年5月27日
许可协议