首页 文章

强制Android使用没有互联网的Wifi网络

提问于
浏览
23

我正在构建一个Android应用程序,需要通过无法访问互联网的WiFi网络进行通信 . 问题是即使连接WiFi,当wifi网络上没有连接互联网时,机器人选择使用蜂窝/移动数据 .

我已经阅读了很多关于这个问题的帖子,其中许多涉及生根设备,但 生产环境 应用程序无法实现(root设备是 not 一个选项) . 其他解决方案(如我的代码bellow)建议使用 bindProcessToNetwork() ,它在我的Sony Z2上完美运行,但在我测试的其他设备上没有(所有运行6.0.1)

private void bindToNetwork() {
    final ConnectivityManager connectivityManager = (ConnectivityManager) mActivity.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkRequest.Builder builder;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        builder = new NetworkRequest.Builder();
        //set the transport type do WIFI
        builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
        connectivityManager.requestNetwork(builder.build(), new ConnectivityManager.NetworkCallback() {
            @Override
            public void onAvailable(Network network) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {


                    connectivityManager.bindProcessToNetwork(null);
                    if (barCodeData.getSsid().contains("screenspace")) {
                        connectivityManager.bindProcessToNetwork(network);
                    }

                } else {
                    //This method was deprecated in API level 23
                    ConnectivityManager.setProcessDefaultNetwork(null);
                    if (barCodeData.getSsid().contains("screenspace")) {

                        ConnectivityManager.setProcessDefaultNetwork(network);
                    }
                }

                connectivityManager.unregisterNetworkCallback(this);
            }
        });
    }
}

5 回答

  • 1

    您可以尝试将全局设置captive_portal_detection_enabled设置为0(false) .

    实际发生的是,默认情况下,每次连接到wifi时,FW都会测试一台服务器(通常是谷歌),看看它是否是一个强大的wifi(需要登录) . 因此,如果您的wifi未连接到谷歌,此检查将失败 . 之后,设备知道wifi没有互联网连接,并且根本不会自动连接到它 .

    将此设置设置为0将避免此检查 .

    以编程方式: Settings.Global.putInt(getContentResolver(), Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 0);

    编辑:您可能需要直接使用字符串“captive_portal_detection_enabled”,而不是根据Android版本不可见的常量 .

  • 2

    您需要在“设置”中禁用移动数据(不确定,如果可以通过编程方式完成,这可能是一种可能的选项) - 或取出USIM;

    否则常见的行为是,它将始终回归到最佳可用连接(而与Internet网关的连接可能是首选,因为它被大多数应用程序使用) .

    也看到这个answer .

  • 1

    您可以检查wifi是否已连接,然后继续向用户显示一个对话框,要求他连接到wifi网络

    由于现在在API-23中不推荐使用NetworkInfo.isConnected()方法,因此这里有一种方法可以检测Wi-Fi适配器是否已打开并使用WifiManager连接到接入点:

    private boolean checkWifiOnAndConnected() {
        WifiManager wifiMgr = (WifiManager) getSystemService(Context.WIFI_SERVICE);
    
        if (wifiMgr.isWifiEnabled()) { // Wi-Fi adapter is ON
    
            WifiInfo wifiInfo = wifiMgr.getConnectionInfo();
    
            if( wifiInfo.getNetworkId() == -1 ){
                return false; // Not connected to an access point
            }
            return true; // Connected to an access point
        }
        else {
            return false; // Wi-Fi adapter is OFF
        }
    }
    
  • 0

    你是在正确的道路上,解决方案确实是ConnectivityManager.bindProcessToNetwork(network) . 此信息发布在本文的Android开发者博客中:Connecting your App to a Wi-Fi Device .

    查看您的代码 barCodeData.getSsid() 不会't look that is getting the SSID of the currently connected wifi network. If that'这是您的代码永远不会成功绑定到网络的情况 .

    尝试替换你的if语句

    if (barCodeData.getSsid().contains("screenspace"))
    

    if (getNetworkSsid(context).equals("screenspace"))
    

    kotlin 中的Helper方法检索连接的wifi网络的SSID

    private fun getNetworkSsid(context: Context?): String {
        // WiFiManager must use application context (not activity context) otherwise a memory leak can occur
        val mWifiManager = context?.applicationContext?.getSystemService(Context.WIFI_SERVICE) as WifiManager
        val wifiInfo: WifiInfo? = mWifiManager.connectionInfo
        if (wifiInfo?.supplicantState == SupplicantState.COMPLETED) {
            return wifiInfo.ssid.removeSurrounding("\"")
        }
        return ""
    }
    

    如果仍然不起作用,请按照my complete solution我使用相同的方法,但有一些额外的检查 . 我在Android版本5.1.1,6.0,6.0.1,7.1.1和8.1.0中测试了它 .

  • 0

    Kotlin的解决方案

    class ConnectWithoutInternetTest constructor(
    private val mContext: Context,
    private val connectivityManager: ConnectivityManager,
    private val wifiManager: WifiManager
    ) {
    
    private val mWifiBroadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            when (intent.action) {
                WifiManager.NETWORK_STATE_CHANGED_ACTION -> {
                    val info = intent.getParcelableExtra<NetworkInfo>(WifiManager.EXTRA_NETWORK_INFO)
                    val isConnected = info.isConnected
    
                    val ssid: String? = normalizeAndroidWifiSsid(wifiManager.connectionInfo?.ssid)
    
                    if (isConnected) {
                        val builder = NetworkRequest.Builder()
                        builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                        connectivityManager.registerNetworkCallback(
                            builder.build(),
                            object : ConnectivityManager.NetworkCallback() {
                                override fun onAvailable(network: Network) {
                                    super.onAvailable(network)
                                    val networkInfo = connectivityManager.getNetworkInfo(network)
                                    val networkSsid = networkInfo.extraInfo
                                    if (networkSsid == ssid) {
                                        connectivityManager.unregisterNetworkCallback(this)
                                    }
                                }
                            })
                    }
                }
            }
        }
    }
    
    private fun init() {
        val intentFilter = IntentFilter()
        intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION)
        mContext.registerReceiver(mWifiBroadcastReceiver, intentFilter)
    }
    
    private fun destroy() {
        mContext.unregisterReceiver(mWifiBroadcastReceiver)
    }
    
    private fun normalizeAndroidWifiSsid(ssid: String?): String? {
        return ssid?.replace("\"", "") ?: ssid
    }
    
    fun connectToWifi(ssidParam: String, password: String?) {
        init()
        val ssid = "\"$ssidParam\""
        val config = wifiManager.configuredNetworks.find { it.SSID == ssid }
        val netId = if (config != null) {
            config.networkId
        } else {
            val wifiConfig = WifiConfiguration()
            wifiConfig.SSID = ssid
            password?.let { wifiConfig.preSharedKey = "\"$password\"" }
            wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE)
            wifiManager.addNetwork(wifiConfig)
        }
    
        wifiManager.disconnect()
        val successful = wifiManager.enableNetwork(netId, true)
    }
    

相关问题