移动端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>
相关推荐
王家视频教程图书馆3 小时前
提交到gitee
gitee
麦克马2 天前
GameplayAbilitiesSystem(二)
gitee
-拟墨画扇-2 天前
Git | 标签操作
git·gitee·github·gitcode
-拟墨画扇-2 天前
Git | 远程仓库操作
git·gitee·github
-拟墨画扇-2 天前
Git | 配置别名操作
git·gitee·github·gitcode
-拟墨画扇-2 天前
Git | 多人协助策略
git·gitee·github·gitcode
Huazzi.2 天前
使用Scoop安装Git
git·elasticsearch·gitee·ssh·github·scoop
KevinRay_2 天前
Github如何上传项目(超详细小白教程)
git·gitee·开源·github·vim
-拟墨画扇-3 天前
Git | 分支管理操作
git·gitee·github·gitcode