如何在NativeScript中自动切换同SSID多BSSID的最强WiFi接入点?
解决WiFi自动切换同SSID最强接入点的问题
我仔细看了你的代码和问题描述,发现几个核心问题导致程序无法触发切换到更强的接入点,下面是诊断和修复方案:
问题根源分析
- ScanResult的networkId无效:你从
scanResults.get(n).networkId获取的ID是没用的——Android的ScanResult对象里的networkId是预留字段,实际值通常为-1,根本不是系统中已配置WiFi的有效网络ID,这直接导致后续的updateNetwork和enableNetwork操作完全失效。 - 未正确断开当前连接:切换时没有先禁用当前的WiFi连接,直接调用
enableNetwork无法强制系统切换接入点。 - WiFi配置逻辑错误:你直接用扫描结果构建
WifiConfiguration,但正确的做法应该是先找到系统中已配置的同SSID网络,再修改其目标BSSID,这样才能让系统识别要切换的接入点。 - 扫描结果判断逻辑错误:
startScan()返回的是“扫描是否发起成功”,不是“扫描结果是否可用”,你用它来判断是否处理结果会漏掉很多有效扫描数据。
修复后的完整代码
import { Injectable, NgZone } from '@angular/core'; import * as applicationModule from 'tns-core-modules/application'; import * as utils from 'tns-core-modules/utils/utils'; import { config } from '../data/config'; import { WifiCon } from '../interfaces/wifi-con'; import { LoggerService } from './logger.service'; declare var android: any; @Injectable({ providedIn: 'root' }) export class WifiConService implements WifiCon { readonly ssid: string = config.SSID; readonly password: string = '12345678'; private currentConnectedBSSID = ''; private readonly wifiManager: any; private readonly items: Array<Item> = new Array<Item>(); constructor(private readonly zone: NgZone, private readonly logger: LoggerService) { this.wifiManager = utils.ad.getApplicationContext() .getSystemService(android.content.Context.WIFI_SERVICE); this.monitorBSSID(); this.logger.log('Created service for wifi'); } // 初始化或获取已配置的WiFi网络 private getOrCreateConfiguredNetwork(): android.net.wifi.WifiConfiguration | null { const configuredNetworks = this.wifiManager.getConfiguredNetworks(); if (!configuredNetworks) return null; // 查找已配置的同SSID网络 for (let i = 0; i < configuredNetworks.size(); i++) { const network = configuredNetworks.get(i); if (network.SSID === `"${this.ssid}"`) { return network; } } // 如果没有配置过,创建新的配置 const conf = new android.net.wifi.WifiConfiguration(); conf.SSID = `"${this.ssid}"`; conf.preSharedKey = `"${this.password}"`; const netId = this.wifiManager.addNetwork(conf); this.wifiManager.saveConfiguration(); return this.wifiManager.getConfiguredNetworks().find(net => net.networkId === netId); } connectWiFiNetwork(): void { if (this.items.length === 0) { this.logger.log('No available access points for target SSID'); return; } // 按信号强度降序排序 this.items.sort((a, b) => b.strength - a.strength); const strongestAP = this.items[0]; // 如果当前已经连接到最强AP,无需切换 if (strongestAP.bssid === this.currentConnectedBSSID) { this.logger.log(`Already connected to strongest AP: ${strongestAP.bssid}`); return; } this.logger.log(`Switching to stronger AP: ${strongestAP.bssid} (strength: ${strongestAP.strength})`); // 获取已配置的网络 const configuredNetwork = this.getOrCreateConfiguredNetwork(); if (!configuredNetwork) { this.logger.log('Failed to get or create configured network'); return; } // 修改配置,指定要连接的BSSID configuredNetwork.BSSID = strongestAP.bssid; const updatedNetId = this.wifiManager.updateNetwork(configuredNetwork); this.wifiManager.saveConfiguration(); // 先断开当前连接 this.wifiManager.disconnect(); // 启用目标网络并重新连接 const isEnabled = this.wifiManager.enableNetwork(updatedNetId, true); const isReconnected = this.wifiManager.reconnect(); this.logger.log(`Switch result: enableNetwork=${isEnabled}, reconnect=${isReconnected}`); this.currentConnectedBSSID = strongestAP.bssid; } disConnectWifi(): boolean { this.logger.log(`WiFi disconnected from "${this.ssid}"`); this.currentConnectedBSSID = ''; return this.wifiManager.setWifiEnabled(false); } getConSubject(): boolean { return true; } switchToStrongNtwk(BSSID: string): boolean { return true; } getNtwkInfo(): any { return this.wifiManager.getConnectionInfo(); } isWifiEnabled(): boolean { return this.wifiManager.isWifiEnabled(); } monitorBSSID(): void { const receiverCallback = (androidContext, intent) => { // 检查扫描结果是否可用 if (!intent.getBooleanExtra(android.net.wifi.WifiManager.EXTRA_RESULTS_UPDATED, false)) { this.logger.log('Scan results not updated'); return; } this.zone.run(() => { this.items.length = 0; const scanResults = this.wifiManager.getScanResults(); const currentConnectionInfo = this.getNtwkInfo(); this.currentConnectedBSSID = currentConnectionInfo.getBSSID() || ''; for (let n = 0; n < scanResults.size(); n++) { const result = scanResults.get(n); if (result.SSID === this.ssid) { this.items.push({ ssid: result.SSID, bssid: result.BSSID, strength: result.level, isConnected: (result.BSSID === this.currentConnectedBSSID), // ScanResult的networkId无效,这里不再使用 netId: -1 }); } } this.logger.log(`Available APs: ${JSON.stringify(this.items)}`); this.connectWiFiNetwork(); }); }; applicationModule.android.registerBroadcastReceiver( android.net.wifi.WifiManager.SCAN_RESULTS_AVAILABLE_ACTION, receiverCallback ); setInterval(() => { this.logger.log('Initiating WiFi scan'); // startScan返回的是扫描是否发起,不是结果是否可用 const scanInitiated = this.wifiManager.startScan(); this.logger.log(`Scan initiated: ${scanInitiated}`); }, config.wifi_scan_time * 1000); } } interface Item { ssid: string; bssid: string; strength: number; isConnected: boolean; netId: number; }
关键修改点说明
- 修复无效networkId问题:移除了从
ScanResult获取networkId的逻辑,改用getOrCreateConfiguredNetwork()方法获取系统中已配置的同SSID网络ID,这个ID才是真正有效的。 - 正确处理扫描结果:在广播接收器中使用
EXTRA_RESULTS_UPDATED来判断扫描结果是否更新,不再依赖startScan()的返回值。 - 强制断开并切换:切换前先调用
disconnect()断开当前连接,再启用目标网络并调用reconnect(),确保系统强制切换到指定的BSSID。 - 优化配置更新逻辑:先查找已有的配置,避免重复创建;更新配置后调用
saveConfiguration()确保修改生效。 - 增加状态判断:切换前检查是否已经连接到最强AP,避免不必要的切换操作,减少资源消耗。
这样修改后,你的程序应该能正确识别最强信号的接入点,并自动触发切换了。
内容的提问来源于stack exchange,提问作者Gayatri Kadam
相关产品推荐
相关产品推荐

