一、前言
从Android P(即Android 9)开始,Android系统会限制了http明文流量的网络请求,若是使用http访问都会抛出
java.io.IOException: Cleartext HTTP traffic to ... not permitted
异常,使用https
就可以正常进行网络请求
官方说明
二、异常现象
1、若是targetSdkVersion >= 28
的应用发起http网络请求
,会抛出类似以下的异常:
Caused by: java.io.IOException: Cleartext HTTP traffic to a.gdt.qq.com not permitted
at com.android.okhttp.HttpHandler$CleartextURLFilter.checkURLPermitted(HttpHandler.java:124)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:462)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:131)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:262)
at com.qq.gdt.action.a.a.e.a(Unknown Source:65)
at com.qq.gdt.action.a.a.e.a(Unknown Source:65)
at com.qq.gdt.action.a.a.a.a.a(Unknown Source:10)
at com.qq.gdt.action.a.a.a.c.a(Unknown Source:43)
at com.qq.gdt.action.a.a.a.e.a(Unknown Source:8)
at com.qq.gdt.action.a.a.a.c.a(Unknown Source:43)
at com.qq.gdt.action.a.a.a.f.a(Unknown Source:4)
at com.qq.gdt.action.a.a.a.c.a(Unknown Source:43)
at com.qq.gdt.action.a.a.a.d.a(Unknown Source:34)
at com.qq.gdt.action.a.a.a.c.a(Unknown Source:43)
at com.qq.gdt.action.a.a.a.b(Unknown Source:36)
at com.qq.gdt.action.a.a.a.a(Unknown Source:0)
at com.qq.gdt.action.a.a.a$1.run(Unknown Source:2)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
三、异常分析
1、面向 Android 9(API 级别 28)及更高版本应用的网络安全默认配置如下所示:
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<certificates src="system" />
</trust-anchors>
</base-config>
也就是说,Android 9之后,系统默认是限制明文传输,而且也只信任系统级别的证书,用户自定义的证书默认是不会信任的
2、面向 Android 7.0(API 级别 24)到 Android 8.1(API 级别 27)的应用的网络安全默认配置如下所示:
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
</trust-anchors>
</base-config>
也就是说,Android 7.0-Android 8.1系统默认是允许明文传输,但是也是只信任系统级别的证书,用户自定义的证书默认是不会信任的
3、面向 Android 6.0(API 级别 23)及更低版本应用的默认网络安全配置如下所示:
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</base-config>
也就是说,Android 6.0以及以下版本,系统默认是允许明文传输,同时信任系统级别的证书与用户自定义的证书
四、解决方案
1、方案一:设置安全网络配置
1)在res/xml目录下新建文件:network_security_config.xml,内容设置如下:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!-- 设置允许http明文传输-->
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<!-- 设置信任系统级别证书-->
<certificates src="system" />
<!-- 设置信任用户自定义证书,设置之后才能用fiddler之类的抓取https请求,出包最好不要设置,防止被抓包-->
<certificates src="user" />
</trust-anchors>
</base-config>
</network-security-config>
2)在AndroidManifest.xml的application标签下增加以下属性声明:
android:networkSecurityConfig="@xml/network_security_config"
2、方案二:设置targetSdkVersion <= 28亦可