解决安卓 9 明文传输 Cleartext HTTP traffic not permitted

Android 2020-04-13 阅读 163 评论 0

问题描述

安卓项目在 Android P 即安卓 9 以下(不包括安卓 9)的手机,使用 OkHttp3 请求网络一直正常,但是在Android P 就会出现以下错误:

java.net.UnknownServiceException: CLEARTEXT communication to example.com not permitted by network security policy
        at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:176)
        at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:249)
        at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:108)

使用 HttpURLConnection 时,会出现:

D/NetworkSecurityConfig: No Network Security Config specified, using platform default
W/System.err: java.io.IOException: Cleartext HTTP traffic to example.com not permitted
W/System.err:     at com.android.okhttp.HttpHandler$CleartextURLFilter.checkURLPermitted(HttpHandler.java:115)
W/System.err:     at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:458)
W/System.err:     at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:407)
W/System.err:     at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:538)

解决方案

可以使用以下几种方法解决这个错误。

1. 使用 https 协议,替换 http

从 Android P(安卓 9,API 级别 28) 系统开始,如果应用使用的是非加密的明文流量的 http 网络请求,则会导致该应用无法进行网络请求,https 则不会受影响,同样地,如果应用嵌套了 webview,webview 也只能使用 https 请求。

因此,项目可以全部使用 https 协议来解决这个问题。

2. 增加 android:usesCleartextTraffic

AndroidManifest.xml 文件的 application 标签,增加 android:usesCleartextTraffic="true" ,表示对整个项目启用明文传输的支持,如下所示。

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

3. 增加 network-security-config 配置

参考官方的 network-security-config ,配置任意数量 domain-config 标签,属性 cleartextTrafficPermittedtrue ,表示允许明文传输,false 表示停用明文流量。同时设置一个或多个域名 domain ,属性 includeSubdomains 为 true 表示此域名规则将匹配所有的子域名,false 表示该规则仅适用于指定域名。

  • 创建 res/xml/network_security_config.xml 配置文件,内容如下。
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <!-- 匹配子域名 example.com -->
        <domain includeSubdomains="true">example.com</domain>
        <!-- 仅匹配域名 api.baidu.com -->
        <domain includeSubdomains="false">api.baidu.com</domain>
    </domain-config>
</network-security-config>
  • 配置 android:networkSecurityConfig

在 AndroidManifest.xml 引用 network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        ...
        android:networkSecurityConfig="@xml/network_security_config"
        ...>
    </application>
</manifest>
最后更新 2020-04-13