From 5f848e6c78368c5f01f731c8ff7095f5ccadf317 Mon Sep 17 00:00:00 2001
From: Ironsp <1522278303@qq.com>
Date: Mon, 14 Sep 2026 10:42:40 +0800
Subject: [PATCH] =?UTF-8?q?feat=20=E9=85=8D=E7=BD=AEWiFi=E6=A8=A1=E5=9D=97?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
manifest.config.ts | 1 +
src/components/settings/wifiNetwork.vue | 71 +++++++-
src/utils/wifi.ts | 217 +++++++++++++++++-------
3 files changed, 224 insertions(+), 65 deletions(-)
diff --git a/manifest.config.ts b/manifest.config.ts
index c8699b4..b07a012 100644
--- a/manifest.config.ts
+++ b/manifest.config.ts
@@ -39,6 +39,7 @@ export default defineManifestConfig({
'',
'',
'',
+ '',
'',
'',
'',
diff --git a/src/components/settings/wifiNetwork.vue b/src/components/settings/wifiNetwork.vue
index 84462ee..ce8e1f4 100644
--- a/src/components/settings/wifiNetwork.vue
+++ b/src/components/settings/wifiNetwork.vue
@@ -2,12 +2,16 @@
import wifi from '@/utils/wifi'
const wifiEnabled = ref(true)
+const scanning = ref(false)
-const networks = ref([
- { name: 'TP_LINK_5G', signal: '信号强度:强', ip: 'IP地址:192.168.1.100', connected: true },
- { name: 'TP_LINK_5G', signal: '信号强度:强', ip: 'IP地址:192.168.1.100', connected: false },
- { name: 'TP_LINK_5G', signal: '信号强度:强', ip: 'IP地址:192.168.1.100', connected: false },
-])
+interface NetworkItem {
+ name: string
+ signal: string
+ ip: string
+ connected: boolean
+}
+
+const networks = ref([])
function handleDisconnect(name: string) {
console.log('断开', name)
@@ -18,9 +22,35 @@ function handleConnect(name: string) {
}
async function handleRefreshWifi() {
+ if (scanning.value)
+ return
+
+ scanning.value = true
console.log('点击了搜索WiFi')
- const result = await wifi.scanWifi()
- console.log('扫描到的WiFi:', result)
+ try {
+ const result = await wifi.scanWifi()
+ console.log('扫描到的WiFi:', result)
+ const connected = await wifi.getConnectedWifi().catch(() => null)
+
+ networks.value = result.map(item => ({
+ name: item.SSID,
+ signal: `信号强度:${wifi.getSignalDescription(item.signalStrength)}`,
+ ip: connected?.SSID === item.SSID ? '已连接' : (wifi.is5GHz(item.frequency || 0) ? '5GHz' : '2.4GHz'),
+ connected: connected?.SSID === item.SSID,
+ }))
+
+ if (!result.length) {
+ uni.showToast({ title: '未发现可用网络', icon: 'none' })
+ }
+ }
+ catch (err) {
+ const message = err instanceof Error ? err.message : '扫描失败'
+ console.error('WiFi 扫描失败:', err)
+ uni.showToast({ title: message, icon: 'none', duration: 3000 })
+ }
+ finally {
+ scanning.value = false
+ }
}
@@ -50,7 +80,16 @@ async function handleRefreshWifi() {
可用网络
-
+
+
+
+ 点击右上角刷新扫描附近 WiFi
@@ -119,6 +158,22 @@ async function handleRefreshWifi() {
color: #999;
}
+.refresh-icon.spinning {
+ animation: spin 1s linear infinite;
+}
+
+@keyframes spin {
+ from { transform: rotate(0deg); }
+ to { transform: rotate(360deg); }
+}
+
+.empty-tip {
+ font-size: 14px;
+ color: #999;
+ padding: 12px 0;
+ text-align: center;
+}
+
.wifi-toggle {
display: flex;
justify-content: space-between;
diff --git a/src/utils/wifi.ts b/src/utils/wifi.ts
index 5c8323e..b6821f0 100644
--- a/src/utils/wifi.ts
+++ b/src/utils/wifi.ts
@@ -55,6 +55,9 @@
* - android.permission.ACCESS_WIFI_STATE
* - android.permission.CHANGE_WIFI_STATE
* - android.permission.ACCESS_NETWORK_STATE
+ * - android.permission.ACCESS_FINE_LOCATION
+ * - android.permission.ACCESS_COARSE_LOCATION
+ * - Android 6+ 还需运行时授予定位权限,且系统「位置信息」开关需开启
*/
// ======================== 类型定义 ========================
@@ -111,6 +114,90 @@ function importClass(name: string) {
return (plus.android as any).importClass(name)
}
+/** 读取 Java 对象字段(ScanResult.SSID 等是字段不是方法) */
+function getAttr(obj: any, name: string) {
+ try {
+ return (plus.android as any).getAttribute(obj, name)
+ }
+ catch {
+ return invoke(obj, name)
+ }
+}
+
+/** 申请定位权限(Android 扫描 WiFi 必需) */
+function requestLocationPermission(): Promise {
+ return new Promise((resolve) => {
+ try {
+ ;(plus.android as any).requestPermissions(
+ [
+ 'android.permission.ACCESS_FINE_LOCATION',
+ 'android.permission.ACCESS_COARSE_LOCATION',
+ ],
+ (result: { granted?: string[], deniedAlways?: string[], deniedPresent?: string[] }) => {
+ const granted = result?.granted || []
+ const ok = granted.includes('android.permission.ACCESS_FINE_LOCATION')
+ || granted.includes('android.permission.ACCESS_COARSE_LOCATION')
+ console.log('定位权限申请结果:', result)
+ resolve(ok)
+ },
+ (err: unknown) => {
+ console.error('定位权限申请失败:', err)
+ resolve(false)
+ },
+ )
+ }
+ catch (err) {
+ console.error('requestPermissions 不可用:', err)
+ resolve(false)
+ }
+ })
+}
+
+/** 系统定位开关是否开启 */
+function isLocationEnabled(): boolean {
+ try {
+ const LocationManager = importClass('android.location.LocationManager')
+ const Context = importClass('android.content.Context')
+ const activity = (plus.android as any).runtimeMainActivity()
+ const lm = activity.getSystemService(Context.LOCATION_SERVICE)
+ return !!(
+ invoke(lm, 'isProviderEnabled', LocationManager.GPS_PROVIDER)
+ || invoke(lm, 'isProviderEnabled', LocationManager.NETWORK_PROVIDER)
+ )
+ }
+ catch {
+ return true
+ }
+}
+
+/** 解析 getScanResults 列表 */
+function parseScanResults(wm: any): WifiInfo[] {
+ const results = invoke(wm, 'getScanResults')
+ if (!results)
+ return []
+
+ const size = invoke(results, 'size') || 0
+ const networks: WifiInfo[] = []
+
+ for (let i = 0; i < size; i++) {
+ const r = invoke(results, 'get', i)
+ const ssid = String(getAttr(r, 'SSID') || '').replace(/"/g, '')
+ if (!ssid || ssid === '')
+ continue
+
+ networks.push({
+ SSID: ssid,
+ BSSID: String(getAttr(r, 'BSSID') || ''),
+ signalStrength: Number(getAttr(r, 'level') || 0),
+ securityType: String(getAttr(r, 'capabilities') || ''),
+ frequency: Number(getAttr(r, 'frequency') || 0),
+ connected: false,
+ })
+ }
+
+ return networks
+}
+
// ======================== WiFi 工具 ========================
const wifi = {
@@ -157,74 +244,89 @@ const wifi = {
},
/** 扫描附近 WiFi 网络 */
- scanWifi(): Promise {
+ async scanWifi(): Promise {
+ const wm = getWifiManager()
+ const isEnabled = invoke(wm, 'isWifiEnabled')
+ console.log('WiFi 是否开启:', isEnabled)
+
+ if (!isEnabled)
+ throw new Error('请先开启 WiFi')
+
+ const hasPermission = await requestLocationPermission()
+ if (!hasPermission)
+ throw new Error('需要定位权限才能扫描 WiFi,请在系统设置中允许')
+
+ if (!isLocationEnabled())
+ throw new Error('请先打开系统「位置信息/定位」开关,否则无法扫描 WiFi')
+
return new Promise((resolve, reject) => {
- try {
- const wm = getWifiManager()
+ let settled = false
+ let receiver: any = null
+ let timer: ReturnType | undefined
+ const activity = (plus.android as any).runtimeMainActivity()
- // 检查 WiFi 是否开启
- const isEnabled = invoke(wm, 'isWifiEnabled')
- console.log('WiFi 是否开启:', isEnabled)
-
- if (!isEnabled) {
- console.warn('WiFi 未开启,返回模拟数据')
- // 模拟器或 WiFi 未开启时返回模拟数据
- resolve([
- { SSID: 'MOCK_WIFI_1', BSSID: 'AA:BB:CC:DD:EE:01', signalStrength: -45, frequency: 5180, connected: false },
- { SSID: 'MOCK_WIFI_2', BSSID: 'AA:BB:CC:DD:EE:02', signalStrength: -65, frequency: 2437, connected: false },
- { SSID: 'TestNetwork', BSSID: 'AA:BB:CC:DD:EE:03', signalStrength: -72, frequency: 2412, connected: false },
- ])
+ const finish = (networks: WifiInfo[], err?: Error) => {
+ if (settled)
return
+ settled = true
+ if (timer)
+ clearTimeout(timer)
+ try {
+ if (receiver)
+ activity.unregisterReceiver(receiver)
}
+ catch {}
+ if (err)
+ reject(err)
+ else
+ resolve(networks)
+ }
+
+ try {
+ const Filter = importClass('android.content.IntentFilter')
+ const Receiver = importClass('android.content.BroadcastReceiver')
+ const filter = new Filter()
+ filter.addAction('android.net.wifi.SCAN_RESULTS')
+
+ receiver = new Receiver({
+ onReceive(_ctx: any, intent: any) {
+ const updated = invoke(intent, 'getBooleanExtra', 'resultsUpdated', false)
+ console.log('收到 SCAN_RESULTS, resultsUpdated:', updated)
+ const networks = parseScanResults(wm)
+ console.log('解析后网络数量:', networks.length)
+ finish(networks)
+ },
+ })
+ activity.registerReceiver(receiver, filter)
- // 启动扫描
const started = invoke(wm, 'startScan')
console.log('WiFi 扫描启动:', started)
- // 等待 3 秒确保扫描完成
- setTimeout(() => {
- try {
- const results = invoke(wm, 'getScanResults')
- if (!results) {
- console.log('扫描结果为 null')
- resolve([])
- return
- }
-
- const size = invoke(results, 'size')
- console.log('扫描到网络数量:', size)
-
- const networks: WifiInfo[] = []
-
- for (let i = 0; i < size; i++) {
- const r = invoke(results, 'get', i)
- const ssid = (invoke(r, 'SSID') || '').replace(/"/g, '')
- if (!ssid || ssid === '')
- continue
-
- networks.push({
- SSID: ssid,
- BSSID: invoke(r, 'BSSID') || '',
- signalStrength: invoke(r, 'level') || 0,
- securityType: invoke(r, 'capabilities') || '',
- frequency: invoke(r, 'frequency') || 0,
- connected: false,
- })
- }
-
- console.log('解析后网络数量:', networks.length)
- resolve(networks)
+ // startScan 失败时仍尝试读取缓存结果(限流时常见)
+ if (!started) {
+ const cached = parseScanResults(wm)
+ console.log('startScan 失败,缓存网络数量:', cached.length)
+ if (cached.length > 0) {
+ finish(cached)
+ return
}
- catch (err) {
- console.error('获取扫描结果失败:', err)
- reject(err)
- }
- }, 3000)
+ finish([], new Error('WiFi 扫描被拒绝(可能被系统限流,请稍后再试)'))
+ return
+ }
}
catch (err) {
- console.error('扫描启动失败:', err)
- reject(err)
+ finish([], err instanceof Error ? err : new Error(String(err)))
+ return
}
+
+ timer = setTimeout(() => {
+ const networks = parseScanResults(wm)
+ console.log('扫描超时,当前网络数量:', networks.length)
+ if (networks.length > 0)
+ finish(networks)
+ else
+ finish([], new Error('扫描超时,未发现可用网络'))
+ }, 8000)
})
},
@@ -453,7 +555,8 @@ const wifi = {
const receiver = new Receiver({
onReceive() {
- wifi.scanWifi().then(callback)
+ const wm = getWifiManager()
+ callback(parseScanResults(wm))
},
})