Android WiFi 相关

因公司业务需求 进行WiFi相关的开发,包括WiFi的打开关闭,WiFi监听,自定义弹窗输入密码连接、断开WiFi,保存密码等;

按照以往的方式 ,首先百度 ,cv代码,结果各种报错 ;

先介绍下本地开发机,Android11 的pad,在各大论坛找到的WiFi相关论文等都是针对Android 10 之前的内容 、陈旧,完全不适用;

首先把官网得WiFi说明及操作链接放这里,懒得阅读可以去官网查看;WLAN 扫描功能概览  |  Android 开发者  |  Android Developers

针对上述问题为甚么不适用呢,由于Android版本迭代较快 ,个人博客不更新,导致滞后,官网相关API过期。因此,需使用最新的API;

下面贴出Wifi操作的最新的API (本人贴出的部分代码是项目中的某些片段,当cv时会提示缺少变量等,不过整体思路。建议参考下官网实例)

private val mWifiManager: WifiManager by lazy {  mContext.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager } 
//打开、关闭 WiFi开关
mWifiManager.isWifiEnabled =true 

 大意:api在Android api 29(android  10 )中过期,统一返回false 但在Android  28 (Android 9)之前得版本可以继续使用

        打开关闭WiFi API失效

       折中得办法是,通过判断是否有网,弹窗跳转设置WiFi界面,手动打开,同理关闭只能手动关闭WiFi;

1. 扫描WiFi

        分三步:

        1.1.注册广播监听器 

        1.2.请求扫描

        1.3.获取扫描结果

//限制调用函数的次数  
private fun timeOut( block: () ->Unit )  {
          if (  System.currentTimeMillis() - currentTimeMillis > timeOutMillis){
               block.invoke()
          }

          currentTimeMillis =  System.currentTimeMillis()

     }

fun build() {
           //广播的回调
          val broadcastWifi =  object : BroadcastReceiver(){
               override fun onReceive(context: Context?, intent: Intent?) {

                    try {

                         timeOut{
                              intent?.let {
                                   handleReceive(it)
                              }

                         }

                    }catch (e:Exception){
                         LogTag.d("onReceive::${e}")
                    }
               }

          }

//注册广播
          val intentFilter = IntentFilter()
          mOnWifiSwitch?.let { intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION)
               mContext.registerReceiver(broadcastWifi,intentFilter)
          }
          mWifiState?.let { intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)
               intentFilter.addAction(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION)
               mContext.registerReceiver(broadcastWifi,intentFilter)
               startScan()
          }

     }

//获取结果
     private fun handleReceive(intent: Intent) {

               when(intent.action){
                     WifiManager.SCAN_RESULTS_AVAILABLE_ACTION ->{

                          if (intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED,false)
                          ){
                               scanSuccess()
                          }else{
                               scanFailure()
                          }
                     }
               }
     }

     fun startScan() {
          LogTag.d("startScan")
          mWifiManager.startScan()
          mWifiManager.isWifiEnabled =true
     }

     private fun scanFailure() {
          val results = mWifiManager.scanResults
          mWifiState?.stateDisabled(mWifiManager,results)
     }


     private fun scanSuccess() {

          if ( !mWifiManager.isWifiEnabled) {
//               mWifiState?.stateDisConnect()
               return
          }

          //mWifiState?.stateEnabled(mWifiManager,mWifiManager.scanResults)

     }

这里引申出 “ 节流 ” 这个新名词 ,此处是限制WiFi扫描的次数,即限制wifimanager.startScan();

Android 版本各有差异

        下列是Android 8及其以上说明。(不要问我为甚么不贴Android 8之前的)

        Android 8.0 和 Android 8.1

                每个后台应用可以在 30 分钟内扫描一次。

        Android 9

                每个前台应用可以在 2 分钟内扫描四次。这样便可在短时间内进行多次扫描。

        所有后台应用总共可以在 30 分钟内扫描一次。

        Android 10 及更高版本

                适用 Android 9 的节流限制。新增一个开发者选项,用户可以关闭节流功能以便进行

        本地测试(位于开发者选项 > 网络 > WLAN 扫描调节下)

在实际编码中会遇到SecurityException

需要注意权限,主要是WiFi及位置相关缺少相关导致;

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />

        当获取到WiFi列表信息后 需按业务整理获取所需信息包括

        上图( 拷贝的别人的 ) 大体了解下 相关类库及描述 

ps.当注册不同的广播可监听不同的结果  

2.连接、断开WiFi  包括 扫描节流、扫描流程

        连接WiFi,以下是copy别人的代码 ,未验证。在Android 10 及其以上无效

/**
 * ssid: 要连接的ssid
 * password: 要连接的密码
 * encryptType: 加密方式
 */
public static void connectWifi (Context context, String ssid, String password, int encryptType) {

    if (!getWifiEnabled()){
        return;
    }

    WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    WifiConfiguration wc = new WifiConfiguration();
    wc.allowedAuthAlgorithms.clear();
    wc.allowedGroupCiphers.clear();
    wc.allowedKeyManagement.clear();
    wc.allowedPairwiseCiphers.clear();
    wc.allowedProtocols.clear();
    wc.SSID = "\"" + ssid + "\"";

    WifiConfiguration configuration = getWifiConfig(context, ssid);
    if (configuration != null) {
        wm.removeNetwork(configuration.networkId);
    }
    switch (encryptType) {
        case 4:
            // 不加密
            wc.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
            break;
        case 3:
            //wep 加密
            wc.hiddenSSID = true;
            wc.wepKeys[0] = "\"" + password +"\"";
            wc.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
            wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
            wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
            wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
            wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
            wc.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
            break;
        case 0:
            // wpa/wap2加密
        case 1:
            // wpa2加密
        case 2:
            // wpa加密
            wc.preSharedKey = "\"" + password + "\"";
            wc.hiddenSSID = true;
            wc.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
            wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
            wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
            wc.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
            wc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
            wc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
            wc.status = WifiConfiguration.Status.ENABLED;
            break;
        default:
            break;
    }
    // 如果 network = -1,那么这个wifi是已经连接过的
    int network = wm.addNetwork(wc);
    if (network == -1){
        connectWifi(context,ssid);
    }else {
        wm.disconnect();
        wm.enableNetwork(network, true);
    }
}

        Android 10 连接WiFi 

fun connectWifi(wcp:Params,wn: ConnectivityManager.NetworkCallback) {

          if (wcp.mSSid.isNullOrEmpty()){
               Throwable("wifi  ssid not null")
          }
          if (wcp.mPs.isNullOrEmpty()){
               Throwable("wifi  ssid not null")
          }

          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
               val specifier = WifiNetworkSpecifier.Builder()
                    .setSsid(wcp.mSSid!!)
                    .setWpa2Passphrase(wcp.mPs!!)
                    .build()
               val request =
                    NetworkRequest.Builder()
                    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                    .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                    .setNetworkSpecifier(specifier)
                    .build()
               mConnectivityManager.requestNetwork(request, wn)
          } else {
               Exception("小于Build.VERSION.SDK_INT,该方法暂未实现")
          }

     }

        2.1.传入ssid 及 密码 通过调用requestNetwork 传入创建的WLAN网络说明符(specifier )实现连接。详情可参考官网:

适用于互联网连接的 WLAN 建议 API

        2.2.连接WiFi后如何判断是否连接成功 ?如果成功系统会在回调对象上调用NetworkCallback.onAvailable()如果失败,则调用NetworkCallback.onUnavailable()

        这里需要普及,在Android10 后通过上述方式建立WiFi 并非在WiFi设置页面操作WiFi ,而是通过自身应用建立的热点,如果退出或删除app,建立的WiFi也将被删除;同样,连接的WiFi只能本app使用 其他应用无法联网使用

3. 自动连接、取消自动连接

        其他论坛的代码

public static void connectWifi (Context context, String ssid) {
    WifiManager wm = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
    WifiConfiguration wc = new WifiConfiguration();
    wc.SSID = "\"" + ssid + "\"";
    WifiConfiguration configuration = getWifiConfig(context, ssid);
    if (configuration != null) {
        wm.disconnect();
        wm.enableNetwork(configuration.networkId, true);
    }

}

        Android 10  自动连接


//自动连接
fun addNetworkSuggestions(wcp:Params) {
          LogTag.d("自动连接Wifi")
          if (wcp.mSSid.isNullOrEmpty()){
               Throwable("wifi  ssid not null")
          }
          if (wcp.mPs.isNullOrEmpty()){
               Throwable("wifi  ssid not null")
          }

          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
               val suggestion1 = WifiNetworkSuggestion.Builder()
                    .setSsid(wcp.mSSid!!)
                    .setWpa2Passphrase(wcp.mPs!!)
                    .setIsAppInteractionRequired(true)
                    .build()
               val status  = mWifiManager.addNetworkSuggestions(listOf(suggestion1))
               if (status != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS){
                    LogTag.d("自动连接失败")
               }
          } else {
          }
     }

/**
* 取消自动连接
* 取消全部,可以传入独立的网络说明符取消个别的
*/

     fun disConnectWifi() {
          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
               if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                    mWifiManager.removeNetworkSuggestions(mWifiManager.networkSuggestions)
               }else Exception("小于${Build.VERSION.SDK_INT},该方法暂未实现")
          }else Exception("小于${Build.VERSION.SDK_INT},该方法暂未实现")
     }

   4. help类

object NetHelper {
    
    //判断是否联网

    fun IsHaveInternet( context: Context): Boolean {
        //获取连接管理器
       if(isWifiConnect(context) ){
            return true
       }else  if(isShuJuConnect(context) ){
           return true
       }
        return false

    }

    fun isWifiConnect(context: Context?): Boolean {
        if (context != null) {
            val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            val info = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
            if (info != null) {
                return info.isAvailable
            }
        }
        return false
    }

    /*
    * 判断数据流量是否可用
    * */
    fun isShuJuConnect(context: Context?): Boolean {
        if (context != null) {
            val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            val info = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
            if (info != null) {
                return info.isAvailable
            }
        }
        return false
    }

    /**
     * 获取加密方式
     */
    enum class WifiCapability {
        WIFI_CIPHER_WEP, WIFI_CIPHER_WPA, WIFI_CIPHER_NO_PASS
    }


    fun capabilities(capabilities: String): WifiCapability {
        return when {
            capabilities.contains("WEB") -> {
                WifiCapability.WIFI_CIPHER_WEP
            }
            capabilities.contains("PSK") -> {
                WifiCapability.WIFI_CIPHER_WPA
            }
            capabilities.contains("WPS") -> {
                WifiCapability.WIFI_CIPHER_NO_PASS
            }
            else -> {
                WifiCapability.WIFI_CIPHER_NO_PASS
            }
        }
    }

  // 是否是 2.4G
    private var is24G = false

    // 是否是 5G
    private var is5G = false

    /**
     * 设置频率
     *
     * @param frequency 频率
     */
    fun setFrequency(frequency: Int):String {
        if (frequency in 2401..2499) {
            is24G = true
            return "2.4G"
        }
        if (frequency in 4901..5899) {
            is5G = true
            return "5G"
        }

        return ""
    }
}

关于WiFi的相关API很多地方又过期 无法使用,建议直接查官网,官网信息是同步更新的;

如果有什么疑惑或不对的地方,望批评指正,感谢;

参考:Android WiFi(一)_winfred_zen的博客-CSDN博客_android wifi

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值