logo头像
Snippet 博客主题

android demo wifi

本文于536天之前发表,文中内容可能已经过时。

android wifi 自动连接

连接方式

无密码连接

  1. mWifiManager.disconnect();
  2. 其他网络 enableNetwork
  3. 创建网络 mWifiManager 中添加网络
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public boolean connectSpecificAP(ScanResult scan) {
List<WifiConfiguration> list = mWifiManager.getConfiguredNetworks();
boolean networkInSupplicant = false;
boolean connectResult = false;
// 重新连接指定AP
mWifiManager.disconnect();
for (WifiConfiguration w : list) {
// 将指定AP 名字转化
// String str = convertToQuotedString(info.ssid);
if (w.BSSID != null && w.BSSID.equals(scan.BSSID)) {
connectResult = mWifiManager.enableNetwork(w.networkId, true);
// mWifiManager.saveConfiguration();
networkInSupplicant = true;
break;
}
}
if (!networkInSupplicant) {
WifiConfiguration config = CreateWifiInfo(scan, "");
connectResult = addNetwork(config);
}

return connectResult;
}

创建网络

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 然后是一个实际应用方法,只验证过没有密码的情况:
public WifiConfiguration CreateWifiInfo(ScanResult scan, String Password) {
WifiConfiguration config = new WifiConfiguration();
config.hiddenSSID = false;
config.status = WifiConfiguration.Status.ENABLED;

if (scan.capabilities.contains("WEP")) {
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
config.allowedAuthAlgorithms
.set(WifiConfiguration.AuthAlgorithm.OPEN);
config.allowedGroupCiphers
.set(WifiConfiguration.GroupCipher.WEP104);

config.SSID = "\"" + scan.SSID + "\"";

config.wepTxKeyIndex = 0;
config.wepKeys[0] = Password;
// config.preSharedKey = "\"" + SHARED_KEY + "\"";
} else if (scan.capabilities.contains("PSK")) {
//
config.SSID = "\"" + scan.SSID + "\"";
config.preSharedKey = "\"" + Password + "\"";
} else if (scan.capabilities.contains("EAP")) {
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
config.allowedAuthAlgorithms
.set(WifiConfiguration.AuthAlgorithm.OPEN);
config.allowedPairwiseCiphers
.set(WifiConfiguration.PairwiseCipher.TKIP);
config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
config.SSID = "\"" + scan.SSID + "\"";
config.preSharedKey = "\"" + Password + "\"";
} else {
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);

config.SSID = "\"" + scan.SSID + "\"";
// config.BSSID = info.mac;
config.preSharedKey = null;
//
}

return config;
}

添加到网络

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 添加到网络
*
* @author Xiho
* @param wcg
*/
public boolean addNetwork(WifiConfiguration wcg) {
if (wcg == null) {
return false;
}
// receiverDhcp = new ReceiverDhcp(ctx, mWifiManager, this,
// wlanHandler);
// ctx.registerReceiver(receiverDhcp, new
// IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION));
int wcgID = mWifiManager.addNetwork(wcg);
boolean b = mWifiManager.enableNetwork(wcgID, true);
mWifiManager.saveConfiguration();
System.out.println(b);
return b;
}

有密码连接

  1. 在wifi列表中获取 加密方式scanResult.capabilities
  2. 创建 WifiConfiguration
  3. 添加到 WifiManager
  4. WifiManager断开连接
    WifiManager.disconnect()
  5. WifiManager 其他的连接断开WifiManager.enableNetwork(netID, true)
  6. WifiManager 重新连接
    WifiManager.reconnect()

code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
* 给外部提供一个借口,连接无线网络
*
* @param SSID
* @param Password
* @param Type
* @return <br>
* @return true:连接成功;false:连接失败<br>
*
*/
public boolean connect(String SSID, String Password, WifiConnectUtils.WifiCipherType Type) {
if (!this.openWifi()) {
return false;
}
// 状态变成WIFI_STATE_ENABLED的时候才能执行下面的语句
while (mWifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLING) {
try {
// 为了避免程序一直while循环,让它睡个100毫秒在检测……
Thread.currentThread();
Thread.sleep(100);
} catch (InterruptedException ie) {
}
}
if (SSID == null || Password == null || SSID.equals("")) {
Log.e(this.getClass().getName(),
"addNetwork() ## nullpointer error!");
return false;
}
WifiConfiguration wifiConfig = createWifiInfo(SSID, Password, Type);
// wifi的配置信息
if (wifiConfig == null) {
return false;
}
// 查看以前是否也配置过这个网络
WifiConfiguration tempConfig = this.isExsits(SSID);
if (tempConfig != null) {

mWifiManager.removeNetwork(tempConfig.networkId);
}
// 添加一个新的网络描述为一组配置的网络。
int netID = mWifiManager.addNetwork(wifiConfig);
Log.d("WifiListActivity", "wifi的netID为:" + netID);
// 断开连接
mWifiManager.disconnect();
// 重新连接
Log.d("WifiListActivity", "Wifi的重新连接netID为:" + netID);
// 设置为true,使其他的连接断开
boolean mConnectConfig = mWifiManager.enableNetwork(netID, true);
mWifiManager.reconnect();
return mConnectConfig;
}

网上大多数demo 都是这样子的

兼容性问题

系统 手机型号 无密码连接 密码连接
4.4.2 华为p6-06 YES YES
4.4.4 酷派 YES YES
5.1.0 moto XT YES YES
7.1.1 android 原生系统 Moto G Play NO (wifi 会断开 后重新连接 之前的wifi 并非指定的) NO (wifi 会断开 后重新连接 之前的wifi 并非指定的)
8.0.0 华为mate 9 NO (wifi 会断开 后重新连接 之前的wifi 并非指定的) NO (wifi 会断开 后重新连接 之前的wifi 并非指定的)

原因分析

android 4.4.4

android 源码
http://androidxref.com/4.4.4_r1/xref/packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java

575行 onContextItemSelected(MenuItem item)
该方法中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
574  @Override
575 public boolean onContextItemSelected(MenuItem item) {
576 if (mSelectedAccessPoint == null) {
577 return super.onContextItemSelected(item);
578 }
579 switch (item.getItemId()) {
580 case MENU_ID_CONNECT: {
581 if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
582 mWifiManager.connect(mSelectedAccessPoint.networkId,
583 mConnectListener);
584 } else if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE) {
585 /** Bypass dialog for unsecured networks */
586 mSelectedAccessPoint.generateOpenNetworkConfig();
587 mWifiManager.connect(mSelectedAccessPoint.getConfig(),
588 mConnectListener);
589 } else {
590 showDialog(mSelectedAccessPoint, true);
591 }
592 return true;
593 }
594 case MENU_ID_FORGET: {
595 mWifiManager.forget(mSelectedAccessPoint.networkId, mForgetListener);
596 return true;
597 }
598 case MENU_ID_MODIFY: {
599 showDialog(mSelectedAccessPoint, true);
600 return true;
601 }
602 }
603 return super.onContextItemSelected(item);
604 }

580 点击链接
无密码

1
2
3
586                    mSelectedAccessPoint.generateOpenNetworkConfig();
587 mWifiManager.connect(mSelectedAccessPoint.getConfig(),
588 mConnectListener);

具体分析
mSelectedAccessPoint.generateOpenNetworkConfig();

1
2
3
4
5
6
7
8
9
390    protected void generateOpenNetworkConfig() {
391 if (security != SECURITY_NONE)
392 throw new IllegalStateException();
393 if (mConfig != null)
394 return;
395 mConfig = new WifiConfiguration();
396 mConfig.SSID = AccessPoint.convertToQuotedString(ssid);
397 mConfig.allowedKeyManagement.set(KeyMgmt.NONE);
398 }

mSelectedAccessPoint.getConfig()

1
2
3
312    WifiConfiguration getConfig() {
313 return mConfig;
314 }

mSelectedAccessPoint 的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
553    @Override
554 public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) {
555 if (info instanceof AdapterContextMenuInfo) {
556 Preference preference = (Preference) getListView().getItemAtPosition(
557 ((AdapterContextMenuInfo) info).position);
558
559 if (preference instanceof AccessPoint) {
560 mSelectedAccessPoint = (AccessPoint) preference;
561 menu.setHeaderTitle(mSelectedAccessPoint.ssid);
562 if (mSelectedAccessPoint.getLevel() != -1
563 && mSelectedAccessPoint.getState() == null) {
564 menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect);
565 }
566 if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
567 menu.add(Menu.NONE, MENU_ID_FORGET, 0, R.string.wifi_menu_forget);
568 menu.add(Menu.NONE, MENU_ID_MODIFY, 0, R.string.wifi_menu_modify);
569 }
570 }
571 }
572 }

mWifiManager.connect(mSelectedAccessPoint.getConfig(),mConnectListener);
分析WifiManager

1
2
3
4
5
6
7
8
1586    public void connect(WifiConfiguration config, ActionListener listener) {
1587 if (config == null) throw new IllegalArgumentException("config cannot be null");
1588 validateChannel();
1589 // Use INVALID_NETWORK_ID for arg1 when passing a config object
1590 // arg1 is used to pass network id when the network already exists
1591 sAsyncChannel.sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,
1592 putListener(listener), config);
1593 }

7.1.1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
477    @Override
478 public boolean onContextItemSelected(MenuItem item) {
479 if (mSelectedAccessPoint == null) {
480 return super.onContextItemSelected(item);
481 }
482 switch (item.getItemId()) {
483 case MENU_ID_CONNECT: {
484 if (mSelectedAccessPoint.isSaved()) {
485 connect(mSelectedAccessPoint.getConfig());
486 } else if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) {
487 /** Bypass dialog for unsecured networks */
488 mSelectedAccessPoint.generateOpenNetworkConfig();
489 connect(mSelectedAccessPoint.getConfig());
490 } else {
491 showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_CONNECT);
492 }
493 return true;
494 }
495 case MENU_ID_FORGET: {
496 forget();
497 return true;
498 }
499 case MENU_ID_MODIFY: {
500 showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_MODIFY);
501 return true;
502 }
503 case MENU_ID_WRITE_NFC:
504 showDialog(WRITE_NFC_DIALOG_ID);
505 return true;
506
507 }
508 return super.onContextItemSelected(item);
509 }
1
2
3
4
853    protected void connect(final WifiConfiguration config) {
854 MetricsLogger.action(getActivity(), MetricsEvent.ACTION_WIFI_CONNECT);
855 mWifiManager.connect(config, mConnectListener);
856 }

相对 4.4.4 引入
MetricsLogger.action(getActivity(), MetricsEvent.ACTION_WIFI_CONNECT);

http://androidxref.com/7.1.1_r6/xref/frameworks/base/core/java/com/android/internal/logging/MetricsLogger.java

1
2
3
62    public static void action(Context context, int category) {
63 action(context, category, "");
64 }
1
2
3
4
5
6
74    public static void action(Context context, int category, String pkg) {
75 if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
76 throw new IllegalArgumentException("Must define metric category");
77 }
78 EventLogTags.writeSysuiAction(category, pkg);
79 }
1
EventLogTags.writeSysuiAction(category, pkg);

8.0.0 8.0.0_r4

http://androidxref.com/8.0.0_r4/xref/packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
509    @Override
510 public boolean onContextItemSelected(MenuItem item) {
511 if (mSelectedAccessPoint == null) {
512 return super.onContextItemSelected(item);
513 }
514 switch (item.getItemId()) {
515 case MENU_ID_CONNECT: {
516 boolean isSavedNetwork = mSelectedAccessPoint.isSaved();
517 if (isSavedNetwork) {
518 connect(mSelectedAccessPoint.getConfig(), isSavedNetwork);
519 } else if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) {
520 /** Bypass dialog for unsecured networks */
521 mSelectedAccessPoint.generateOpenNetworkConfig();
522 connect(mSelectedAccessPoint.getConfig(), isSavedNetwork);
523 } else {
524 showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_CONNECT);
525 }
526 return true;
527 }
528 case MENU_ID_FORGET: {
529 forget();
530 return true;
531 }
532 case MENU_ID_MODIFY: {
533 showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_MODIFY);
534 return true;
535 }
536 case MENU_ID_WRITE_NFC:
537 showDialog(WRITE_NFC_DIALOG_ID);
538 return true;
539
540 }
541 return super.onContextItemSelected(item);
542 }
1
2
3
4
5
6
1003    protected void connect(final WifiConfiguration config, boolean isSavedNetwork) {
1004 // Log subtype if configuration is a saved network.
1005 mMetricsFeatureProvider.action(getActivity(), MetricsEvent.ACTION_WIFI_CONNECT,
1006 isSavedNetwork);
1007 mWifiManager.connect(config, mConnectListener);
1008 }

android 8.0 这里 又做了修改

http://androidxref.com/8.0.0_r4/xref/packages/apps/Settings/src/com/android/settings/core/instrumentation/MetricsFeatureProvider.java

1
2
3
4
5
63    public void action(Context context, int category, Pair<Integer, Object>... taggedData) {
64 for (LogWriter writer : mLoggerWriters) {
65 writer.action(context, category, taggedData);
66 }
67 }

1
2
3
4
5
6
7
8
9
10
11
12

33 private List<LogWriter> mLoggerWriters;
34
35 public MetricsFeatureProvider() {
36 mLoggerWriters = new ArrayList<>();
37 installLogWriters();
38 }
39
40 protected void installLogWriters() {
41 mLoggerWriters.add(new EventLogWriter());
42 mLoggerWriters.add(new SettingSuggestionsLogWriter());
43 }

主要是 EventLogWriter SettingSuggestionsLogWriter

http://androidxref.com/8.0.0_r4/xref/packages/apps/Settings/src/com/android/settings/core/instrumentation/EventLogWriter.java

EventLogWriter 中 MetricsLogger

以上分析 只能指定 android 系统API 更改了 不能找到相应的 解决方法

换条路吧

从代码上看

1
wifiManager.addNetwork返回-1

应该是失败原因

纠结好几个小时 发现
在设置中忘记配置 连接是成功的

原因分析

android M 连接无 Internet 会提示 是否自动切换
一旦自动切换 那就记录下来了

下次 自动连接 就连接不了 检测网络又问题 就自动切换了

解决版本

自动连接前 删除配置信息

应该在自动连接前 添加 忘记配置就可以了

  1. 系统 忘记配置 系统的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* Delete the network in the supplicant config.
*
* This function is used instead of a sequence of removeNetwork()
* and saveConfiguration().
*
* @param config the set of variables that describe the configuration,
* contained in a {@link WifiConfiguration} object.
* @param listener for callbacks on success or failure. Can be null.
* @throws IllegalStateException if the WifiManager instance needs to be
* initialized again
* @hide
*/
public void forget(int netId, ActionListener listener) {
if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
validateChannel();
sAsyncChannel.sendMessage(FORGET_NETWORK, netId, putListener(listener));
}

hide 不能使用啊

反射吧 android 9.0 禁止了 放弃反射

好吧 放弃

removeNetwork() 试试 发现 不行啊

  1. 让系统 不检测 是否有可以用的 Internet

https://blog.csdn.net/u010042260/article/details/52931489

frameworks/base/services/core/java/com/android/server/connectivity/NetworkMonitor.java
修改:mIsCaptivePortalCheckEnabled = false;即可。

isCaptivePortal() 这个方法真的 在检测了

修改 mIsCaptivePortalCheckEnabled 没有方法 不能反射

通过命令 修改 不需要 root

https://android.stackexchange.com/questions/100657/how-to-disable-captive-portal-detection-how-to-remove-exclamation-mark-on-wi-fi

https://support.honeywellaidc.com/s/article/What-does-limited-or-no-Internet-Access-mean

修改了 但是 连接 无可用的 Internet
还是提示了

但是 可以连接上了

https://android.stackexchange.com/questions/100657/how-to-disable-captive-portal-detection-how-to-remove-exclamation-mark-on-wi-fi

settings put global captive_portal_detection_enabled 1
刚刚开始 没用
重启后 可以连接上了

不太确定 是不是 这个原因
还是重启 系统导致的

恢复之前的值
settings put global captive_portal_detection_enabled null
之后 现在无法复现了
问题 待更近

支付宝打赏 微信打赏

打赏