news 2026/2/12 12:39:13

移动端app获取wifi步骤 用的uni

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
移动端app获取wifi步骤 用的uni

1manifest.json配置权限

说明:

  • WiFi:启用uni.startWifi / uni.getWifiList / uni.onGetWifiList等 API

  • GeolocationWi-Fi 扫描在 Android 8+ 必须依赖定位模块

✅ 这是正确且必须的配置
⚠️ 没有Geolocation,Wi-Fi 列表在真机上会直接返回空

2UniApp 权限弹窗描述(Android 13+ 必须)

"permissions": { "Location": { "desc": "应用需要访问位置信息" }, "NearbyWiFiDevices": { "desc": "应用需要扫描附近 Wi-Fi 设备" }, "AccessNetworkState": { "desc": "应用需要访问网络状态" }, "ChangeNetworkState": { "desc": "应用需要更改网络状态" }, "ChangeWiFiState": { "desc": "应用需要更改 Wi-Fi 状态" } }

说明:

  • 这些desc是:

    • Android 12+ / 13+弹窗文案来源

  • 没有desc

    • 打包正常

    • 真机运行 →权限请求失败 / 静默拒绝

你这里是完整且合规的

3Android 权限声明(Manifest 层)

"distribute": { "android": { /* android打包配置 */ "permissions": [ "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>", "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>", "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>", "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>", "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>", "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>", "<uses-permission android:name=\"android.permission.NEARBY_WIFI_DEVICES\"/>" ] } }
下面是我的完整配置
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>", "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>", "<uses-permission android:name=\"android.permission.VIBRATE\"/>", "<uses-permission android:name=\"android.permission.READ_LOGS\"/>", "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>", "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>", "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>", "<uses-permission android:name=\"android.permission.CAMERA\"/>", "<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>", "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>", "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>", "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>", "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>", "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>", "<uses-feature android:name=\"android.hardware.camera\"/>", "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>", "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>", "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>", "<uses-permission android:name=\"android.permission.NEARBY_WIFI_DEVICES\"/>" //Android 13+ 必须 ]

vue业务代码

html

<template> <view class="wifi-wrapper"> <view class="wifi-container"> <!-- 顶部当前连接信息 --> <view class="title">当前连接</view> <view class="current-connection"> <text class="wifi-info"> <image src="/static/icons/WiFiok.svg" class="icon" /> {{ currentWifi.SSID || '未连接' }} </text> <text class="connection-status" v-if="currentWifi.SSID">已连接</text> <text class="connection-status" v-else>未连接</text> </view> <!-- Tab 切换 --> <view class="tab-container"> <text class="tab-item" :style="{ color: activeTab === 'available' ? '#fff' : '#888' }" @click="switchTab('available')"> 本地可连接WiFi </text> <text class="tab-item" :style="{ color: activeTab === 'history' ? '#fff' : '#888' }" @click="switchTab('history')"> 历史连接WiFi </text> </view> <!-- WiFi 列表 --> <scroll-view class="wifi-list" scroll-y="true"> <view v-for="(wifi, index) in displayedWifiList" :key="index" class="wifi-item"> <view class="wifi-left"> <image :src="getSignalIcon(typeof wifi.signal === 'number' ? wifi.signal : signalToPercent(wifi.signal))" class="signal-icon" /> <text class="wifi-name">{{ wifi.SSID }}</text> </view> <text class="connect-btn" :style="{ color: activeTab === 'available' ? '#4e9dc2' : '#888' }" @click="connectToWifi(wifi)"> {{ activeTab === 'available' ? '立即连接' : '连接' }} </text> </view> </scroll-view> <!-- 底部按钮 --> <view class="button-container"> <button class="back-btn" @click="goBack">返回</button> <button class="next-btn" @click="goToNext">下一步</button> </view> </view> <view class="side"></view> <!-- 弹窗组件 --> <uni-popup ref="isModalVisible" @close="closeModal"> <view class="popupContent"> <view class="top"> <view>连接网络</view> <uni-icons type="closeempty" size="18" color="#fff" @click="closeModal"></uni-icons> </view> <view class="popcontent"> <view class="title"> 请输入 <text class="colortitle">{{ wifiInfo }}</text>的密码 </view> <view class="popinpbox"> <uni-easyinput v-model="passwordvalue" type="password" :clearable="false" passwordIcon placeholder="请输入密码" /> </view> </view> <view class="foolter"> <view class="cancel" @click="closeModal">取消</view> <view class="confirm" @click="handleConfirm">连接</view> </view> </view> </uni-popup> </view> </template>

<script setup>

<script setup> import { ref, computed, onMounted } from 'vue' // ---------- 响应式变量 ---------- const isModalVisible = ref(false) const useinfo = ref({}) const wifi = ref({}) const wifiInfo = ref('') const passwordvalue = ref('') const activeTab = ref('available') const currentWifi = ref({ SSID: '' }) const wifiList = ref([]) const historyWifiList = ref([]) const selectedWifi = ref({}) // ---------- 信号强度辅助 ---------- const getSignalIcon = (signal) => { if (!signal && signal !== 0) return '/static/icons/wifi4.svg' if (signal <= 25) return '/static/icons/wifi3.svg' if (signal <= 50) return '/static/icons/wifi2.svg' if (signal <= 75) return '/static/icons/wifi1.svg' return '/static/icons/wifi3.svg' } // ---------- 显示列表 ---------- const displayedWifiList = computed(() => { return activeTab.value === 'available' ? wifiList.value : historyWifiList.value }) // ---------- Tab 切换 ---------- const switchTab = (tab) => { activeTab.value = tab if (tab === 'history') loadHistoryWifi() } // ---------- 历史 Wi-Fi ---------- const saveHistoryWifi = (wifi) => { let history = uni.getStorageSync('historyWifi') || [] const existIndex = history.findIndex(item => item.SSID === wifi.SSID) if (existIndex >= 0) history.splice(existIndex, 1) history.unshift(wifi) if (history.length > 20) history = history.slice(0, 20) uni.setStorageSync('historyWifi', history) } const loadHistoryWifi = () => { historyWifiList.value = uni.getStorageSync('historyWifi') || [] } // ---------- 连接 Wi-Fi ---------- const connectToWifi = (wifiObj) => { selectedWifi.value = wifiObj wifiInfo.value = wifiObj.SSID || '' if (!wifiInfo.value) return isModalVisible.value.open() } const closeModal = () => { isModalVisible.value.close() passwordvalue.value = '' } const handleConfirm = () => { console.log(333333333); if (!passwordvalue.value) { uni.showToast({ title: '请输入密码', icon: 'none' }) return } uni.showLoading({ title: '连接中...' }) uni.connectWifi({ SSID: selectedWifi.value.SSID, password: passwordvalue.value, // 只传密码 success: () => { uni.hideLoading() uni.showToast({ title: `已连接 ${selectedWifi.value.SSID}`, icon: 'success' }) saveHistoryWifi(selectedWifi.value) currentWifi.value = selectedWifi.value closeModal() }, fail: (err) => { uni.hideLoading() uni.showToast({ title: '连接失败,请检查密码', icon: 'none' }) console.error('连接 Wi-Fi 失败', err) } }) } // ---------- 页面跳转和登录 ---------- const goBack = () => uni.navigateTo({ url: '/pages/login/index' }) const goToNext = () => { useinfo.value.userWifiSsid = currentWifi.value.SSID useinfo.value.userEquipmentNumber = useinfo.value.userName uni.setStorageSync('useinfo', useinfo.value) const wifiInfoStr = encodeURIComponent(JSON.stringify(currentWifi.value)) uni.navigateTo({ url: `/sub-device/user/index?wifiInfo=${wifiInfoStr}` }) } // ---------- 初始化 Wi-Fi 插件 ---------- const initWifiPlugin = () => { // Android App-plus 原生获取位置权限 // Android App-plus 原生动态申请 Wi-Fi 所需权限 if (plus && plus.os.name === 'Android') { const main = plus.android.runtimeMainActivity() const PackageManager = plus.android.importClass('android.content.pm.PackageManager') const permission = plus.android.importClass('android.Manifest$permission') const ActivityCompat = plus.android.importClass('androidx.core.app.ActivityCompat') // 需要申请的权限列表 const permissions = [ permission.ACCESS_FINE_LOCATION, permission.ACCESS_COARSE_LOCATION, permission.ACCESS_WIFI_STATE, permission.CHANGE_WIFI_STATE, permission.INTERNET, permission.ACCESS_NETWORK_STATE ] // 检查哪些权限未被授予 const needRequest = permissions.filter(p => plus.android.invoke(main, 'checkSelfPermission', p) !== PackageManager.PERMISSION_GRANTED ) if (needRequest.length > 0) { ActivityCompat.requestPermissions(main, needRequest, 0) console.log('请求 Wi-Fi 相关权限中...') return } } uni.getLocation({ type: 'wgs84', success() { // 初始化 Wi-Fi startWifiScan() }, fail() { uni.showModal({ title: '提示', content: '请开启手机定位服务,否则无法扫描 Wi-Fi', showCancel: false }) } }) // 获取当前已连接 Wi-Fi uni.getConnectedWifi({ success(res) { currentWifi.value = res.wifi }, fail(err) { uni.showToast({ title: '获取当前连接 Wi-Fi失败', icon: 'none' }) console.error('获取当前连接 Wi-Fi失败', err) } }) // uni.startWifi({ // success() { // console.log('Wi-Fi 初始化成功') // // 获取当前已连接 Wi-Fi // uni.getConnectedWifi({ // success(res) { // currentWifi.value = res.wifi // }, // fail(err) { // console.error('获取当前连接 Wi-Fi失败', err) // uni.showToast({ title: '获取当前连接 Wi-Fi失败', icon: 'none' }) // } // }) // // 扫描 Wi-Fi // uni.onGetWifiList(res => { // console.log('扫描到 Wi-Fi 列表', res.wifiList) // wifiList.value = res.wifiList.map(item => ({ // SSID: item.SSID, // BSSID: item.BSSID, // signal: item.signalStrength || item.signal, // capabilities: item.security // })) // }) // // ⚠️ 必须传一个空对象 {} 避免 NullPointerException // uni.getWifiList({}) // }, // fail(err) { // console.error('Wi-Fi 初始化失败', err) // } // }) } // 抽离 Wi-Fi 扫描逻辑 const startWifiScan = () => { uni.startWifi({ success() { console.log('Wi-Fi 初始化成功') uni.getConnectedWifi({ success(res) { currentWifi.value = res.wifi }, fail(err) { console.error('获取当前连接 Wi-Fi失败', err) uni.showToast({ title: '获取当前 Wi-Fi 失败', icon: 'none' }) } }) uni.onGetWifiList(res => { console.log('扫描到 Wi-Fi 列表', res.wifiList) wifiList.value = res.wifiList.map(item => ({ SSID: item.SSID, BSSID: item.BSSID, signal: item.signalStrength || item.signal, capabilities: item.security })) }) uni.getWifiList({}) }, fail(err) { console.error('Wi-Fi 初始化失败', err) uni.showToast({ title: 'Wi-Fi 初始化失败,请检查权限', icon: 'none' }) } }) } // ---------- 页面初始化 ---------- onMounted(() => { useinfo.value = uni.getStorageSync('useinfo') || {} setTimeout(() => { initWifiPlugin() }, 600); loadHistoryWifi() }) </script>
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/5 13:49:20

Linux系统下Miniconda-Python3.9安装PyTorch避坑大全

Linux系统下Miniconda-Python3.9安装PyTorch避坑大全 在深度学习项目中&#xff0c;环境配置常常比写模型代码更让人头疼。你是否遇到过这样的场景&#xff1a;好不容易跑通了一个开源项目&#xff0c;结果换一台机器就报错 ModuleNotFoundError: No module named torch&#…

作者头像 李华
网站建设 2026/2/6 4:24:35

把消息变成可运维资产:SAP Application Log 方法论与 BAL 全链路实战

在 ABAP 开发里,MESSAGE 当然好用:屏幕上立刻弹出报错,用户也能马上感知问题。但一旦场景从 对话框报错 走向 批处理作业、接口集成、异步队列、后台校验,单次弹窗就不够了——你需要的是一套能收集、持久化、检索、展示、归档的日志体系,让业务用户、运维同事、开发人员都…

作者头像 李华
网站建设 2026/2/6 21:08:35

小白逆袭!一文搞定Qwen3医学模型微调,DeepSeek式推理不再是专利!

Qwen3是阿里通义实验室最近开源的大语言模型&#xff0c;发布时便登顶了开源LLM榜单第一名。同时&#xff0c;Qwen系列模型也超越LLaMA&#xff0c;成为了开源模型社区中最受欢迎的开源LLM。 可以说&#xff0c;不论是进行研究学习&#xff0c;还是应用落地&#xff0c;Qwen已…

作者头像 李华
网站建设 2026/2/6 20:50:58

Miniconda-Python3.9环境下运行Stable Diffusion PyTorch代码

在 Miniconda-Python3.9 环境中高效运行 Stable Diffusion 的完整实践 你有没有遇到过这样的情况&#xff1a;从 GitHub 上克隆了一个热门的 Stable Diffusion 项目&#xff0c;满怀期待地执行 pip install -r requirements.txt&#xff0c;结果却卡在 PyTorch 安装环节&#x…

作者头像 李华