瀏覽代碼

WiFi模块

wzh 2 年之前
父節點
當前提交
f5c1dd88b7

+ 5 - 0
uni_modules/uni-wifi/changelog.md

@@ -0,0 +1,5 @@
+## 1.0.5(2023-10-26)
+兼容HBuilder 3.9x 版本
+## 1.0.0(2022-12-05)
+实现Android/iOS平台Wi-Fi功能模块  
+注:iOS平台仅支持获取已连接的 Wi-Fi 信息

+ 122 - 0
uni_modules/uni-wifi/package.json

@@ -0,0 +1,122 @@
+{
+  "id": "uni-wifi",
+  "displayName": "uni-wifi",
+  "version": "1.0.5",
+  "description": "wifi管理",
+  "keywords": [
+    "wifi"
+],
+  "repository": "",
+  "engines": {
+    "HBuilderX": "^3.91"
+  },
+  "dcloudext": {
+    "type": "uts",
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "插件不采集任何数据",
+      "permissions": "Android平台:\n<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>\n<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>\n<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>\n<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>\niOS平台:\niOS13及以上平台获取Wifi信息需要定位权限"
+    },
+    "npmurl": ""
+  },
+  "uni_modules": {
+    "uni-ext-api": {
+      "uni": {
+        "startWifi": {
+          "web": false
+        },
+        "stopWifi": {
+          "web": false
+        },
+        "connectWifi": {
+          "web": false
+        },
+        "getConnectedWifi": {
+          "web": false
+        },
+        "getWifiList": {
+          "web": false
+        },
+        "onGetWifiList": {
+          "web": false
+        },
+        "offGetWifiList": {
+          "web": false
+        },
+        "onWifiConnected": {
+          "web": false
+        },
+        "offWifiConnected": {
+          "web": false
+        },
+        "onWifiConnectedWithPartialInfo": {
+          "web": false
+        },
+        "offWifiConnectedWithPartialInfo": {
+          "web": false
+        }
+      }
+    },
+    "dependencies": [],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y"
+      },
+      "client": {
+        "Vue": {
+          "vue2": "y",
+          "vue3": "y"
+        },
+        "App": {
+          "app-android": {
+            "minVersion": "19"
+          },
+          "app-ios": {
+            "minVersion": "9"
+          }
+        },
+        "H5-mobile": {
+          "Safari": "n",
+          "Android Browser": "n",
+          "微信浏览器(Android)": "n",
+          "QQ浏览器(Android)": "n"
+        },
+        "H5-pc": {
+          "Chrome": "n",
+          "IE": "n",
+          "Edge": "n",
+          "Firefox": "n",
+          "Safari": "n"
+        },
+        "小程序": {
+          "微信": "n",
+          "阿里": "n",
+          "百度": "n",
+          "字节跳动": "n",
+          "QQ": "n",
+          "钉钉": "n",
+          "快手": "n",
+          "飞书": "n",
+          "京东": "n"
+        },
+        "快应用": {
+          "华为": "n",
+          "联盟": "n"
+        }
+      }
+    }
+  }
+}

+ 145 - 0
uni_modules/uni-wifi/readme.md

@@ -0,0 +1,145 @@
+## 使用说明  
+
+Wi-Fi功能模块
+
+
+### App-iOS平台注意事项  
+- iOS平台App获取Wi-Fi信息需要开启“Access WiFi information”能力  
+  登录苹果开发者网站,在“Certificates, Identifiers & Profiles”页面选择“Identifiers”中选择对应的App ID,确保开启“Access WiFi information”,保存后重新生成profile文件  
+- iOS13及以上系统,获取当前连接的Wi-Fi信息需要先获取系统定位权限,因此在iOS13及以上系统使用此接口时,会触发定位权限申请的弹窗  
+
+### App-Android平台注意事项  
+- 如果是自定义基座,需要具备下面的权限
+
+```
+<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_FINE_LOCATION"/>
+<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+```
+
+
+###uni.startWifi(OBJECT)
+
+初始化Wi-Fi模块。
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#startwifi](https://uniapp.dcloud.net.cn/api/system/wifi.html#startwifi)
+
+
+### uni.stopWifi(OBJECT)
+
+关闭 Wi-Fi 模块。
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#stopwifi](https://uniapp.dcloud.net.cn/api/system/wifi.html#stopwifi)
+
+
+### uni.getConnectedWifi(OBJECT)
+
+获取已连接的 Wi-Fi 信息
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#getconnectedwifi](https://uniapp.dcloud.net.cn/api/system/wifi.html#getconnectedwifi)
+
+
+### uni.getWifiList(OBJECT)
+
+请求获取 Wi-Fi 列表。wifiList 数据会在 onGetWifiList 注册的回调中返回。
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#getWifiList](https://uniapp.dcloud.net.cn/api/system/wifi.html#getWifiList)
+
+**平台差异说明**
+
+|App-Android|App-iOS|
+|:-:|:-:|
+|√|x|
+
+
+### uni.onGetWifiList(CALLBACK)
+
+监听获取到 Wi-Fi 列表数据事件。
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#onGetWifiList](https://uniapp.dcloud.net.cn/api/system/wifi.html#onGetWifiList)
+
+**平台差异说明**
+
+|App-Android|App-iOS|
+|:-:|:-:|
+|√|x|
+
+
+### uni.offGetWifiList(CALLBACK)
+
+移除获取到 Wi-Fi 列表数据事件的监听函数。
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#offGetWifiList](https://uniapp.dcloud.net.cn/api/system/wifi.html#offGetWifiList)
+
+**平台差异说明**
+
+|App-Android|App-iOS|
+|:-:|:-:|
+|√|x|
+
+
+### uni.connectWifi(OBJECT)
+
+连接 Wi-Fi。若已知 Wi-Fi 信息,可以直接利用该接口连接。
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#connectWifi](https://uniapp.dcloud.net.cn/api/system/wifi.html#connectWifi)
+
+**平台差异说明**
+
+|App-Android|App-iOS|
+|:-:|:-:|
+|√|x|
+
+
+### uni.onWifiConnected(CALLBACK)
+
+监听连接上 Wi-Fi 的事件。
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#onWifiConnected](https://uniapp.dcloud.net.cn/api/system/wifi.html#onWifiConnected)
+
+**平台差异说明**
+
+|App-Android|App-iOS|
+|:-:|:-:|
+|√|x|
+
+
+### uni.offWifiConnected(CALLBACK)
+
+移除连接上 Wi-Fi 的事件的监听函数。
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#offWifiConnected](https://uniapp.dcloud.net.cn/api/system/wifi.html#offWifiConnected)
+
+**平台差异说明**
+
+|App-Android|App-iOS|
+|:-:|:-:|
+|√|x|
+
+
+### uni.onWifiConnectedWithPartialInfo(CALLBACK)
+
+监听连接上 Wi-Fi 的事件。
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#onWifiConnectedWithPartialInfo](https://uniapp.dcloud.net.cn/api/system/wifi.html#onWifiConnectedWithPartialInfo)
+
+**平台差异说明**
+
+|App-Android|App-iOS|
+|:-:|:-:|
+|√|x|
+
+
+### uni.offWifiConnectedWithPartialInfo(CALLBACK)
+
+移除连接上 Wi-Fi 的事件的监听函数。
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#offWifiConnectedWithPartialInfo](https://uniapp.dcloud.net.cn/api/system/wifi.html#offWifiConnectedWithPartialInfo)
+
+**平台差异说明**
+
+|App-Android|App-iOS|
+|:-:|:-:|
+|√|x|
+

+ 3 - 0
uni_modules/uni-wifi/utssdk/app-android/config.json

@@ -0,0 +1,3 @@
+{
+  "minSdkVersion": "19"
+}

+ 847 - 0
uni_modules/uni-wifi/utssdk/app-android/index.uts

@@ -0,0 +1,847 @@
+import Context from "android.content.Context";
+import { UTSAndroid } from "io.dcloud.uts";
+import WifiManager from "android.net.wifi.WifiManager";
+import WifiInfo from "android.net.wifi.WifiInfo";
+import Manifest from "android.Manifest";
+import PackageManager from "android.content.pm.PackageManager";
+import ScanResult from "android.net.wifi.ScanResult";
+import BroadcastReceiver from "android.content.BroadcastReceiver";
+import ActivityCompat from "androidx.core.app.ActivityCompat";
+import IntentFilter from "android.content.IntentFilter";
+import JSONObject from "com.alibaba.fastjson.JSONObject";
+import Intent from "android.content.Intent";
+import Thread from "java.lang.Thread";
+
+import WifiConfiguration from 'android.net.wifi.WifiConfiguration';
+import AuthAlgorithm from 'android.net.wifi.WifiConfiguration.AuthAlgorithm';
+import KeyMgmt from 'android.net.wifi.WifiConfiguration.KeyMgmt';
+import TextUtils from 'android.text.TextUtils';
+import Build from 'android.os.Build';
+
+import { UniWifiResult, GetConnectedWifiOptions, WifiConnectOption, WifiOption, UniWifiInfo } from "../interface.uts"
+
+
+
+/**
+	* 全局数据储存
+	*/
+class Global {
+	static mReceiver : CustomBroadcastReceiver | null = null;
+	static WIFI_AUTH_OPEN : string = "";
+	static WIFI_AUTH_ROAM : String = "[ESS]";
+	// 扫描wifi结果
+	static scanList : AndroidUniWifiInfo[] = []
+	// 获取wifi列表监听
+	static onGetWifiListCallback : UTSCallback | null = null
+	static supendGetWifiSuccess : ((res: UniWifiResult) => void) | null = null
+	static supendGetWifiComplete : ((res: UniWifiResult) => void) | null = null
+	// wifi链接监听
+	static onWifiConnectCallbackList : UTSCallback[] = []
+	static onWifiConnectWithPartialInfoCallbackList : UTSCallback[] = []
+}
+
+
+/**
+	* 是否是标准的16进制字符
+	*/
+function isHex(key : string) : boolean {
+	for (var i = key.length - 1; i >= 0; i--) {
+		let c = key.charAt(i);
+		if (!(c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a'
+			&& c <= 'f')) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
+/**
+	* 判断是否是wep格式的key
+	*/
+function isHexWepKey(wepKey : string) : boolean {
+	let len = wepKey.length;
+
+	// WEP-40, WEP-104, and some vendors using 256-bit WEP (WEP-232?)
+	if (len != 10 && len != 26 && len != 58) {
+		return false;
+	}
+
+	return isHex(wepKey);
+}
+/**
+ * android 平台特有的Wifi信息对象,主要是加了加密信息这个字段
+ */
+export type AndroidUniWifiInfo = {
+	SSID : string;
+	BSSID ?: string;
+	secure : boolean;
+	signalStrength : number;
+	frequency : number;
+	securityType : string;
+}
+
+function wrapUniWifiInfoFromAndroid(androidInfo : AndroidUniWifiInfo) : UniWifiInfo {
+	let ret : UniWifiInfo = {
+		SSID: androidInfo.SSID,
+		BSSID: androidInfo.BSSID,
+		secure: androidInfo.secure,
+		signalStrength: androidInfo.signalStrength,
+		frequency: androidInfo.frequency,
+	}
+	return ret
+}
+/**
+ * 从扫描结果中提取统一的wifi数据结构
+ */
+function wrapUniWifiInfoFromScan(scanResult : ScanResult) : AndroidUniWifiInfo {
+
+	let ret : AndroidUniWifiInfo = {
+		SSID: "",
+		secure: false,
+		signalStrength: 0,
+		frequency: 0,
+		securityType: "NONE"
+	}
+	if (scanResult != null) {
+		// 如果是通过扫描列表得到的数据,进行封装
+		ret.BSSID = scanResult.BSSID;
+		ret.SSID = scanResult.SSID;
+
+		ret.signalStrength = scanResult.level;
+		ret.frequency = scanResult.frequency;
+
+		// 是否安全,微信的标准是是否需要密码。 来源:https://developers.weixin.qq.com/community/develop/doc/00064cf1790458db19cddf9925ac00?highLine=WifiInfo
+		ret.secure = false;
+		let capabilities = scanResult.capabilities.trim();
+		if ((capabilities.equals(Global.WIFI_AUTH_OPEN) || capabilities.equals(Global.WIFI_AUTH_ROAM))) {
+			ret.secure = false;
+		} else {
+			ret.secure = true;
+		}
+
+		/*扩展字段*/
+		ret.securityType = getSecurityType(scanResult);
+	}
+
+	return ret
+}
+/**
+ * 从链接信息中提取统一的wifi数据结构
+ */
+function wrapUniWifiInfoFromConnectInfo(connectInfo : WifiInfo) : UniWifiInfo {
+	let ret : UniWifiInfo = {
+		SSID: "",
+		secure: false,
+		signalStrength: 0,
+		frequency: 0,
+	}
+
+
+	if (connectInfo.getSSID() != null) {
+		let s = connectInfo.getSSID();
+		// 微信不带,这里需要去掉引号
+		if (s.length > 2 && s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') {
+			s = s.substring(1, s.length - 1);
+		}
+		ret.SSID = s;
+	}
+
+	ret.BSSID = connectInfo.getBSSID();
+	//Android返回的值是-100~0,而微信API规范是0~100,值越大信号越好,需要+100拉齐
+	ret.signalStrength = connectInfo.getRssi() + 100;
+	ret.frequency = connectInfo.getFrequency();
+
+
+	return ret
+}
+
+
+/**
+ * 连接wifi时使用,根据用户输入内容包装为系统需要的wifi配置对象
+ **/
+@Suppress("DEPRECATION")
+function wrapWifiConfiguration(SSID : string, password ?: string, passwordType : string) : WifiConfiguration {
+
+	let config = new WifiConfiguration();
+	config.status = WifiConfiguration.Status.ENABLED;
+	config.allowedAuthAlgorithms.clear();
+	config.allowedGroupCiphers.clear();
+	config.allowedKeyManagement.clear();
+	config.allowedPairwiseCiphers.clear();
+	config.allowedProtocols.clear();
+	config.SSID = "\"".concat(SSID).concat("\"");
+
+
+	// nopass
+	if ("NONE".equals(passwordType) || password == null) {
+		config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+	}
+	// wep
+	else if ("WEP".equals(passwordType)) {
+		if (password != null && !TextUtils.isEmpty(password)) {
+			if (isHexWepKey(password)) {
+				config.wepKeys[0] = password;
+			} else {
+				config.wepKeys[0] = "\"".concat(password).concat("\"");
+			}
+		}
+		config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
+		config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
+		config.allowedKeyManagement.set(KeyMgmt.NONE);
+		config.wepTxKeyIndex = 0;
+	}
+	// wpa
+	else if ("WPA".equals(passwordType)) {
+		config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
+		config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
+		config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+		config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+		config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
+		config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
+		config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
+		config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
+		config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
+		config.preSharedKey = "\"".concat(password).concat("\"");
+	}
+
+	return config;
+}
+
+
+/**
+ * 判断当前wifi的加密类型
+ */
+function getSecurityType(result : ScanResult) : string {
+	if (result.capabilities.contains("WEP")) {
+		return "WEP";
+	} else if (result.capabilities.contains("PSK")) {
+		return "WPA";
+	} else if (result.capabilities.contains("EAP")) {
+		return "EAP";
+	}
+	return "NONE";
+}
+
+
+function zeroCountNum(source ?: string) : number {
+	if (source == null) {
+		return 0
+	}
+	var splitted = source.split(":")
+	var countNum = 0;
+	for (perItem in splitted) {
+		if (perItem == "00") {
+			countNum += 1
+		}
+	}
+	return countNum
+}
+
+
+/**
+	* 自定义wifi变化广播监听器
+	*/
+@Suppress("UNUSED_PARAMETER", "DEPRECATION")
+class CustomBroadcastReceiver extends BroadcastReceiver {
+
+	mWifiManager : WifiManager | null = null;
+
+	constructor(wifiManager : WifiManager) {
+		super();
+		this.mWifiManager = wifiManager;
+	}
+
+	override onReceive(_context : Context, intent : Intent) : void {
+
+
+		if (intent.action == WifiManager.WIFI_STATE_CHANGED_ACTION) {
+			let state =
+				intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN)
+			if (state == WifiManager.WIFI_STATE_ENABLED) {
+				// 获取当前的connectInfo 并且进行数据封装
+				// let uniWifiInfo = new UniWifiInfo(null)
+				let uniWifiInfo : UniWifiInfo = {
+					SSID: "",
+					secure: false,
+					signalStrength: 0,
+					frequency: 0,
+				}
+				//做一些异步操作
+				setTimeout(function () {
+					// BroadcastReceiver 中不能执行耗时任务,需要使用setTimeout
+					// @ts-ignore
+					let winfo = this.mWifiManager!.getConnectionInfo();
+
+					while (winfo.bssid == null || zeroCountNum(winfo.bssid) > 4) {
+						Thread.sleep(1000)
+						winfo = this.mWifiManager!.getConnectionInfo();
+					}
+
+					// 封装成数据对象
+					uniWifiInfo = wrapUniWifiInfoFromConnectInfo(winfo)
+					let res = {
+						errMsg: 'onWifiConnected:ok',
+						errCode: 0,
+						wifi: uniWifiInfo
+					}
+					// wifi状态可用了,分发当前的链接状态给已注册的监听集合
+					for (let perCallback in Global.onWifiConnectCallbackList) {
+						perCallback(res);
+					}
+					// 封装仅SSID 数据对象
+					var connectedWithPartialInfo = {
+						SSID: uniWifiInfo.SSID
+					}
+					for (let perCallback in Global.onWifiConnectWithPartialInfoCallbackList) {
+						perCallback(connectedWithPartialInfo);
+					}
+
+				}, 100);
+			}
+
+		}
+
+
+		if (intent.action == WifiManager.SCAN_RESULTS_AVAILABLE_ACTION) {
+			startWifiScaning = false;
+			
+			
+			
+			
+			// wifi 扫描结果回调
+			let results = this.mWifiManager!.scanResults;
+
+			
+			if (results != null) {
+				Global.scanList = []
+				for (let scanResult in results) {
+					if (scanResult.SSID == null) {
+						continue;
+					}
+					Global.scanList.push(wrapUniWifiInfoFromScan(scanResult));
+				}
+
+				// 挨个通知,所有的监听器
+				if(Global.onGetWifiListCallback != null){
+					const data = new JSONObject();
+					data["wifiList"] = Global.scanList
+					Global.onGetWifiListCallback?.(data);
+					/**
+					 * 确保onGetWifiList 只会被执行一次
+					 */
+					Global.onGetWifiListCallback = null
+				}
+
+			}
+
+			let ret : UniWifiResult = {
+				errCode: 0,
+				errSubject: "uni-getWifiList",
+				errMsg: "getWifiList:ok"
+			}
+			if(Global.supendGetWifiSuccess != null){
+				Global.supendGetWifiSuccess?.(ret)
+				Global.supendGetWifiSuccess = null
+			}
+			if(Global.supendGetWifiComplete != null){
+				Global.supendGetWifiComplete?.(ret)
+				Global.supendGetWifiComplete = null
+			}
+		}
+	}
+
+}
+
+
+
+/************************* 下面是对外提供的函数 *************************/
+/**
+ * start wifi是否正在扫描
+ */
+var startWifiScaning = false
+
+/**
+ * 开启wifi
+ */
+@Suppress("DEPRECATION")
+export function startWifi(option : WifiOption) {
+
+	// 需要先开启wifi,才能使用后续的功能
+	let requestCode = 1001;
+	let permissionWifi = arrayOf("android.permission.ACCESS_FINE_LOCATION");
+	
+	let result : UniWifiResult = {
+		errCode: 12001,
+		errMsg: "startWifi:premission loss",
+		errSubject: "uni-startWifi"
+	}
+
+	// 检查权限
+	if (ActivityCompat.checkSelfPermission(UTSAndroid.getUniActivity()!, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
+
+		ActivityCompat.requestPermissions(UTSAndroid.getUniActivity()!, permissionWifi, requestCode.toInt())
+		// 尚不具备权限,返回错误
+		let err = new UniError("uni-startWifi",12001,"startWifi:premission loss");
+		option.fail?.(err)
+		option.complete?.(err)
+
+		return;
+	}
+	
+	// 具备了权限,继续前进
+	let wifiManager : WifiManager =
+		UTSAndroid.getAppContext()!.getSystemService(Context.WIFI_SERVICE) as WifiManager
+	// 用户没有开启wifi 总开关
+	if (!wifiManager.isWifiEnabled()) {
+		// wifi 没开启
+		let err = new UniError("uni-startWifi",12005,"wifi not turned on");
+		option.fail?.(err);
+		option.complete?.(err);
+		return;
+	}
+	// 初始化wifi 状态广播监听,后续所有的api,均基于此
+	if(Global.mReceiver != null){
+		// 说明已经注册过了
+		result.errCode = 0
+		result.errMsg = "startWifi:ok"
+		
+		option.success?.(result)
+		option.complete?.(result)
+		return 
+	}
+	
+	
+	Global.mReceiver = new CustomBroadcastReceiver(wifiManager)
+
+	let filter = new IntentFilter()
+	filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)
+	// @ts-ignore
+	filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION)
+	// @ts-ignore
+	filter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
+
+	UTSAndroid.getUniActivity()!.registerReceiver(Global.mReceiver, filter)
+
+	/**
+		* activity 被销毁时,取消注册
+		*/
+	UTSAndroid.onAppActivityDestroy(function () {
+
+		if (Global.mReceiver != null) {
+			UTSAndroid.getUniActivity()!.unregisterReceiver(Global.mReceiver)
+			Global.mReceiver = null
+
+			Global.scanList = []
+			Global.onGetWifiListCallback = null
+			Global.onWifiConnectCallbackList = []
+			Global.onWifiConnectWithPartialInfoCallbackList = []
+		}
+
+	});
+	startWifiScaning = true
+	// 开始扫描
+	wifiManager.startScan()
+
+	result.errCode = 0
+	result.errMsg = "startWifi:ok"
+
+	option.success?.(result)
+	option.complete?.(result)
+
+}
+
+/**
+	* 获取wifi列表
+	*/
+@Suppress("DEPRECATION")
+export function getWifiList(option : WifiOption) {
+
+
+	if (Global.mReceiver == null) {
+		// 还没调用startWifi 提示报错
+		let err = new UniError("uni-getWifiList",12000,"getWifiList:fail:not invoke startWifi");
+		
+		option.fail?.(err)
+		option.complete?.(err)
+
+		return
+	}
+
+	let wifiManager : WifiManager =
+		UTSAndroid.getAppContext()!.getSystemService(Context.WIFI_SERVICE) as WifiManager
+
+
+
+	Global.supendGetWifiSuccess = option.success
+	Global.supendGetWifiComplete = option.complete
+	
+	wifiManager.startScan()
+	
+
+}
+
+
+
+/**
+	* wifi 链接成功的回调注册
+	*/
+export function onWifiConnected(callback : UTSCallback) {
+	Global.onWifiConnectCallbackList.push(callback)
+}
+
+
+export function onWifiConnectedWithPartialInfo(callback : UTSCallback) {
+	Global.onWifiConnectWithPartialInfoCallbackList.push(callback)
+}
+
+
+/**
+ * wifi 链接成功的回调取消注册
+ */
+export function offWifiConnected(callback? : UTSCallback) {
+	
+	if(callback == null){
+		Global.onWifiConnectCallbackList = []
+		return
+	}
+	
+	let callbackIndex = Global.onWifiConnectCallbackList.indexOf(callback)
+	if (callbackIndex >= 0) {
+		Global.onWifiConnectCallbackList.splice(callbackIndex, 1);
+	}
+}
+
+/**
+ * 不具备详细信息的wifi 反注册
+ */
+export function offWifiConnectedWithPartialInfo(callback? : UTSCallback) {
+	
+	if(callback == null){
+		Global.onWifiConnectWithPartialInfoCallbackList = []
+		return
+	}
+	
+	let callbackIndex = Global.onWifiConnectWithPartialInfoCallbackList.indexOf(callback)
+	if (callbackIndex >= 0) {
+		Global.onWifiConnectWithPartialInfoCallbackList.splice(callbackIndex, 1);
+	}
+}
+
+/**
+	* 注册Wifi列表的监听事件
+	*/
+export function onGetWifiList(callback : UTSCallback) {
+	Global.onGetWifiListCallback = callback
+}
+
+/**
+ * 取消注册Wifi列表的监听事件
+ */
+export function offGetWifiList(callback? : UTSCallback) {
+	Global.onGetWifiListCallback = null
+	Global.supendGetWifiComplete = null
+	Global.supendGetWifiSuccess = null
+}
+
+
+/**
+ * 真正执行wifi链接逻辑
+ */
+function realWifiConnect(option : WifiConnectOption){
+	
+	if (Global.mReceiver == null || Global.scanList.length < 1) {
+		
+		let err = new UniError("uni-connectWifi",12000,"connectWifi:fail:not invoke startWifi");
+		option.fail?.(err)
+		option.complete?.(err)
+		
+		return
+	}
+	
+	// 执行后续的逻辑
+	let scanWifiInfo : AndroidUniWifiInfo | null = null
+	for (let scanResult in Global.scanList) {
+		if (scanResult.SSID.equals(option.SSID)) {
+			scanWifiInfo = scanResult
+		}
+	}
+	
+	if (scanWifiInfo == null) {
+		// 不在扫描列表中返回错误
+		let err = new UniError("uni-connectWifi",12000,"connectWifi:fail:not invoke startWifi");
+		option.fail?.(err)
+		option.complete?.(err)
+		return
+	}
+	
+	let wifiConfigration = wrapWifiConfiguration(scanWifiInfo.SSID, option.password, scanWifiInfo.securityType);
+	wifiConfigration.BSSID = scanWifiInfo.BSSID
+	let wifiManager : WifiManager =
+		UTSAndroid.getAppContext()!.getSystemService(Context.WIFI_SERVICE) as WifiManager
+	
+	// 如果已经存在了指定wifi 配置,移除之
+	let targetExistConfig : WifiConfiguration | null = null
+	let existingConfigs = wifiManager.getConfiguredNetworks();
+	for (let existingConfig in existingConfigs) {
+		if (existingConfig.SSID.equals("\"" + option.SSID + "\"")) {
+			targetExistConfig = existingConfig
+		}
+	}
+	// 如果wifi已经保存了当前ssid的配置,可能是别的应用添加的。android系统要求,需要删除掉重新添加
+	if (targetExistConfig != null) {
+		let removeRet = wifiManager.removeNetwork(targetExistConfig.networkId);
+		
+		if (!removeRet) {
+			
+			// add since 2023-03-28,如果当前系统大于等于android10, 则明确当前系统不支持
+			if(Build.VERSION.SDK_INT > 28){
+				// 系统大于android 9
+				let err = new UniError("uni-connectWifi",12001,"connectWifi:system not support");
+				option.fail?.(err)
+				option.complete?.(err)
+			}else{
+				// 移除之前的配置失败了,返回错误,需要用户手动取消保存一下
+				let err = new UniError("uni-connectWifi",12013,"connectWifi:wifi config may be expired");
+				option.fail?.(err)
+				option.complete?.(err)
+			}
+			
+	
+			return
+		}
+	
+	}
+	
+	let currentConnect = wifiManager.getConnectionInfo()
+	if (currentConnect.networkId >= 0) {
+		wifiManager.disableNetwork(currentConnect.networkId)
+	} else {
+		wifiManager.removeNetwork(currentConnect.networkId)
+	}
+	wifiManager.disconnect()
+	
+	let connected = false;
+	try {
+	
+		let netID = wifiManager.addNetwork(wifiConfigration);
+		// 如果-1 说明没添加上,报错即可
+		if (netID < 0) {
+			
+			let err = new UniError("uni-connectWifi",12002,"connectWifi:password error Wi-Fi");
+	
+			option.fail?.(err)
+			option.complete?.(err)
+	
+			return
+		}
+	
+	
+		let enabled = wifiManager.enableNetwork(netID, true);
+		if (!enabled) {
+	
+			let err = new UniError("uni-connectWifi",12007,"connectWifi:user denied");
+				
+			option.fail?.(err)
+			option.complete?.(err)
+	
+			return
+		}
+		connected = wifiManager.reconnect();
+	
+	} catch (e) {
+		connected = false;
+		console.log(e);
+	}
+	
+	if (!connected) {
+		// 出错了,返回错误
+		// 兜底的报错
+		let err = new UniError("uni-connectWifi",12010,"connectWifi:fail:unknown error");
+		option.fail?.(err)
+		option.complete?.(err)
+		return
+	}
+	
+	let result : UniWifiResult = {
+		errCode: 0,
+		errMsg: "connectWifi:ok",
+		errSubject: "uni-connectWifi",
+	}
+	
+	wifiManager.saveConfiguration()
+	//scanWifiInfo 根据 partialInfo 填充给返回字段
+	if (option.partialInfo != null && option.partialInfo == true) {
+		let wifiPartialInfo : UniWifiInfo = {
+			SSID: scanWifiInfo.SSID
+		}
+		result.wifi = wifiPartialInfo
+	} else {
+		result.wifi = wrapUniWifiInfoFromAndroid(scanWifiInfo)
+	}
+	
+	
+	option.success?.(result)
+	option.complete?.(result)
+}
+
+/**
+ * 链接指定wifi
+ */
+@Suppress("UNUSED_PARAMETER", "DEPRECATION")
+export function connectWifi(option : WifiConnectOption) {
+
+	if (option.maunal == true) {
+		// 指定了手动模式
+		let manunalIntent = new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS);
+		UTSAndroid.getUniActivity()!.startActivity(manunalIntent);
+
+		let result : UniWifiResult = {
+			errCode: 0,
+			errMsg: "connectWifi:ok",
+			errSubject: "uni-connectWifi",
+		}
+
+		option.success?.(result)
+		option.complete?.(result)
+		return
+	}
+
+	
+	
+	// add since 2022-03-28 ,增加逻辑,如果正在扫描中,则可以等待5s
+	if(startWifiScaning){
+		let taskCount = 0
+		let taskId:number  = 0
+		taskId = setInterval(function(){
+		
+			taskCount += 1;
+			if(taskCount >= 5 || startWifiScaning == false){
+				// 超过10s了。或者扫描过程结束了
+				clearInterval(taskId)
+				realWifiConnect(option)
+			}
+		},2000)
+		
+		UTSAndroid.onAppActivityDestroy(function () {
+			clearInterval(taskId)
+		});
+	}else{
+		realWifiConnect(option)
+	}
+
+	
+
+}
+
+
+/**
+	* 关闭wifi
+	*/
+export function stopWifi(option : WifiOption) {
+	// 需要先开启wifi,才能使用后续的功能
+	if (Global.mReceiver == null) {
+		let err = new UniError("uni-stopWifi",12000,"stopWifi:not init");
+		option.fail?.(err)
+		option.complete?.(err)
+
+		return
+	}
+	try {
+		UTSAndroid.getUniActivity()!.unregisterReceiver(Global.mReceiver)
+	} catch (e) {
+		// 多次调用
+		//TODO handle the exception
+	}
+	
+	Global.onGetWifiListCallback = null
+	Global.onWifiConnectWithPartialInfoCallbackList = []
+	Global.onWifiConnectCallbackList = []
+	Global.mReceiver = null
+	
+	let result : UniWifiResult = {
+		errCode: 0,
+		errSubject: "uni-stopWifi",
+		errMsg: "stopWifi:ok"
+	}
+
+	option.success?.(result)
+	option.complete?.(result)
+
+}
+
+/**
+ * 获取当前连接中的wifi信息
+ */
+@Suppress("DEPRECATION")
+export function getConnectedWifi(option : GetConnectedWifiOptions) {
+
+	let wifiInfo : UniWifiInfo = {
+		SSID: ""
+	}
+
+	
+	if (Global.mReceiver == null) {
+		// 还没调用startWifi 提示报错
+		let err = new UniError("uni-getConnectedWifi",12000,"getConnectedWifi:fail:not invoke startWifi");
+		option.fail?.(err)
+		option.complete?.(err)
+
+		return
+	}
+
+	// 需要先校验权限,没有位置权限无法获取wifi
+	if (ActivityCompat.checkSelfPermission(UTSAndroid.getUniActivity()!, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
+		// 尚不具备权限,返回错误
+		let err = new UniError("uni-getConnectedWifi",12001,"getConnectedWifi:permission loss");
+		option.fail?.(err)
+		option.complete?.(err)
+		return;
+	}
+
+	
+	
+	const context = UTSAndroid.getAppContext();
+	if (context != null) {
+		const wm = context.getSystemService(
+			Context.WIFI_SERVICE
+		) as WifiManager;
+		// 测试android 12上可以使用
+		//@ts-ignore
+		const winfo = wm.getConnectionInfo();
+
+		wifiInfo = wrapUniWifiInfoFromConnectInfo(winfo);
+		
+		let res : UniWifiResult = {
+			errCode: 0,
+			errMsg: "getConnectedWifi:ok",
+			errSubject: "uni-getConnectedWifi",
+		}
+
+		// 判断一下是否wifi 关闭了
+		if (option.partialInfo!= null) {
+			let ret : UniWifiInfo = {
+				SSID: wifiInfo.SSID
+			}
+			res.wifi = ret;
+		} else {
+			if (wifiInfo.BSSID == null || zeroCountNum(wifiInfo.BSSID) > 3) {
+				let err = new UniError("uni-getConnectedWifi",12005,"getConnectedWifi:fail:wifi is disable");
+				option.fail?.(err)
+				option.complete?.(err)
+				return
+			}
+			res.wifi = wifiInfo;
+		}
+
+
+		option.success?.(res)
+		option.complete?.(res)
+		return
+	}
+	
+	let err = new UniError("uni-getConnectedWifi",12000,"getConnectedWifi:fail:not invoke startWifi");
+	option.fail?.(err)
+	option.complete?.(err)
+}
+

+ 8 - 0
uni_modules/uni-wifi/utssdk/app-ios/Info.plist

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+  <dict>
+    <key>NSLocationWhenInUseUsageDescription</key>
+    <string>使用期间获取位置权限</string>
+  </dict>
+</plist>

+ 8 - 0
uni_modules/uni-wifi/utssdk/app-ios/UTS.entitlements

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>com.apple.developer.networking.wifi-info</key>
+	<true/>
+</dict>
+</plist>

+ 9 - 0
uni_modules/uni-wifi/utssdk/app-ios/config.json

@@ -0,0 +1,9 @@
+{
+	"frameworks": [
+		"CoreLocation.framework",
+		"SystemConfiguration.framework"
+	],
+	"validArchitectures": [
+		"arm64", "armv7"
+	],"deploymentTarget": "9"
+}

+ 267 - 0
uni_modules/uni-wifi/utssdk/app-ios/index.uts

@@ -0,0 +1,267 @@
+import { CLLocationManager, CLAuthorizationStatus, CLLocationManagerDelegate } from 'CoreLocation'
+import { CaptiveNetwork, kCNNetworkInfoKeySSID, kCNNetworkInfoKeyBSSID } from 'SystemConfiguration.CaptiveNetwork';
+import { NSArray, NSDictionary } from 'Foundation';
+import { CFString } from 'CoreFoundation';
+import { UIDevice } from 'UIKit';
+import { WifiOption, WifiConnectOption, GetConnectedWifiOptions, UniWifiInfo, UniWifiResult, UniWifiCallback, StartWifi, StopWifi, GetWifiList, OnGetWifiList, OffGetWifiList, GetConnectedWifi, ConnectWifi, OnWifiConnected, OnWifiConnectedWithPartialInfo, OffWifiConnected, OnOffWifiConnectedWithPartialInfo, SetWifiList } from "../interface.uts"
+
+/* 
+ * 系统定位权限获取类
+ */
+class LocationPromiseService implements CLLocationManagerDelegate  {
+	static promiseCompletionHandler: ((res: boolean)=>void)[] = []
+	
+	manager?: CLLocationManager
+	
+	constructor(manager?: CLLocationManager) {
+		this.manager = manager
+	}
+	
+	initlizeManager(): boolean {
+		if (this.manager == null) {
+			this.manager = new CLLocationManager()
+			this.manager!.delegate = this
+		}
+		return true
+	}
+	
+	locationManager(manager: CLLocationManager, @argumentLabel("didChangeAuthorization") status: CLAuthorizationStatus) {
+		if (status == CLAuthorizationStatus.authorizedAlways || status == CLAuthorizationStatus.authorizedWhenInUse) {
+			LocationPromiseService.promiseCompletionHandler.forEach((handler): void => {
+				handler(true)
+			})
+		} else if (status == CLAuthorizationStatus.notDetermined) { 
+			manager.requestWhenInUseAuthorization()
+		} else if (status == CLAuthorizationStatus.denied) {
+			LocationPromiseService.promiseCompletionHandler.forEach((handler): void => {
+				handler(false)
+			})
+		}
+	}   
+	requestPromise(@escaping completion: (res: boolean)=>void) {
+		let status: CLAuthorizationStatus = CLLocationManager.authorizationStatus()
+		if (status == CLAuthorizationStatus.notDetermined) {
+			if (this.initlizeManager() == true) {
+				this.manager!.requestWhenInUseAuthorization()
+				LocationPromiseService.promiseCompletionHandler.push(completion)
+			}
+		} else if (status == CLAuthorizationStatus.authorizedAlways || status == CLAuthorizationStatus.authorizedWhenInUse) {
+			completion(true)
+		} else if (status == CLAuthorizationStatus.denied) {
+			if (CLLocationManager.locationServicesEnabled() == false && this.initlizeManager() == true) {
+				this.manager!.requestWhenInUseAuthorization()
+				LocationPromiseService.promiseCompletionHandler.push(completion)
+			}
+		} 
+	}
+}
+
+const locationPromiseService: LocationPromiseService = new LocationPromiseService(null)
+
+/* 
+ * 获取系统定位权限 
+ */
+function requestLocationPromise(@escaping completion: (res: boolean)=>void) {
+	locationPromiseService.requestPromise(completion)
+}
+
+/* 
+ * 获取当前连接的wifi信息(通过定位权限)
+ */
+function fetchConnectedWifiWithLocationPromise(option: GetConnectedWifiOptions) {
+	let arr = CNCopySupportedInterfaces()
+	let wifiInfo: UniWifiInfo = {
+		BSSID: "",
+		SSID: "",
+		secure: false,
+		signalStrength: 0,
+		frequency: 0
+	} 
+	
+	if (arr != null) {
+		let list = arr! as NSArray
+		let index: Int = 0
+		while (index < list.count) { 
+			let item = list[index] 
+			let interfaceName = item as string
+			let dic = CNCopyCurrentNetworkInfo(interfaceName as CFString)
+			if (dic != null) {
+				let dict = dic! as NSDictionary
+				let SSID = dict[kCNNetworkInfoKeySSID as string] 
+				let BSSID = dict[kCNNetworkInfoKeyBSSID as string]
+				
+				if (SSID != null && BSSID != null) {
+					let ssid = SSID! as string
+					let bssid = BSSID! as string
+					wifiInfo.SSID = ssid
+					wifiInfo.BSSID = bssid
+					wifiInfo.secure = false
+					wifiInfo.signalStrength = 0
+					wifiInfo.frequency = 0
+					break;
+				}
+			}
+			index++
+		}
+		
+		if (wifiInfo.BSSID!.length > 0 && wifiInfo.SSID.length > 0) {
+			let res: UniWifiResult = {
+				errSubject: "uni-getConnectedWifi",
+				errCode: 0,
+				errMsg: "getConnectedWifi:ok",
+				wifi: wifiInfo,
+			}
+			option.success?.(res)
+			option.complete?.(res)
+		}else {
+			let err = new UniError("uni-getConnectedWifi",12010,"getConnectedWifi:system internal error");
+			option.fail?.(err)
+			option.complete?.(err)
+		}
+	}else {
+		let err = new UniError("uni-getConnectedWifi",12010,"getConnectedWifi:system internal error");
+		option.fail?.(err)
+		option.complete?.(err)
+	}
+}
+
+
+
+/* 
+ * 保存全局数据信息
+ */
+class UniWiFiModuleGloabInfo {
+	static alreadyStartWifi: boolean = false
+}
+
+/* =================================== 对外暴露的接口 ==============================================*/
+
+
+
+/* 
+ * 初始化wifi模块 
+ */
+export const startWifi: StartWifi = function (option: WifiOption) {
+	UniWiFiModuleGloabInfo.alreadyStartWifi = true
+	let res: UniWifiResult = {
+		errSubject: "uni-startWifi",
+		errCode: 0, 
+		errMsg: "startWifi:ok",
+		wifi: null
+	}
+	option.success?.(res)
+	option.complete?.(res)
+}
+
+/* 
+ * 停止wifi模块 
+ */
+export const stopWifi: StopWifi = function (option: WifiOption) {
+	UniWiFiModuleGloabInfo.alreadyStartWifi = false
+	LocationPromiseService.promiseCompletionHandler = []	
+	let res: UniWifiResult = {
+		errSubject: "uni-stopWifi",
+		errCode: 0, 
+		errMsg: "stopWifi:ok",
+		wifi: null
+	}
+	option.success?.(res)
+	option.complete?.(res)
+}
+
+/* 
+ * 获取wifi列表, 在调用之前需要引导用户跳转到系统设置-WIFI设置页面,系统搜索周边wifi后app才能接收到回调
+ */
+export const getWifiList: GetWifiList = function (option: WifiOption) {
+	let err = new UniError("uni-getWifiList",12001,"getWifiList:system not support");
+	option.fail?.(err)
+	option.complete?.(err)
+}
+
+/* 获取wifi列表的回调
+ * note: 请在getWifiList方法的回调里调用该方法
+ */
+export const onGetWifiList: OnGetWifiList = function (callback: UniWifiCallback) {
+	
+}
+
+/* 
+ *	注销获取wifi列表的回调
+ */
+export const offGetWifiList: OffGetWifiList = function (callback: UniWifiCallback) {
+
+}
+
+
+/* 
+ * 获取当前连接的wifi信息
+ */
+export const getConnectedWifi: GetConnectedWifi = function (option: GetConnectedWifiOptions) {
+	if (UniWiFiModuleGloabInfo.alreadyStartWifi == false) {
+		let err = new UniError("uni-getConnectedWifi",12000,"getConnectedWifi:not init");
+		option.fail?.(err)
+		option.complete?.(err)
+	} else{
+		if (UIDevice.current.systemVersion >= "13.0") {
+			requestLocationPromise((success) => {
+				if (success == true) {
+					fetchConnectedWifiWithLocationPromise(option)
+				}else {
+					let err = new UniError("uni-getConnectedWifi",12007,"getConnectedWifi:user denied");
+					option.fail?.(err)
+					option.complete?.(err)
+				}
+			})
+		} else{
+			fetchConnectedWifiWithLocationPromise(option)
+		}
+	}
+}
+
+/* 
+ * 连接wifi
+ */
+export const connectWifi: ConnectWifi = function (option: WifiConnectOption) {
+	
+	let err = new UniError("uni-connectWifi",12001,"connectWifi:system not support");
+	option.fail?.(err)
+	option.complete?.(err)
+}
+
+
+/* 
+ * 连上wifi事件的监听函数
+ */
+export const onWifiConnected: OnWifiConnected = function (callback: UniWifiCallback) {
+	
+}
+
+/* 
+ * 连上wifi事件的监听函数, wifiInfo仅包含ssid
+ */
+export const onWifiConnectedWithPartialInfo: OnWifiConnectedWithPartialInfo = function (callback: UniWifiCallback) {
+	
+}
+
+/* 
+ *	移除连接上wifi的事件的监听函数,不传此参数则移除所有监听函数。
+ */
+export const offWifiConnected: OffWifiConnected = function (callback: UniWifiCallback | null) {
+
+}
+
+/* 
+ *	移除连接上wifi的事件的监听函数,不传此参数则移除所有监听函数。
+ */
+export const onOffWifiConnectedWithPartialInfo: OnOffWifiConnectedWithPartialInfo = function (callback: UniWifiCallback | null) {
+
+}
+
+/* 
+ * 设置 wifiList 中 AP 的相关信息。在 onGetWifiList 回调后调用,iOS特有接口。
+ */
+export const setWifiList: SetWifiList = function (option: WifiOption) {
+	let err = new UniError("uni-setWifiList",12001,"setWifiList:system not support");
+	option.fail?.(err)
+	option.complete?.(err)
+}

+ 395 - 0
uni_modules/uni-wifi/utssdk/interface.uts

@@ -0,0 +1,395 @@
+/**
+ * Wifi 函数通用入参封装
+ */
+export type WifiOption = {
+	success ?: (res : UniWifiResult) => void;
+	fail ?: (res : UniError) => void;
+	complete ?: (res : any) => void;
+};
+
+/**
+ * Wifi 链接参数封装 
+ */
+export type WifiConnectOption = {
+	SSID ?: string;
+	BSSID ?: string;
+	password ?: string;
+	maunal ?: boolean;
+	partialInfo ?: boolean; //ios不生效
+	success ?: (res : UniWifiResult) => void;
+	fail ?: (res : UniError) => void;
+	complete ?: (res : any) => void;
+}
+
+/**
+ * 获取当前链接的wifi信息
+ */
+export type GetConnectedWifiOptions = {
+	partialInfo ?: boolean
+	success ?: (res : UniWifiResult) => void
+	fail ?: (res : UniError) => void
+	complete ?: (res : any) => void
+}
+
+/* 
+ * 对外暴露的wifi信息
+ */
+export type UniWifiInfo = {
+	SSID : string;
+	BSSID ?: string;
+	secure ?: boolean;
+	signalStrength ?: number;
+	frequency ?: number;
+}
+
+
+export type UniWifiResult = {
+	errCode : number,
+	errSubject : string,
+	errMsg : string,
+	wifi : UniWifiInfo | null
+}
+
+export type UniWifiCallback = () => void
+
+
+export type StartWifi = (option : WifiOption) => void
+
+export type StopWifi = (option : WifiOption) => void
+
+export type GetWifiList = (option : WifiOption) => void
+
+export type OnGetWifiList = (callback : UniWifiCallback) => void
+
+export type OffGetWifiList = (callback : UniWifiCallback) => void
+
+export type GetConnectedWifi = (option : GetConnectedWifiOptions) => void
+
+export type ConnectWifi = (option : WifiConnectOption) => void
+
+export type OnWifiConnected = (callback : UniWifiCallback) => void
+
+export type OnWifiConnectedWithPartialInfo = (callback : UniWifiCallback) => void
+
+export type OffWifiConnected = (callback : UniWifiCallback | null) => void
+
+export type OnOffWifiConnectedWithPartialInfo = (callback : UniWifiCallback | null) => void
+
+export type SetWifiList = (option : WifiOption) => void
+
+interface Uni {
+	/**
+	 * 初始化Wi-Fi模块
+	 * 
+	 * @param {WifiOption} option 
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#startwifi
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "4.4.4",
+	 *            "uniVer": "3.7.0",
+	 *            "unixVer": "3.9.0"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "9.0",
+	 *            "uniVer": "3.7.7",
+	 *            "unixVer": "3.9.0"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest { after: 'stopWifi' }
+	 */
+	startWifi(option : WifiOption): void,
+	/**
+	 * 关闭 Wi-Fi 模块
+	 * 
+	 * @param {WifiOption} option 
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#stopwifi
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "4.4.4",
+	 *            "uniVer": "3.7.0",
+	 *            "unixVer": "3.9.0"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "9.0",
+	 *            "uniVer": "3.7.7",
+	 *            "unixVer": "3.9.0"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest { before: 'startWifi' }
+	 */
+	stopWifi(option : WifiOption) : void,
+	/**
+	 * @param {WifiConnectOption} option 
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#connectWifi
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": ">=4.4 && <10.0",
+	 *            "uniVer": "3.7.0",
+	 *            "unixVer": "3.9.0"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "9.0",
+	 *            "uniVer": "3.7.7",
+	 *            "unixVer": "3.9.0"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest {
+		generated: false,
+		pollution: false,
+		cases:[
+			{
+				before: 'startWifi',
+				after: 'stopWifi',
+				input: [{
+					maunal:false,
+					SSID:"Xiaomi_20D0",
+					password:"streamApp!2016",
+				}],
+				output:{
+						callbackType: 'success',
+						value: { errCode: 12013 ,errMsg: "connectWifi:wifi config may be expired",errSubject: "uni-connectWifi"}
+					}
+			}
+		]
+	}
+	*/
+	connectWifi(option : WifiConnectOption) : void,
+	/**
+	 * 请求获取 Wi-Fi 列表。wifiList 数据会在 onGetWifiList 注册的回调中返回。
+	 * @param {WifiOption} option
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#getWifiList
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "4.4.4",
+	 *            "uniVer": "3.7.0",
+	 *            "unixVer": "3.9.0"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "9.0",
+	 *            "uniVer": "3.7.7",
+	 *            "unixVer": "3.9.0"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest { before: 'startWifi', after: 'stopWifi' }
+	*/
+	getWifiList(option : WifiOption) : void,
+	/**
+	 * 监听获取到 Wi-Fi 列表数据事件。
+	 * 
+	 * @param {UniWifiCallback} callback 
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#onGetWifiList
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "4.4.4",
+	 *            "uniVer": "3.7.0",
+	 *            "unixVer": "3.9.0"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "9.0",
+	 *            "uniVer": "3.7.7",
+	 *            "unixVer": "3.9.0"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest  { expectCallback: true }
+	 * @autotest {
+		 generated: false,
+		 pollution: false,
+		 expectCallback: true,
+		 before: 'startWifi',
+		 after: 'onGetWifiListAfter',
+		 cases: [
+			 {
+				 output: {
+					 value: 0,
+					 returnKey: '.wifiList.length',
+					 jestExpectSyntax: 'toBeGreaterThan'
+				 },
+			 }
+		 ]
+	}
+	 */
+	onGetWifiList(callback : UniWifiCallback) : void,
+	/**
+	 * 移除获取到 Wi-Fi 列表数据事件的监听函数。
+	 * 
+	 * @param {UniWifiCallback} callback 
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#offGetWifiList
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "4.4.4",
+	 *            "uniVer": "3.7.0",
+	 *            "unixVer": "3.9.0"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "9.0",
+	 *            "uniVer": "3.7.7",
+	 *            "unixVer": "3.9.0"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest { expectCallback: true }
+	 */
+	offGetWifiList(callback : UniWifiCallback) : void,
+	/**
+	 * 获取已连接的 Wi-Fi 信息
+	 * 
+	 * @param {GetConnectedWifiOptions} option 
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#getConnectedWifi
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "4.4.4",
+	 *            "uniVer": "3.7.0",
+	 *            "unixVer": "3.9.0"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "9.0",
+	 *            "uniVer": "3.7.7",
+	 *            "unixVer": "3.9.0"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest { before: 'startWifi', after: 'stopWifi' }
+	 */
+	getConnectedWifi(option : GetConnectedWifiOptions) : void,
+	/**
+	 * 监听连接上 Wi-Fi 的事件
+	 * 
+	 * @param {UniWifiCallback} callback 
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#onWifiConnected
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "4.4.4",
+	 *            "uniVer": "3.7.0",
+	 *            "unixVer": "3.9.0"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "9.0",
+	 *            "uniVer": "3.7.7",
+	 *            "unixVer": "3.9.0"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest { expectCallback: true }
+	 */
+	onWifiConnected(callback : UniWifiCallback) : void,
+	/**
+	 * 监听连接上 Wi-Fi 的事件。
+	 * 
+	 * @param {UniWifiCallback} callback 
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#onWifiConnectedWithPartialInfo
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "4.4.4",
+	 *            "uniVer": "3.7.0",
+	 *            "unixVer": "3.9.0"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "9.0",
+	 *            "uniVer": "3.7.7",
+	 *            "unixVer": "3.9.0"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest { expectCallback: true }
+	 */
+	onWifiConnectedWithPartialInfo(callback : UniWifiCallback) : void,
+	/**
+	 * 移除连接上 Wi-Fi 的事件的监听函数。
+	 * 
+	 * @param {UniWifiCallback} callback 
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#offWifiConnected
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "4.4.4",
+	 *            "uniVer": "3.7.0",
+	 *            "unixVer": "3.9.0"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "9.0",
+	 *            "uniVer": "3.7.7",
+	 *            "unixVer": "3.9.0"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest { expectCallback: true }
+	 */
+	offWifiConnected(callback : UniWifiCallback | null) : void,
+	/**
+	 * 移除连接上 Wi-Fi 的事件的监听函数。
+	 * 
+	 * @param {UniWifiCallback} callback 
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#onOffWifiConnectedWithPartialInfo
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "x",
+	 *            "uniVer": "x",
+	 *            "unixVer": "x"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "x",
+	 *            "uniVer": "x",
+	 *            "unixVer": "x"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest { expectCallback: true }
+	 */
+	onOffWifiConnectedWithPartialInfo(callback : UniWifiCallback | null) : void,
+	/**
+	 * SetWifiList  暂未实现
+	 * 
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "x",
+	 *            "uniVer": "x",
+	 *            "unixVer": "x"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "x",
+	 *            "uniVer": "x",
+	 *            "unixVer": "x"
+	 *   	  }
+	 *    }
+	 * }
+	 */
+	setWifiList(option : WifiOption) : void,
+}

+ 35 - 0
uni_modules/uni-wifi/utssdk/uni.autotest.js

@@ -0,0 +1,35 @@
+export function startWifi() {
+	return new Promise((resolve, reject) => {
+		uni.startWifi({
+			success: () => {
+				console.log('startWifi success');
+				resolve()
+			},
+			complete: () => {
+				console.log('startWifi fail');
+				resolve()
+			}
+		})
+	})
+}
+
+export function stopWifi() {
+	return new Promise((resolve, reject) => {
+		uni.stopWifi({
+			complete: resolve
+		})
+	})
+}
+
+export function onGetWifiListAfter() {
+	return new Promise((resolve, reject) => {
+		uni.getWifiList({
+			success() {
+				setTimeout(resolve, 500)
+			},
+			complete() {
+				stopWifi().finally(resolve)
+			}
+		})
+	})
+}