解决 Android 9 Pie: http 及 https 的网络连接问题
默认情况下启用网络传输层安全协议 (TLS)
如果您的应用以 Android 9 或更高版本为目标平台,则默认情况下 isCleartextTrafficPermitted()
函数返回 false
。 如果您的应用需要为特定域名启用明文,您必须在应用的网络安全性配置中针对这些域名将 cleartextTrafficPermitted
显式设置为 true
。
按进程分设基于网络的数据目录
为改善 Android 9 中的应用稳定性和数据完整性,应用无法再让多个进程共用同一 WebView
数据目录。 此类数据目录一般存储 Cookie、HTTP 缓存以及其他与网络浏览有关的持久性和临时性存储。
在大多数情况下,您的应用只应在一个进程中使用 android.webkit
软件包中的类,例如 WebView
和 CookieManager
。 例如,您应该将所有使用 WebView
的 Activity
对象移入同一进程。 您可以通过在应用的其他进程中调用 disableWebView()
,更严格地执行“仅限一个进程”规则。 该调用可防止 WebView
在这些其他进程中被错误地初始化,即使是从依赖内容库进行的调用也能防止。
如果您的应用必须在多个进程中使用 WebView
的实例,则必须先利用 WebView.setDataDirectorySuffix()
函数为每个进程指定唯一的数据目录后缀,然后再在该进程中使用 WebView
的给定实例。 该函数会将每个进程的网络数据放入其在应用数据目录内自己的目录中。
注:即使您使用 setDataDirectorySuffix()
,系统也不会跨应用的进程界限共享 Cookie 以及其他网络数据。 如果应用中的多个进程需要访问同一网络数据,您需要自行在这些进程之间复制数据。 例如,您可以调用 getCookie()
和 setCookie()
,在不同进程之间手动传输 Cookie 数据。
以应用为单位的 SELinux 域名
以 Android 9 或更高版本为目标平台的应用无法利用可全球访问的 Unix 权限与其他应用共享数据。 此变更可改善 Android 应用沙盒的完整性, 具体地讲,就是要求应用的私有数据只能由该应用访问。
要与其他应用共享文件,请使用 content provider。
连接变更
连接数据计数和多路径
在以 Android 9 或更高版本为目标平台的应用中,系统计算并非当前默认网络的网络流量,例如,当设备连接 WLAN 时的蜂窝流量,并在 NetworkStatsManager
类中提供函数以查询该流量。
具体而言,getMultipathPreference()
现在将返回一个基于上述网络流量的值。 从 Android 9 开始,此函数针对蜂窝数据返回 true
,但当超过一天内累积的特定流量时,它将开始返回 false
。 在 Android 9 上运行的应用必须调用此函数并采用此提示。
ConnectivityManager.NetworkCallback
类现在将有关 VPN 的信息发送到应用。 此变更让应用侦听连接事件变得更容易,而无需混用同步和异步调用,也无需使用有限的 API。 此外,它还意味着将设备同时连接至多个 WLAN 网络或多个蜂窝网络时,信息传输可按预期工作。
Apache HTTP 客户端弃用
在 Android 6.0 中,我们取消了对 Apache HTTP 客户端的支持。 从 Android 9 开始,默认情况下该内容库已从 bootclasspath 中移除且不可用于应用。
要继续使用 Apache HTTP 客户端,以 Android 9 及更高版本为目标的应用可以向其 AndroidManifest.xml
添加以下内容:
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
注:拥有最低 SDK 版本 23 或更低版本的应用需要 android:required="false"
属性,因为在 API 级别低于 24 的设备上,org.apache.http.legacy
库不可用。 (在这些设备上,Apache HTTP 类在 bootclasspath 中提供。)
作为使用运行时 Apache 库的替代,应用可以在其 APK 中绑定自己的 org.apache.http
库版本。 如果进行此操作,您必须将该库重新打包(使用一个类似 Jar Jar 的实用程序)以避免运行时中提供的类存在类兼容性问题。
关于 Android 9 更多变更去官网看看:https://developer.android.google.cn/about/versions/pie/android-9.0-changes-28
Google表示,为保证用户数据和设备的安全,针对下一代 Android 系统(Android P) 的应用程序,将要求默认使用加密连接,这意味着 Android P 将禁止 App 使用所有未加密的连接,因此运行 Android P 系统的安卓设备无论是接收或者发送流量,未来都不能明码传输,需要使用下一代(Transport Layer Security)传输层安全协议,而 Android Nougat 和 Oreo 则不受影响。
因此在Android 中 使用HttpUrlConnection进行http请求会出现以下异常:
W/System.err: java.io.IOException: Cleartext HTTP traffic to **** not permitted
使用OKHttp请求则出现:
java.net.UnknownServiceException: CLEARTEXT communication ** not permitted by network security policy
在Android P系统的设备上,如果应用使用的是非加密的明文流量的http网络请求,则会导致该应用无法进行网络请求,https则不会受影响,同样地,如果应用嵌套了webview,webview也只能使用https请求。
有人认为 Android P 上所有的 App 都需要使用 TLS 加密会降低上网体验,事实上这是一种误解,至于 App 对于少数旧服务器的连接如果非要使用明码传输,开发者需要更改 App 的网络安全配置以允许此类连接。
有以下三种解决方案
APP 改用 https 请求
argetSdkVersion 降到 27 以下
在 res 下新增一个 xml 目录,然后创建一个名为:network_config.xml 文件(名字自定) ,内容如下,大概意思就是允许开启 http 请求。
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
然后在APP的 AndroidManifest.xml 文件下的 application 标签增加以下属性。
<application
...
android:networkSecurityConfig="@xml/network_config"
...
/>
网络其他方案描述
从Android 9开始,需要根据网络全进行相关配置(According to Network security configuration )。 Starting with Android 9.0 (API level 28), cleartext support is disabled by default.
在AndroidManifest.xml中设置 android:usesCleartextTraffic="true"
即可。
<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
<uses-permission android:name="android.permission.INTERNET" />
<application
...
android:usesCleartextTraffic="true"
...>
...
</application>
</manifest>
但这样设置可能会有一个问题,具体见下面,没有的话就算了:
Also as @david.s’ answer pointed out android:targetSandboxVersion can be a problem too. According to Manifest Docs: android:targetSandboxVersion The target sandbox for this app to use. The higher the sandbox version number, the higher the level of security. Its default value is 1; you can also set it to 2. Setting this attribute to 2 switches the app to a different SELinux sandbox. The following restrictions apply to a level 2 sandbox:
The default value of usesCleartextTraffic in the Network Security Config is false.
Uid sharing is not permitted.
如果在 <manifest>
中有配置 android:targetSandboxVersion
,将其减少到1. 即在 AndroidManifest.xml 文件中:
<?xml version="1.0" encoding="utf-8"?>
<manifest android:targetSandboxVersion="1">
<uses-permission android:name="android.permission.INTERNET" />
...
</manifest>
这个方法可以解决 android 9 okhttp 报错
java.net.UnknownServiceException: CLEARTEXT communication to develop.dianmoge.com not permitted by network security policy