news 2026/5/16 4:02:16

移动端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/5/2 4:03:05

Linux下Miniconda-Python3.9配置PyTorch全流程详解

Linux下Miniconda-Python3.9配置PyTorch全流程详解 在深度学习项目开发中&#xff0c;最令人头疼的往往不是模型设计本身&#xff0c;而是“环境配不起来”——明明代码没问题&#xff0c;却因为Python版本冲突、依赖包不兼容、CUDA驱动错位等问题导致训练失败。这种“在我机器…

作者头像 李华
网站建设 2026/5/2 12:02:20

贪心算法专题(十):维度权衡的艺术——「根据身高重建队列」

哈喽各位&#xff0c;我是前端小L。 欢迎来到贪心算法专题第十篇&#xff01; 想象一下&#xff0c;一群人排队&#xff0c;每个人都知道自己的身高 h&#xff0c;也知道排在自己前面且身高大于或等于自己的人数 k。 现在队伍被打乱了&#xff0c;只给你这两个数字&#xff…

作者头像 李华
网站建设 2026/5/3 18:13:43

PyTorch安装卡顿?切换清华源优化Miniconda-Python3.9下载速度

PyTorch安装卡顿&#xff1f;切换清华源优化Miniconda-Python3.9下载速度 在高校实验室的深夜&#xff0c;你正准备复现一篇顶会论文&#xff0c;环境搭建到一半&#xff0c;conda install pytorch 卡在“Fetching packages”已经十分钟——进度条纹丝不动&#xff0c;网络监控…

作者头像 李华
网站建设 2026/5/6 10:43:20

Docker Events实时事件流:Miniconda-Python3.9监听容器活动

Docker Events实时事件流&#xff1a;Miniconda-Python3.9监听容器活动 在现代云原生架构中&#xff0c;系统的可观测性早已不再局限于日志和指标。随着微服务与容器化部署的深入&#xff0c;对运行时行为的动态感知能力成为运维自动化的关键一环。想象这样一个场景&#xff1a…

作者头像 李华
网站建设 2026/5/13 9:23:05

CTF 赛事 SQL 注入实战手册:绕过过滤机制与非常规注入方法

正文 无过滤带回显的情况 手工注入 bugku的环境 在这一环境中的主要是通过post方式传入一个参数id来查询数据库内容。 首先判断sql语句闭合方式 当在id的值后面加上时&#xff0c;界面无回显&#xff0c;可以判断后端的sql语句应该是 select xxxx from xxxx where id in…

作者头像 李华
网站建设 2026/5/2 22:53:11

震惊!文本分块竟成大模型处理长文本的“救命稻草“?程序员必看,小白也能秒懂的Chunk技术解析!

“ 向量数据库的检索原理&#xff0c;就是存储不同数据之间的向量关系&#xff0c;在检索时通过向量关系查询相关数据 ” 文本分块也就是chunk技术是大模型领域中非常重要的一项技术&#xff0c;原因就在于大模型众所周知的问题&#xff0c;上下文窗口限制&#xff1b;虽然说现…

作者头像 李华