Android - 绑定移动网络套接字时权限被拒绝(OkHttp.socketFactory(network.socketFactory))

Posted

技术标签:

【中文标题】Android - 绑定移动网络套接字时权限被拒绝(OkHttp.socketFactory(network.socketFactory))【英文标题】:Android - Permission denied when binding a mobile network socket (OkHttp.socketFactory(network.socketFactory)) 【发布时间】:2022-01-02 19:51:04 【问题描述】:

我正在寻找与以下问题相关的帮助/想法:

我想要达到的目标:

使用 Retrofit2、OktHttp 在 android 上通过移动网络路由请求

我做了什么:

使用ConnectivityManager获得了所需的Network实例 为 OkHttpClient 设置 socketFactory 以使用 Network 实例中的那个 在AndroidManifest.xml中指定了这些权限。:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>

示例代码:

val network: Network = connectivityManager.allNetworks.first 
    connectivityManager.getNetworkCapabilities(it)?.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == true


val okHttpClient = OkHttpClient.Builder()
            .socketFactory(network.socketFactory)
            .build()

结果:

抛出异常:java.net.SocketException:将套接字绑定到网络 505 失败:EACCES(权限被拒绝)

注意事项/免责声明:

以上适用于 WiFi 我知道这是一种不好的做法:它不是应用程序的默认行为。用户可以随时选择加入和退出。有一个特定的用例是有意义的。

如果您对我做错了什么有任何想法,或者为什么它不适用于移动网络,请告诉我。

【问题讨论】:

【参考方案1】:

我设法找出我做错的原因。

简而言之:

使用 ConnectivityManager.requestNetwork() 代替 ConnectivityManager.getAllNetworks(),指定网络详细信息并使用收到的详细信息。
val cellularRequest = NetworkRequest.Builder()
    .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
    .build()

connectivityManager.requestNetwork(cellularRequest, object :
            ConnectivityManager.NetworkCallback() 
            override fun onAvailable(network: Network) 
                // use the network...
            
        )

说来话长: 测试时,我打开了 WiFi 和移动数据。 来自关于 ConnectivityManager.getAllNetworks() 的文档:

“返回框架当前跟踪的所有网络的数组。” 我想这里的关键词是我强调的部分(移动数据网络接口从一开始就不会被跟踪,它不会出现在列表中。当我看到具有CELLULAR功能的那个时,我想那就是我要找的那个。我弄错了。那是一个不同的界面。我没有观察到它没有互联网功能。) 默认返回2个网络实例,如下:
Network ID Capabilities
525 Transports: CELLULARCapabilities: IMS&NOT_METERED&TRUSTED&NOT_***&VALIDATED&NOT_ROAMING&FOREGROUND&NOT_CONGESTED&NOT_SUSPENDED
767 Transports: WIFICapabilities: NOT_METERED&INTERNET&NOT_RESTRICTED&TRUSTED&NOT_***&VALIDATED&NOT_ROAMING&FOREGROUND&NOT_CONGESTED&NOT_SUSPENDED

请注意,CELLULAR one(ID:525)没有互联网功能,并且有 IMS(如果我从文档中正确理解,它指的是 GSM 网络)。 当我尝试将套接字绑定到此网络时,它显然失败了。 然后我调用了 requestNetwork() 方法,发现我收到了一个新的(第三个)网络实例:

Network ID Capabilities
770 Transports: CELLULARCapabilities: SUPL&INTERNET&NOT_RESTRICTED&TRUSTED&NOT_***&VALIDATED&NOT_ROAMING&FOREGROUND&NOT_CONGESTED&NOT_SUSPENDED

使用这个,绑定可以无缝地工作。

【讨论】:

以上是关于Android - 绑定移动网络套接字时权限被拒绝(OkHttp.socketFactory(network.socketFactory))的主要内容,如果未能解决你的问题,请参考以下文章

用户模式权限被拒绝绑定到套接字

Android HTTP POST 请求错误 - 套接字 EACCES 失败(权限被拒绝)

权限被拒绝无法获取位置 Android

Apache 权限被拒绝连接到套接字

发送的广播数据报在Android中无法通过EACCES

错误消息“java.net.SocketException:套接字失败:EACCES(权限被拒绝)”