随着国内应用市场的逐步规范,上架各应用市场的要求也越来越高,就目前来看,国内应用市场平台上架普遍要求应用的 targetSdkVersion 不得低于 26,也算是紧跟『Google Play』(targetSdkVersion 不得低于 28)的步伐了。

当然,为了让用户有更加舒适的体验,我们开发应用的时候理应将 targetSdkVersion 设置得越高越好,尽管这意味着开发者将面临更加严格的权限管控和繁琐的适配。

其中就包括了 Android M(Marshmallow,Android 6.0,API Levle 23)的动态权限、Android O(Oreo,Android 8.0,API Level 26)的渠道通知等。

而在 Android P(Pie,Android 9,API Level 28)中,则对 HTTP 明文通信做出了限制。

Starting with Android 9 (API level 28), cleartext support is disabled by default.

从 Android 9(API Level 28)开始,系统默认情况下已停用明文支持。

如果你使用『OkHttp』进行明文的 HTTP 网络请求,会抛出如下异常:

W/System.err: java.net.UnknownServiceException: CLEARTEXT communication to <HOST> not permitted by network security policy

触发源码如下:

if (!Platform.get().isCleartextTrafficPermitted(host)) {
      throw new RouteException(new UnknownServiceException(
          "CLEARTEXT communication to " + host + " not permitted by network security policy"));
}

使用 Android 中标准 Java 接口 HttpURLConnection 来进行 HTTP 请求,也同样会抛出异常:

W/System.err: java.io.IOException: Cleartext HTTP traffic to <HOST> not permitted

而使用 HTTPS 请求则不会出现问题。

Android P 之后系统限制了明文的网络请求,非加密请求会被系统禁止掉,也就是说如果当前应用的请求是 HTTP 请求而非 HTTPS,就会导系统禁止当前应用进行该请求。

既然是 Android P 的问题,也就是说只要指定了 targetSdkVersion28,就必定会执行这段代码,那么我只要把其修改为低版本就可以避免了。

但是,在各大应用平台都在逐渐提高应用上架门槛的情况下,这必定不是长久之计,这与浏览器对 HTTPS 的要求是吻合的,不过在 Android 中我们依然可以通过一些简单的配置让应用支持 HTTP 请求。

最简单的方法,直接在 AndroidManifest 中设置明文开启:

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

复杂一点儿的方法,设置单独的网络安全配置文件,需在「res」目录下新建一个「xml」文件夹,并在该文件夹中创建一个「network_security_config.xml」文件,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

然后在 AndroidManifest 中引用该网络安全配置文件:

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

尽管这样看来使用单独的网络安全配置文件似乎有点儿繁琐,但有个好处是可以针对特定网域和特定应用配置自定义信任锚、配置用于调试的 CA 等,拥有更大的配置权限。

最后,还是建议督促下后端和运维人员赶紧上 HTTPS 吧。

参考内容: