基础环境

Flutter 社区地址: https://atomgit.com/CPF-Flutter/flutter_flutter
三方库地址:https://atomgit.com/oh-flutter/wifi_iot
Flutter版本:3.44.9
在这里插入图片描述

库的概述

wifi_iot 原本是 flutternetwork/WiFiFlutter 提供的 Flutter WiFi 连接管理插件,官方版本支持 Android、iOS 两个平台。通过社区的努力,现阶段已经支持鸿蒙方向。

在这里插入图片描述
鸿蒙系统版本
在这里插入图片描述

主要功能

用于处理 WiFi 连接(AP、STA)的 Flutter 插件。

WiFi 站点(STA)模式

  • 启用/禁用 WiFi 模块
  • 扫描附近 WiFi 网络
  • 连接/断开 WiFi 网络(支持 WPA/WEP)
  • 注册/注销 WiFi 网络
  • 获取当前连接信息:SSID、BSSID、信号强度、频率、IP 地址

WiFi 热点(AP)模式

  • 查询热点状态
  • 启用/禁用热点
  • 获取/设置热点 SSID 和密码
  • 隐藏/显示 SSID
  • 获取已连接客户端列表

API 说明

API描述参数返回值OpenHarmony支持
isEnabled()检查WiFi是否启用Future<bool>
setEnabled()启用/禁用WiFishouldOpenSettings: boolFuture<void>是(打开设置页)
connect()连接到WiFi网络ssid, password, security, join_once, is_hidden, timeout_in_secondsFuture<bool>
findAndConnect()通过SSID查找并连接ssid, bssid, password, join_once, timeout_in_secondsFuture<bool>
registerWifiNetwork()注册WiFi网络ssid, password, security, is_hiddenFuture<bool>
isConnected()检查是否已连接Future<bool>
disconnect()断开网络连接Future<bool>
getSSID()获取当前SSIDFuture<String?>
getBSSID()获取当前BSSIDFuture<String?>
getCurrentSignalStrength()获取信号强度Future<int?>
getFrequency()获取频率Future<int?>
getIP()获取IP地址Future<String?>
isRegisteredWifiNetwork()检查网络是否已注册ssidFuture<bool>
removeWifiNetwork()移除已注册网络ssidFuture<bool>
isWiFiAPEnabled()检查热点是否启用Future<bool>
getWiFiAPSSID()获取热点SSIDFuture<String?>
setWiFiAPSSID()设置热点SSIDssidFuture<void>
getWiFiAPPreSharedKey()获取热点密码Future<String?>
setWiFiAPPreSharedKey()设置热点密码passwordFuture<void>
getClientList()获取已连接客户端Future<List?>

核心代码

Dart 层入口

这一段在 lib/wifi_iot.dart 里。

class WiFiForIoTPlugin {
  static const MethodChannel _channel = MethodChannel('wifi_iot');
  static const EventChannel _eventChannel = EventChannel('plugins.wififlutter.io/wifi_scan');

  static Future<bool?> isEnabled() async {
    return await _channel.invokeMethod('isEnabled');
  }

  static Future<void> setEnabled({bool shouldOpenSettings = false}) async {
    await _channel.invokeMethod('setEnabled', <String, dynamic>{
      'shouldOpenSettings': shouldOpenSettings,
    });
  }

  static Future<bool?> connect({
    required String ssid,
    String? password,
    String? security,
    bool joinOnce = true,
    bool isHidden = false,
    int timeoutInSeconds = 30,
  }) async {
    return await _channel.invokeMethod('connect', <String, dynamic>{
      'ssid': ssid,
      'password': password,
      'security': security,
      'join_once': joinOnce,
      'is_hidden': isHidden,
      'timeout_in_seconds': timeoutInSeconds,
    });
  }

  static Future<bool?> disconnect() async {
    return await _channel.invokeMethod('disconnect');
  }

  static Future<String?> getSSID() async {
    return await _channel.invokeMethod('getSSID');
  }

  static Future<String?> getBSSID() async {
    return await _channel.invokeMethod('getBSSID');
  }

  static Future<int?> getCurrentSignalStrength() async {
    return await _channel.invokeMethod('getCurrentSignalStrength');
  }

  static Future<int?> getFrequency() async {
    return await _channel.invokeMethod('getFrequency');
  }

  static Future<String?> getIP() async {
    return await _channel.invokeMethod('getIP');
  }
}

MethodChannel 的通道名固定为 wifi_iot,EventChannel 为 plugins.wififlutter.io/wifi_scan,和各平台原生端保持一致。这一层是纯 Dart 代码,跨平台通用。

鸿蒙端 MethodCallHandlerImpl

文件在 ohos/src/main/ets/components/plugin/WifiIotPlugin.ets。

import {
  FlutterPlugin,
  FlutterPluginBinding,
  MethodCall,
  MethodCallHandler,
  MethodChannel,
  EventChannel,
  EventSink,
  StreamHandler,
  AbilityAware,
  AbilityPluginBinding,
} from '@ohos/flutter_ohos';
import { wifiManager } from '@kit.ConnectivityKit';
import { settings } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

export default class WifiIotPlugin implements FlutterPlugin, MethodCallHandler, StreamHandler, AbilityAware {
  private static readonly CHANNEL_NAME: string = "wifi_iot";
  private static readonly EVENT_CHANNEL_NAME: string = "plugins.wififlutter.io/wifi_scan";

  private methodChannel: MethodChannel | null = null;
  private eventChannel: EventChannel | null = null;
  private eventSink: EventSink | null = null;
  private scanStateCallback: ((value: number) => void) | null = null;
  private uiContext: common.UIAbilityContext | null = null;

  getUniqueClassName(): string {
    return "WifiIotPlugin";
  }

  onAttachedToEngine(binding: FlutterPluginBinding): void {
    this.methodChannel = new MethodChannel(binding.getBinaryMessenger(), WifiIotPlugin.CHANNEL_NAME);
    this.methodChannel.setMethodCallHandler(this);
    this.eventChannel = new EventChannel(binding.getBinaryMessenger(), WifiIotPlugin.EVENT_CHANNEL_NAME);
    this.eventChannel.setStreamHandler(this);
  }

  onDetachedFromEngine(binding: FlutterPluginBinding): void {
    this.unregisterScanListener();
    if (this.eventSink !== null) {
      this.eventSink.endOfStream();
    }
    if (this.methodChannel !== null) {
      this.methodChannel.setMethodCallHandler(null);
    }
    this.methodChannel = null;
    if (this.eventChannel !== null) {
      this.eventChannel.setStreamHandler(null);
    }
    this.eventChannel = null;
    this.eventSink = null;
    this.uiContext = null;
  }

  onAttachedToAbility(binding: AbilityPluginBinding): void {
    const ability = binding.getAbility();
    if (ability !== null && ability !== undefined) {
      this.uiContext = ability.context as common.UIAbilityContext;
    }
  }

  onDetachedFromAbility(): void {
    this.uiContext = null;
  }

  onMethodCall(call: MethodCall, result: MethodResult): void {
    switch (call.method) {
      case "isEnabled":
        this.handleIsEnabled(result);
        break;
      case "setEnabled":
        this.handleSetEnabled(call, result);
        break;
      case "connect":
        this.handleConnect(call, result);
        break;
      case "disconnect":
        this.handleDisconnect(result);
        break;
      case "getSSID":
        this.handleGetSSID(result);
        break;
      case "getBSSID":
        this.handleGetBSSID(result);
        break;
      case "getCurrentSignalStrength":
        this.handleGetCurrentSignalStrength(result);
        break;
      case "getFrequency":
        this.handleGetFrequency(result);
        break;
      case "getIP":
        this.handleGetIP(result);
        break;
      default:
        result.notImplemented();
        break;
    }
  }
}

这是鸿蒙适配的核心,实现了鸿蒙的 FlutterPlugin 接口。onAttachedToEngine 时创建 MethodChannel 和 EventChannel,onDetachedFromEngine 时解除注册,避免内存泄漏。

鸿蒙端 WiFi 连接实现

文件在 ohos/src/main/ets/components/plugin/WifiIotPlugin.ets。

private handleIsEnabled(result: MethodResult): void {
  try {
    result.success(wifiManager.isWifiActive());
  } catch (error) {
    result.success(false);
  }
}

private handleSetEnabled(call: MethodCall, result: MethodResult): void {
  const args = call.args as Map<string, Object> | null;
  const shouldOpenSettings = this.argBool(args, 'shouldOpenSettings', false);
  if (shouldOpenSettings) {
    this.openWlanSettings().then(() => {
      result.success(null);
    }).catch(() => {
      result.success(null);
    });
    return;
  }
  // Normal applications cannot turn the WLAN radio on/off programmatically on HarmonyOS.
  result.success(null);
}

private async openWlanSettings(): Promise<void> {
  if (this.uiContext === null) {
    return;
  }
  try {
    await settings.openNetworkManagerSettings(this.uiContext as common.Context);
  } catch (error) {
  }
}

private handleGetSSID(result: MethodResult): void {
  this.getLinkedInfoSafe().then((info: wifiManager.WifiLinkedInfo | null) => {
    if (info === null) {
      result.success(null);
      return;
    }
    result.success(info.ssid);
  });
}

private handleGetBSSID(result: MethodResult): void {
  this.getLinkedInfoSafe().then((info: wifiManager.WifiLinkedInfo | null) => {
    if (info === null) {
      result.success(null);
      return;
    }
    result.success(info.bssid.toUpperCase());
  });
}

private handleGetCurrentSignalStrength(result: MethodResult): void {
  this.getLinkedInfoSafe().then((info: wifiManager.WifiLinkedInfo | null) => {
    if (info === null) {
      result.success(null);
      return;
    }
    result.success(info.rssi);
  });
}

private handleGetFrequency(result: MethodResult): void {
  this.getLinkedInfoSafe().then((info: wifiManager.WifiLinkedInfo | null) => {
    if (info === null) {
      result.success(null);
      return;
    }
    result.success(info.frequency);
  });
}

private handleGetIP(result: MethodResult): void {
  try {
    const info: wifiManager.IpInfo = wifiManager.getIpInfo();
    result.success(this.ipNumberToString(info.ipAddress));
  } catch (error) {
    result.success(null);
  }
}

private async getLinkedInfoSafe(): Promise<wifiManager.WifiLinkedInfo | null> {
  try {
    return await wifiManager.getLinkedInfo();
  } catch (error) {
    return null;
  }
}

private ipNumberToString(ip: number): string {
  const b0 = ip & 0xFF;
  const b1 = (ip >> 8) & 0xFF;
  const b2 = (ip >> 16) & 0xFF;
  const b3 = (ip >> 24) & 0xFF;
  return b0 + '.' + b1 + '.' + b2 + '.' + b3;
}

把 Dart 发来的 isEnabled、setEnabled、connect、getSSID 等方法映射到鸿蒙 ArkUI 的 wifiManager API。连接信息通过 getLinkedInfo() 获取。

权限检查实现

文件在 ohos/src/main/ets/components/plugin/WifiIotPlugin.ets。

private isWifiActiveSafe(): boolean {
  try {
    return wifiManager.isWifiActive();
  } catch (error) {
    return false;
  }
}

连接实现

private async doConnect(call: MethodCall, result: MethodResult): Promise<void> {
  try {
    const args = call.args as Map<string, Object> | null;
    const ssid = this.argString(args, 'ssid');
    const password = this.argNullableString(args, 'password');
    const security = this.argNullableString(args, 'security');
    const joinOnce = this.argBool(args, 'join_once', true);
    const isHidden = this.argBool(args, 'is_hidden', false);
    const timeoutInSeconds = this.argInt(args, 'timeout_in_seconds', 30);
    
    if (ssid.length === 0 || ssid.length > 32) {
      result.success(false);
      return;
    }
    
    const securityType = this.securityToCode(security, password, result);
    if (securityType < 0) {
      return;
    }
    
    const ok = await this.connectToSsid(ssid, password, isHidden, securityType, timeoutInSeconds);
    if (ok && joinOnce) {
      await this.removeRecordedCandidates();
    }
    result.success(ok);
  } catch (error) {
    result.success(false);
  }
}

使用示例

引入依赖的时候鸿蒙必须用 git 分支,不能直接写版本号。

dependencies:
  flutter:
    sdk: flutter
  wifi_iot:
    git:
      url: "https://atomgit.com/oh-flutter/wifi_iot.git"
      ref: "0.3.19+2-ohos-1.0.0-beta.1"

在鸿蒙工程的 module.json5 中需要声明以下权限:

{
  "requestPermissions": [
    {
      "name": "ohos.permission.GET_WIFI_INFO"
    },
    {
      "name": "ohos.permission.SET_WIFI_INFO"
    }
  ]
}

基础 WiFi 连接调用示例:

import 'package:wifi_iot/wifi_iot.dart';

void _checkWifiStatus() async {
  // 检查WiFi是否启用
  final isEnabled = await WiFiForIoTPlugin.isEnabled();
  print('WiFi已启用: $isEnabled');
}

void _enableWifi() async {
  // 启用WiFi(在OpenHarmony上会打开设置页)
  await WiFiForIoTPlugin.setEnabled(shouldOpenSettings: true);
}

void _connectToWifi() async {
  // 连接到WiFi网络
  final connected = await WiFiForIoTPlugin.connect(
    ssid: "MyNetwork",
    password: "password123",
    security: "WPA",
  );
  print('连接结果: $connected');
}

void _getConnectionInfo() async {
  // 获取当前连接信息
  final ssid = await WiFiForIoTPlugin.getSSID();
  final bssid = await WiFiForIoTPlugin.getBSSID();
  final signalStrength = await WiFiForIoTPlugin.getCurrentSignalStrength();
  final frequency = await WiFiForIoTPlugin.getFrequency();
  final ip = await WiFiForIoTPlugin.getIP();
  
  print('SSID: $ssid');
  print('BSSID: $bssid');
  print('信号强度: $signalStrength dBm');
  print('频率: $frequency MHz');
  print('IP地址: $ip');
}

void _disconnectWifi() async {
  // 断开当前网络连接
  await WiFiForIoTPlugin.disconnect();
}

WiFi 热点功能示例

void _checkApStatus() async {
  // 检查热点是否启用
  final isEnabled = await WiFiForIoTPlugin.isWiFiAPEnabled();
  print('热点已启用: $isEnabled');
}

void _getApInfo() async {
  // 获取热点信息
  final ssid = await WiFiForIoTPlugin.getWiFiAPSSID();
  final password = await WiFiForIoTPlugin.getWiFiAPPreSharedKey();
  print('热点SSID: $ssid');
  print('热点密码: $password');
}

void _setApConfig() async {
  // 设置热点配置
  await WiFiForIoTPlugin.setWiFiAPSSID("MyHotspot");
  await WiFiForIoTPlugin.setWiFiAPPreSharedKey("12345678");
}

void _getClientList() async {
  // 获取已连接客户端列表
  final clients = await WiFiForIoTPlugin.getClientList();
  print('已连接客户端: $clients');
}

WiFiAccessPoint 数据结构

字段名类型描述OpenHarmony支持
SSIDStringWiFi网络的SSID(网络名称)
BSSIDStringWiFi接入点的BSSID(MAC地址)是(注意:无GET_WIFI_PEERS_MAC权限时可能为随机值)
capabilitiesString网络的安全能力描述
frequencyint频率(MHz)
levelint信号强度(dBm)
timestampint扫描时间戳(微秒)

连接状态枚举

描述OpenHarmony映射
已连接当前已连接到WiFi网络
正在连接正在连接WiFi网络
已断开当前未连接WiFi网络
未知连接状态未知

使用说明

启动 WiFi

调用 setEnabled() 触发 WiFi 开关操作。在 OpenHarmony 上,由于权限限制,会打开系统 WLAN 设置页面。

连接 WiFi 网络

调用 connect() 连接到指定的 WiFi 网络。支持 WPA/WEP 安全类型。

获取当前连接信息

调用 getSSID()、getBSSID()、getCurrentSignalStrength()、getFrequency()、getIP() 获取当前连接的详细信息。

断开连接

调用 disconnect() 断开当前 WiFi 网络连接。

热点功能

调用 isWiFiAPEnabled() 检查热点状态,setWiFiAPEnabled() 启用/禁用热点,getWiFiAPSSID() / setWiFiAPSSID() 获取/设置热点 SSID,getWiFiAPPreSharedKey() / setWiFiAPPreSharedKey() 获取/设置热点密码,getClientList() 获取已连接客户端列表。

OpenHarmony 平台差异说明

  • 普通应用程序无法在 HarmonyOS 上以编程方式打开/关闭 WLAN 无线装置。setEnabled() 将打开 WLAN 设置页面。
  • connect() 使用基于候选网络的方法,因为 HarmonyOS 不向普通应用暴露系统级网络注册。
  • 如果没有受限制的 ohos.permission.GET_WIFI_PEERS_MAC 权限,系统会返回随机化的 BSSID。
  • GET_WIFI_INFO 和 SET_WIFI_INFO 为 system_grant 权限,在安装时授予,无需运行时弹窗授权。

新增特性

  • 新增 OpenHarmony(ohos)平台支持,基于 @ohos.wifiManager 实现,与 Android/iOS 平台接口行为保持一致。
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐