Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions packages/wifi_iot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,26 @@ Becareful, some commands as no effect on iOS because Apple don't let us to do wh

Additional Wifi protocols on Android side like - Wifi Direct, Wifi Aware, etc are in active discussion at [#140](https://github.com/flutternetwork/WiFiFlutter/issues/140). Encourage you to engage if you want this features.

## WPA2 and WPA3-Personal

Use `NetworkSecurity.WPA2` for password-protected WPA2 networks or
`NetworkSecurity.WPA3` for WPA3-Personal (SAE) networks. The existing
`NetworkSecurity.WPA` value keeps its WPA2 behavior. WPA3-Enterprise is not
supported by these password-based connection methods.

```dart
final connected = await WiFiForIoTPlugin.connect(
'My network',
password: 'My password',
security: NetworkSecurity.WPA3,
);
```

On Android, WPA3-Personal requires Android 10 or later and SAE support on the
device. `findAndConnect` falls back to WPA2 for WPA2/WPA3 transition networks
when the device does not support SAE. On iOS, WPA2 and WPA3 use the system's
password-based hotspot configuration.

## Access Point
| Description | Android | iOS |
| :------------------------------------------------------------------------------------ | :--------------------: | :------------------: |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,12 @@ private void registerWifiNetwork(final MethodCall poCall, final Result poResult)
String security = poCall.argument("security");
Boolean isHidden = poCall.argument("is_hidden");

if ("WPA3".equalsIgnoreCase(security)
&& (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || !moWiFi.isWpa3SaeSupported())) {
poResult.error("Error", "WPA3-Personal is not supported on this device", "");
return;
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
final WifiNetworkSuggestion.Builder suggestedNet = new WifiNetworkSuggestion.Builder();
suggestedNet.setSsid(ssid);
Expand All @@ -938,8 +944,11 @@ private void registerWifiNetwork(final MethodCall poCall, final Result poResult)
suggestedNet.setBssid(macAddress);
}

if (security != null && security.toUpperCase().equals("WPA")) {
if (security != null
&& (security.toUpperCase().equals("WPA") || security.toUpperCase().equals("WPA2"))) {
suggestedNet.setWpa2Passphrase(password);
} else if (security != null && security.toUpperCase().equals("WPA3")) {
suggestedNet.setWpa3Passphrase(password);
} else if (security != null && security.toUpperCase().equals("WEP")) {
// WEP is not supported
poResult.error(
Expand Down Expand Up @@ -1038,10 +1047,17 @@ public void run() {
}.start();
}

private static String getSecurityType(ScanResult scanResult) {
private String getSecurityType(ScanResult scanResult) {
String capabilities = scanResult.capabilities;

if (capabilities.contains("WPA")
if (capabilities.contains("SAE")) {
// Transition networks also advertise PSK; use it if SAE is unavailable.
if (capabilities.contains("PSK")
&& (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || !moWiFi.isWpa3SaeSupported())) {
return "WPA";
}
return "WPA3";
} else if (capabilities.contains("WPA")
|| capabilities.contains("WPA2")
|| capabilities.contains("WPA/WPA2 PSK")) {
return "WPA";
Expand Down Expand Up @@ -1267,6 +1283,11 @@ private void connectTo(
final Boolean isHidden,
final Integer timeoutInSeconds) {
final Handler handler = new Handler(Looper.getMainLooper());
if ("WPA3".equalsIgnoreCase(security)
&& (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || !moWiFi.isWpa3SaeSupported())) {
handler.post(() -> poResult.success(false));
return;
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
final boolean connected =
connectToDeprecated(ssid, bssid, password, security, joinOnce, isHidden);
Expand Down Expand Up @@ -1313,8 +1334,11 @@ public void run() {
}

// set password
if (security != null && security.toUpperCase().equals("WPA")) {
if (security != null
&& (security.toUpperCase().equals("WPA") || security.toUpperCase().equals("WPA2"))) {
builder.setWpa2Passphrase(password);
} else if (security != null && security.toUpperCase().equals("WPA3")) {
builder.setWpa3Passphrase(password);
}

// remove suggestions if already existing
Expand Down Expand Up @@ -1363,8 +1387,11 @@ public void run() {
}

// set security
if (security != null && security.toUpperCase().equals("WPA")) {
if (security != null
&& (security.toUpperCase().equals("WPA") || security.toUpperCase().equals("WPA2"))) {
builder.setWpa2Passphrase(password);
} else if (security != null && security.toUpperCase().equals("WPA3")) {
builder.setWpa3Passphrase(password);
}

final NetworkRequest networkRequest =
Expand Down Expand Up @@ -1467,8 +1494,7 @@ private android.net.wifi.WifiConfiguration generateConfiguration(
if (security != null) security = security.toUpperCase();
else security = "NONE";

if (security.toUpperCase().equals("WPA")) {

if (security.equals("WPA") || security.equals("WPA2")) {
/// appropriate ciper is need to set according to security type used,
/// ifcase of not added it will not be able to connect
conf.preSharedKey = "\"" + password + "\"";
Expand All @@ -1489,6 +1515,13 @@ private android.net.wifi.WifiConfiguration generateConfiguration(

conf.allowedProtocols.set(android.net.wifi.WifiConfiguration.Protocol.RSN);
conf.allowedProtocols.set(android.net.wifi.WifiConfiguration.Protocol.WPA);
} else if (security.equals("WPA3")) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
conf.preSharedKey = "\"" + password + "\"";
conf.allowedKeyManagement.set(android.net.wifi.WifiConfiguration.KeyMgmt.SAE);
conf.allowedProtocols.set(android.net.wifi.WifiConfiguration.Protocol.RSN);
conf.status = android.net.wifi.WifiConfiguration.Status.ENABLED;
}
} else if (security.equals("WEP")) {
conf.wepKeys[0] = "\"" + password + "\"";
conf.wepTxKeyIndex = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ public class WifiIotPlugin: NSObject, FlutterPlugin {
-> NEHotspotConfiguration
{
switch security?.uppercased() {
case "WPA":
case "WPA", "WPA2", "WPA3":
return NEHotspotConfiguration.init(ssid: ssid, passphrase: passphrase!, isWEP: false)
case "WEP":
return NEHotspotConfiguration.init(ssid: ssid, passphrase: passphrase!, isWEP: true)
Expand Down
10 changes: 7 additions & 3 deletions packages/wifi_iot/lib/wifi_iot.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ enum WIFI_AP_STATE {
WIFI_AP_STATE_FAILED,
}

enum NetworkSecurity { WPA, WEP, NONE }
enum NetworkSecurity { WPA, WEP, NONE, WPA2, WPA3 }

const serializeNetworkSecurityMap = <NetworkSecurity, String>{
NetworkSecurity.WPA: "WPA",
NetworkSecurity.WEP: "WEP",
NetworkSecurity.NONE: "NONE",
NetworkSecurity.WPA2: "WPA2",
NetworkSecurity.WPA3: "WPA3",
};

const MethodChannel _channel = const MethodChannel('wifi_iot');
Expand Down Expand Up @@ -320,7 +322,8 @@ class WiFiForIoTPlugin {
/// @param [security] The security type of the network. [NetworkSecurity.NONE]
/// means no password is required.
/// On Android, from version 10 (Q) onward, [NetworkSecurity.WEP] is no
/// longer supported.
/// longer supported. WPA3-Personal requires Android 10 (Q) or later and
/// a device that supports SAE. WPA remains an alias for WPA2.
///
/// @param [joinOnce] If true, the network will be removed on exit.
///
Expand Down Expand Up @@ -397,7 +400,8 @@ class WiFiForIoTPlugin {
/// @param [security] The security type of the network. [NetworkSecurity.NONE]
/// means no password is required.
/// On Android, from version 10 (Q) onward, [NetworkSecurity.WEP] is no
/// longer supported.
/// longer supported. WPA3-Personal requires Android 10 (Q) or later and
/// a device that supports SAE. WPA remains an alias for WPA2.
///
/// @param [isHidden] Whether the SSID is hidden (not broadcasted by the AP).
///
Expand Down
Loading