安卓 : Reconnect to Wi-Fi after entering coverage area while screen turned off

标签 android xamarin.android android-wifi wifimanager

我一直在努力解决当设备进入接入点范围内而不打开屏幕时自动打开 Wi-Fi 的问题。测试和找出解决方案一直非常令人沮丧,尤其是因为不同的设备会产生完全不同的结果。

基础测试
在此测试期间保持屏幕关闭。该应用程序应持有 WifiLock。

  1. 走出 WiFi 覆盖范围并在那里停留一分钟。
  2. 回到报道中。

结果:Wifi 没有立即重新连接,因此应用程序没有重新连接到服务器。根据设备和设置,有时在屏幕打开之前根本不会重新连接。

强制重新连接 Wi-Fi
好的,这次如果 Wifi 断开,我的应用程序会每隔一段时间调用 WifiManager.Reconnect()。

重复测试。 结果:对 S3 有效,对其他设备失败。

尝试添加一些其他调用
尝试了 WifiManager.Scan()、WifiManager.Reassociate() 等的不同组合。最终它适用于除 S4 之外的大多数设备(HTC、S3)。

似乎适用于所有设备的代码

NetworkInfo wifiInfo = _androidConnectivityMgr.GetNetworkInfo(ConnectivityType.Wifi);
if (!_wifiManager.IsWifiEnabled || _wifiManager.WifiState == WifiState.Disabled || _wifiManager.WifiState == WifiState.Disabling)
{
    // Make sure the Wi-Fi is enabled, required for some devices when enable WiFi does not occur immediately
    _wifiManager.SetWifiEnabled(true);
}

if (!wifiInfo.IsConnectedOrConnecting)
{
    // Do not wait for the OS to initiate a reconnect to a Wi-Fi router
    _wifiManager.PingSupplicant();
    if (_wifiManager.WifiState == WifiState.Enabled)
    {
        try
        {
            // Brute force methods required for some devices
            _wifiManager.SetWifiEnabled(false);
            _wifiManager.SetWifiEnabled(true);
        }
        catch (Java.Lang.SecurityException)
        {
            // Catching exception which should not occur on most devices. OS bug details at :
            // https://code.google.com/p/android/issues/detail?id=22036
        }
    }
    _wifiManager.Disconnect();
    _wifiManager.StartScan();
    _wifiManager.Reassociate();
    _wifiManager.Reconnect();
}

我什至不确定所有这些代码是否必要,因为我无法在网上找到很多信息。 WifiFixer确实帮助了一些。但这似乎适用于我测试过的设备。

问题

  • 有更好的方法吗?
  • 制造商是否真的修改了我可以看到如此大差异的基本 Android?
  • 这是完全错误的处理方式吗?

感谢您阅读所有这些:)

附加说明

  1. 代码在从 AlarmManager 启动的 10 秒以上的时间间隔内运行。 WakeLock 仅在此调用期间保持。
  2. 在这个看起来很吓人的解决方案/破解之前,“Wifi sleep 策略”影响了结果。这让我感到困惑,因为我一直拿着 WifiLock,我认为这相当于“从不”。
  3. 以编程方式更改“Wifi sleep 策略”对 S4 不起作用,其他人可以确认吗?
  4. 是的,我们有这样做的特殊需要,并且知道对电池的影响。

最佳答案

我的情况略有不同 - 我一开始并没有锁定 wifi (我使用的是普通 android,所以我不得不翻译你的方法)。

屏幕关闭,CPU 关闭, radio 死机。警报唤醒我的(清醒的)服务 - 我持有(部分)唤醒锁。

我想要的是 - 如果启用 wifi 以连接到接入点,它在 radio 死机之前已连接 - 我获得一个 wifi 锁并调用你的函数 - wakeWifiUp()。当 radio 停止运行时(!wifiInfo.IsConnectedOrConnecting 为真)当我尝试连接时网络无法访问。我解决了这个问题:

public final class NetworkService extends WakefulIntentService {

    // this is an intent service - runs on its own thread - otherwise it would
    // deadlock as I am using it. Moreover it holds a wakelock and woken up by
    // an AlarmManager's Receiver - works reliably
    private BroadcastReceiver mConnectionReceiver;
    private volatile static CountDownLatch latch;

    @Override
    protected void doWakefulWork(Intent intent) {
        WifiLock _wifiLock = null;
        WifiManager wm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        boolean failedToConnect = true;
        if (wm != null && wm.isWifiEnabled()) {// Don't want to enable it myself
            _wifiLock = wm.createWifiLock(
            /* WifiManager.WIFI_MODE_FULL_HIGH_PERF */0x3, this.getClass()
                .getName() + ".WIFI_LOCK");
            _wifiLock.acquire();
            failedToConnect = !wakeWifiUp();
        }
        if (failedToConnect) {
            if (_wifiLock != null) _wifiLock.release();
            w("No connection !");
            return;
        }
        HttpURLConnection connection = null;
        try {
            connection = connection(); 
        } catch (IOException e) {/* won't throw - it doesn't do much*/}
        OutputStream serverOutputStream = null;
        try {
            serverOutputStream = connection.getOutputStream(); // now
            // this is really where the connection might seriously throw
            // .... Work ....
        } catch (IOException e) {
            w("IOException sending data " + e.getMessage());
            // I get here : Network unreachable when radio dies
        } finally {
            if (_wifiLock != null) _wifiLock.release();
            if (connection != null) connection.disconnect();
        }
    }

    private HttpURLConnection connection() throws MalformedURLException,
            IOException {
        HttpURLConnection connection = (HttpURLConnection) new URL("localhost")
            .openConnection();
        connection.setDoOutput(true); // triggers POST
        connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setRequestProperty("User-Agent",
            "Android Multipart HTTP Client 1.1");
        return connection;
    }

    private boolean wakeWifiUp() {
        ConnectivityManager _androidConnectivityMgr = (ConnectivityManager)
                getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo wifiInfo = _androidConnectivityMgr
            .getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        WifiManager _wifiManager = (WifiManager)
                getSystemService(Context.WIFI_SERVICE);
        final int wifiState = _wifiManager.getWifiState();
        if (!_wifiManager.isWifiEnabled()
            || wifiState == WifiManager.WIFI_STATE_DISABLED
            || wifiState == WifiManager.WIFI_STATE_DISABLING) {
            // Make sure the Wi-Fi is enabled, required for some devices when
            // enable WiFi does not occur immediately
            d("!_wifiManager.isWifiEnabled()");
            _wifiManager.setWifiEnabled(true);
            // do not enable if not enabled ! FIXME
            return false;
        }
        if (!wifiInfo.isConnectedOrConnecting()) {
            d("Wifi is NOT Connected Or Connecting - "
                + "wake it up and wait till is up");
            // Do not wait for the OS to initiate a reconnect to a Wi-Fi router
            _wifiManager.pingSupplicant();
            if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
                try {
                    // Brute force methods required for some devices
                    _wifiManager.setWifiEnabled(false);
                    _wifiManager.setWifiEnabled(true);
                } catch (SecurityException e) {
                    // Catching exception which should not occur on most
                    // devices. OS bug details at :
                    // https://code.google.com/p/android/issues/detail?id=22036
                }
            }
            _wifiManager.disconnect();
            _wifiManager.startScan();
            _wifiManager.reassociate();
            _wifiManager.reconnect();
            // THIS IS WHAT I DO TO WAIT FOR A CONNECTION
            try {
                mConnectionReceiver = new WifiConnectionMonitor();
                startMonitoringConnection();
                latch = new CountDownLatch(1);
                w("I wait");
                latch.await();
                w("Woke up");
                return true; // made it
            } catch (InterruptedException e) {
                w("Interrupted while waiting for connection", e);
                return false;
            } finally {
                stopMonitoringConnection();
            }
        }
        return true;
    }

    static void downTheLatch() {
        latch.countDown();
    }

    private synchronized void startMonitoringConnection() {
        IntentFilter aFilter = new IntentFilter(
            ConnectivityManager.CONNECTIVITY_ACTION);
        aFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
        registerReceiver(mConnectionReceiver, aFilter);
    }

    private synchronized void stopMonitoringConnection() {
        unregisterReceiver(mConnectionReceiver);
    }

    private final class WifiConnectionMonitor extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent in) {
            String action = in.getAction();
            if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
                NetworkInfo networkInfo = in
                    .getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
                d(networkInfo + "");
                if (networkInfo.isConnected()) {
                    d("Wifi is connected!");
                    NetworkService.downTheLatch(); // HERE THE SERVICE IS WOKEN!
                }
            }
        }
    }
}

顺便说一句,并不是所有的 wakeWifiUp() 技巧都需要(在我的例子中)并且所有的 !_wifiManager.isWifiEnabled() 都可能被忽略 - 因为我只使用如果用户启用了网络。为了完整起见,我保留了它。

回顾:在我的场景中,您的方法是不够的(如果我正确地翻译成 java 并且没有犯一些愚蠢的错误,这总是适用的 - 另请参阅我的 connection())。我需要等待建立连接 - 但之后一切都很好。仍然不确定您是如何使用它的——如果像我一样,那么不同之处可能在于您一直持有 wifi 锁

HTC Nexus 1, 2.3.7, Cyanogen mod(不要拍我已经给它测试了)。

会及时通知您

关于安卓 : Reconnect to Wi-Fi after entering coverage area while screen turned off,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19148765/

相关文章:

xamarin - Xamarin Studio 中的 "Execution Failed"错误

android - 在android中创建Wifi热点配置

机器人 : how to create GridView

c# - 我应该如何使用 xamarin 表单在 android 上创建主要 Activity 以支持画中画模式?

java - 如何使我的 ActionBar DrawerToggle 按钮正常工作?

Android Activity 背景图片

java - Android 手机可以暂停 wifi 扫描请求吗?

android - 以编程方式自动连接到特定的 WiFi 接入点

java - Android教程报错: edit_message cannot be resolved or is not a field

android - 如何通过电子邮件发送密码?