解决安卓OkHttp报错UnknownServiceException CLEARTEXT communication to not permitted by network security

笔者报错时的运行环境:

  • OkHttp 4.11.0

  • Android Studio Flamingo | 2022.2.1

  • Android SDK 33

  • Gradle 8.0.1

  • JDK 17

问题描述

  最近笔者在安卓中使用 OkHttp 向本地服务器发送请求的时候,发生了如下报错。

java.net.UnknownServiceException: CLEARTEXT communication to 192.168.XXX.XXX not permitted by network security policy
at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:188)
at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)
at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)
at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:255)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
at okhttp3.internal.connection.RealCall.execute(RealCall.kt:154)

问题原因

原来这个报错是因为笔者在调试时使用 OkHttp 发送的是 HTTP 明文请求,因此该请求被安卓阻止。

详情可见安卓中文官网描述:

When cleartext network traffic is not permitted, the platform's components (e.g. HTTP and FTP stacks, DownloadManager, MediaPlayer) will refuse this process's requests to use cleartext traffic. Third-party libraries are strongly encouraged to honor this setting as well.

在这里插入图片描述

解决办法

  解决办法也很简单。

方法 1

  直接使用 HTTPS 这种非明文的协议即可,这也是安卓官方推荐的解决办法。

方法 2

  在应用清单文件 AndroidManifest.xml 使用 android:usesCleartextTraffic="true" 来允许使用明文网络传输协议。如下所示。

<manifest ...>
    
    <uses-permission ... />
    
    <application
            ...其它属性...
            android:usesCleartextTraffic="true"
    >    
        <activity .../>
        
    </application>
    
</manifest>

【提示】

  官方已经说明,从安卓 9 及以上,上述属性 android:usesCleartextTraffic="true" 会默认为 false,这会导致此安卓应用拒绝明文请求。

  详情可见安卓中文官网描述:https://developer.android.google.cn/guide/topics/manifest/application-element#usesCleartextTraffic

Indicates whether the app intends to use cleartext network traffic, such as cleartext HTTP. The default value for apps that target API level 27 or lower is "true". Apps that target API level 28 or higher default to "false".
When the attribute is set to "false", platform components, for example, HTTP and FTP stacks, DownloadManager, and MediaPlayer, refuse the app's requests to use cleartext traffic.

在这里插入图片描述


方法 3

  方法 2 会开放所有的连接,这有很大的安全隐患。可以使用更细粒度的方式开放连接。

  在安卓资源目录下创建一个配置文件 res/xml/network_security_config.xml。在此配置文件中使用下面的代码可以开放明文访问 secure.example.com

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="false">
        <domain includeSubdomains="true">secure.example.com</domain>
    </domain-config>
</network-security-config>

  更多的信息,安卓中文官网:https://developer.android.google.cn/training/articles/security-config#CleartextTrafficPermitted

补充

  当然,还要在应用清单文件 AndroidManifest.xml 中使用如下代码开启网络权限,不然还是无法联网。

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

猜你喜欢

转载自blog.csdn.net/wangpaiblog/article/details/131842841