一旦设备在接入点的范围内而不打开屏幕,我一直在努力自动打开Wi-Fi。测试和找出解决方案非常令人沮丧,特别是因为不同的设备有完全不同的结果。
基础测试
在此测试期间保持屏幕关闭。该应用程序应该持有WifiLock。
结果: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帮助了一些人。但这似乎适用于我测试过的设备。
问题
感谢阅读所有这些:)
附加说明
答案 0 :(得分:2)
我的情况略有不同 - 我没有开始使用 的wifi锁(我在普通的android上,所以我不得不翻译你的方法)。< / p>
屏幕关闭,CPU关闭,无线电死机。警报唤醒我的(唤醒)服务 - 我持有(部分)唤醒锁。
我想要的是 - 如果启用wifi连接到接收点,它在无线电死亡之前就连接了 - 我获得了一个wifi锁,我调用了你的功能 - wakeWifiUp()
。当收音机死亡时(!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(不要射击我已经给它进行测试)。
会让你发布
答案 1 :(得分:1)
在Android 4.4 KitKat(Nexus 4)下,Alex和Mr_and_Mrs_D的方法很接近,但并不完全一致。这可能与谷歌从KitKat开始的更积极的节电政策有关。我使用了他们的方法和修改的组合。
一般的想法是,在定期WiFi检查期间,显式启动扫描,然后在扫描结果处理程序中调用reassociate()和reconnect()。此外,在NETWORK_STATE_CHANGED_ACTION回调中,检查在释放唤醒锁之前是否建立了连接。关键是要保持唤醒锁定的时间足够长,以便WiFi连接正确建立(显然不会超过必要)。
周期性无线网络检查可以解决问题:
public static void CheckWiFi() {
mWakeLock.acquire();
if (!WiFi_Mgr.isWifiEnabled()) {
WiFi_Mgr.setWifiEnabled(true);
}
WiFi_Mgr.startScan();
//Set an alarm to fire after N seconds to release wake lock & shut off WiFi if no connection is available.
// ...
}
注册WiFi广播
//Setup WiFi connection status receiver
IntentFilter WiFiFilters = new IntentFilter();
WiFiFilters.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
WiFiFilters.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
this.registerReceiver(WiFiReceiver, WiFiFilters);
和WiFi事件处理程序
private final BroadcastReceiver WiFiReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
NetworkInfo netInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
// This is the magic bullet. The connection usually establishes after
// the scan results callback so release the wake lock here.
if(netInfo.isConnected()) {
mWakeLock.release();
}
}
//Search the scan results for saved WiFi APs.
else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action))
{
boolean foundMatch = false;
if (!IsWiFiConnected()) {
Map<String, Integer> savedNetworks = new HashMap<String, Integer>();
for (WifiConfiguration config : WiFi_Mgr.getConfiguredNetworks()) {
String escapedSSID = config.SSID.replaceAll("\"", "");
savedNetworks.put(escapedSSID, config.networkId);
}
List<ScanResult> scanResults = WiFi_Mgr.getScanResults();
for (ScanResult ap : scanResults) {
Integer networkId = savedNetworks.get(ap.SSID);
if (networkId != null) {
savedNetworks.remove(ap.SSID);
WiFi_Mgr.enableNetwork(networkId, false);
foundMatch = true;
}
}
}
if(foundMatch) {
WiFi_Mgr.reassociate();
WiFi_Mgr.reconnect();
}
if (IsWiFiConnected())
mWakeLock.release();
}
}
};
您需要声明必要的变量(例如,mWakeLock是部分非参考计数的唤醒锁; WiFi_Mgr是WifiManager的实例;等等......)。
答案 2 :(得分:0)
该地区有第二次出行。虽然上述解决方案适用于我们所有合格的设备,但是有太多的呼叫可能是不必要的。另外,我们得到了解决方案不起作用的新设备。这是一个更好的解决方案:
在每个时间间隔都会调用此代码
NetworkInfo wifiInfo = _androidConnectivityMgr.GetNetworkInfo(ConnectivityType.Wifi);
if (!wifiInfo.IsConnectedOrConnecting)
{
// Need to make sure the CPU does not go to sleep before the following async calls are finished
_wifiScanWakeLock.Acquire();
// Do not wait for the OS to initiate a reconnect to a Wi-Fi router
_wifiManager.StartScan();
}
完成Wi-Fi扫描后
private void OnWifiScanResultsReceived(Intent result)
{
NetworkInfo wifiInfo = _androidConnectivityMgr.GetNetworkInfo(ConnectivityType.Wifi);
if (!wifiInfo.IsConnectedOrConnecting)
{
Dictionary<string, int> savedNetworks = new Dictionary<string, int>();
foreach (WifiConfiguration config in _wifiManager.ConfiguredNetworks)
{
string escapedSsid = Regex.Replace(config.Ssid, "^\"|\"$", String.Empty);
savedNetworks[escapedSsid] = config.NetworkId;
}
foreach (ScanResult ap in _wifiManager.ScanResults)
{
int networkId;
if (savedNetworks.TryGetValue(ap.Ssid, out networkId))
{
savedNetworks.Remove(ap.Ssid);
_wifiManager.EnableNetwork(networkId, false);
}
}
}
_wifiScanWakeLock.Release();
}