fixed ios wifi part support. retry 4.

This commit is contained in:
aria committed 2026-04-22 20:29:17 +09:00
1 parent f499351b21
commit 87ba9a928b
4 files changed
+36 -118

No files matched your search

-2
View File
@@ -104,7 +104,6 @@ WiFi options:
- `password`:开放网络可省略 - `password`:开放网络可省略
- `security`:`open`、`wep`、`wpa2`、`wpa3`,默认按是否存在 password 推断为 `open` 或 `wpa2` - `security`:`open`、`wep`、`wpa2`、`wpa3`,默认按是否存在 password 推断为 `open` 或 `wpa2`
- `hiddenSsid`:可选;Android 支持隐藏 SSID;iOS 13+ 会设置 `NEHotspotConfiguration.hidden` - `hiddenSsid`:可选;Android 支持隐藏 SSID;iOS 13+ 会设置 `NEHotspotConfiguration.hidden`
- `resetExisting`:可选,仅 iOS,默认 `true`;应用 WiFi 配置前会移除本 App 以前写入过的同 SSID 配置,再重新应用
- `bssid`:可选,仅 Android 10+ 临时连接使用 - `bssid`:可选,仅 Android 10+ 临时连接使用
- `joinOnce`:可选,仅 iOS;`connectWifi` 默认 `true`,`saveWifi` 默认 `false` - `joinOnce`:可选,仅 iOS;`connectWifi` 默认 `true`,`saveWifi` 默认 `false`
@@ -213,7 +212,6 @@ iOS WiFi:
- 使用 `NEHotspotConfiguration`。 - 使用 `NEHotspotConfiguration`。
- 插件会向 Cordova iOS entitlements 写入 `com.apple.developer.networking.HotspotConfiguration`,但仍必须在 Apple Developer App ID 中开启 `Hotspot Configuration` capability,并使用包含该 capability 的 provisioning profile 重新构建。 - 插件会向 Cordova iOS entitlements 写入 `com.apple.developer.networking.HotspotConfiguration`,但仍必须在 Apple Developer App ID 中开启 `Hotspot Configuration` capability,并使用包含该 capability 的 provisioning profile 重新构建。
- iOS 调用会在主线程执行。默认会先查询本 App 已配置的 SSID,如果同名 SSID 存在,会先移除该 App 写入的旧配置再重新应用,以规避 iOS 内部状态导致的 `NEHotspotConfigurationErrorInternal`。
- 如果 iOS 返回 `NEHotspotConfigurationErrorDomain` code `8` / `internal error`,优先检查 App ID、entitlements、provisioning profile 是否都包含 `Hotspot Configuration`,并确认是在真机前台运行,不是在模拟器中测试。 - 如果 iOS 返回 `NEHotspotConfigurationErrorDomain` code `8` / `internal error`,优先检查 App ID、entitlements、provisioning profile 是否都包含 `Hotspot Configuration`,并确认是在真机前台运行,不是在模拟器中测试。
- iOS 的 `NEHotspotConfiguration` password initializer 公开支持 WEP/WPA/WPA2 Personal。WPA2/WPA3 mixed 通常应先按 `security: "wpa2"` 测试;如果 WPA2-only 可用但 mixed 不可用,需要调整热点兼容性配置或改用配置描述文件/MDM 流程。 - iOS 的 `NEHotspotConfiguration` password initializer 公开支持 WEP/WPA/WPA2 Personal。WPA2/WPA3 mixed 通常应先按 `security: "wpa2"` 测试;如果 WPA2-only 可用但 mixed 不可用,需要调整热点兼容性配置或改用配置描述文件/MDM 流程。
- iOS 不提供第三方 App 断开当前 WiFi 的公开 API,因此 `disconnectWifi` 在 iOS 返回错误。 - iOS 不提供第三方 App 断开当前 WiFi 的公开 API,因此 `disconnectWifi` 在 iOS 返回错误。
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "bluememe-utils", "name": "bluememe-utils",
"version": "0.1.3", "version": "0.1.4",
"description": "Cordova utilities for WiFi, Firebase Cloud Messaging, and biometric unlock for OutSystems 11 apps.", "description": "Cordova utilities for WiFi, Firebase Cloud Messaging, and biometric unlock for OutSystems 11 apps.",
"license": "MIT", "license": "MIT",
"files": [ "files": [
+1 -1
View File
@@ -2,7 +2,7 @@
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" <plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
id="bluememe-utils" id="bluememe-utils"
version="0.1.3"> version="0.1.4">
<name>bluememe-utils</name> <name>bluememe-utils</name>
<description>Cordova utilities for WiFi, Firebase Cloud Messaging, and biometric unlock.</description> <description>Cordova utilities for WiFi, Firebase Cloud Messaging, and biometric unlock.</description>
<license>MIT</license> <license>MIT</license>
+34 -114
View File
@@ -282,13 +282,6 @@ static NSString * const BluememeDeviceKeyDefaultsKey = @"bluememe_utils_device_k
- (void)applyWifiCommand:(CDVInvokedUrlCommand *)command defaultJoinOnce:(BOOL)defaultJoinOnce - (void)applyWifiCommand:(CDVInvokedUrlCommand *)command defaultJoinOnce:(BOOL)defaultJoinOnce
{ {
if (![NSThread isMainThread]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self applyWifiCommand:command defaultJoinOnce:defaultJoinOnce];
});
return;
}
NSDictionary *options = [self firstDictionaryArgument:command]; NSDictionary *options = [self firstDictionaryArgument:command];
NSString *ssid = [self stringFromDictionary:options key:@"ssid"]; NSString *ssid = [self stringFromDictionary:options key:@"ssid"];
NSString *password = [self stringFromDictionary:options key:@"password"]; NSString *password = [self stringFromDictionary:options key:@"password"];
@@ -300,7 +293,6 @@ static NSString * const BluememeDeviceKeyDefaultsKey = @"bluememe_utils_device_k
BOOL isWep = [security isEqualToString:@"wep"] || [self boolFromDictionary:options key:@"isWep" defaultValue:NO]; BOOL isWep = [security isEqualToString:@"wep"] || [self boolFromDictionary:options key:@"isWep" defaultValue:NO];
BOOL joinOnce = [self boolFromDictionary:options key:@"joinOnce" defaultValue:defaultJoinOnce]; BOOL joinOnce = [self boolFromDictionary:options key:@"joinOnce" defaultValue:defaultJoinOnce];
BOOL hiddenSsid = [self boolFromDictionary:options key:@"hiddenSsid" defaultValue:NO]; BOOL hiddenSsid = [self boolFromDictionary:options key:@"hiddenSsid" defaultValue:NO];
BOOL resetExisting = [self boolFromDictionary:options key:@"resetExisting" defaultValue:YES];
if (ssid.length == 0) { if (ssid.length == 0) {
[self sendErrorForCommand:command code:@"INVALID_WIFI_OPTIONS" message:@"ssid is required."]; [self sendErrorForCommand:command code:@"INVALID_WIFI_OPTIONS" message:@"ssid is required."];
@@ -325,117 +317,45 @@ static NSString * const BluememeDeviceKeyDefaultsKey = @"bluememe_utils_device_k
#endif #endif
if (@available(iOS 11.0, *)) { if (@available(iOS 11.0, *)) {
NSDictionary *context = @{ NEHotspotConfiguration *configuration = nil;
@"ssid": ssid, if (isOpen) {
@"security": security, configuration = [[NEHotspotConfiguration alloc] initWithSSID:ssid];
@"passwordLength": @(password.length), } else {
@"joinOnce": @(joinOnce), configuration = [[NEHotspotConfiguration alloc] initWithSSID:ssid passphrase:password isWEP:isWep];
@"hiddenSsid": @(hiddenSsid), }
@"resetExisting": @(resetExisting) if (@available(iOS 13.0, *)) {
}; configuration.hidden = hiddenSsid;
[self prepareAndApplyWifiConfigurationForCommand:command }
ssid:ssid configuration.joinOnce = joinOnce;
password:password
isOpen:isOpen [[NEHotspotConfigurationManager sharedManager] applyConfiguration:configuration completionHandler:^(NSError *error) {
isWep:isWep dispatch_async(dispatch_get_main_queue(), ^{
joinOnce:joinOnce if (error != nil && error.code != NEHotspotConfigurationErrorAlreadyAssociated) {
hiddenSsid:hiddenSsid NSDictionary *context = @{
resetExisting:resetExisting @"ssid": ssid,
context:context]; @"security": security,
@"passwordLength": @(password.length),
@"joinOnce": @(joinOnce),
@"hiddenSsid": @(hiddenSsid)
};
[self sendWifiApplyErrorForCommand:command error:error context:context];
return;
}
NSDictionary *result = @{
@"ssid": ssid,
@"platformMode": @"hotspotConfiguration",
@"connected": @YES,
@"saved": @(!joinOnce),
@"alreadyAssociated": @(error != nil && error.code == NEHotspotConfigurationErrorAlreadyAssociated)
};
[self sendSuccessForCommand:command dictionary:result];
});
}];
} else { } else {
[self sendErrorForCommand:command code:@"UNSUPPORTED_IOS_VERSION" message:@"WiFi configuration requires iOS 11 or newer."]; [self sendErrorForCommand:command code:@"UNSUPPORTED_IOS_VERSION" message:@"WiFi configuration requires iOS 11 or newer."];
} }
} }
- (void)prepareAndApplyWifiConfigurationForCommand:(CDVInvokedUrlCommand *)command
ssid:(NSString *)ssid
password:(NSString *)password
isOpen:(BOOL)isOpen
isWep:(BOOL)isWep
joinOnce:(BOOL)joinOnce
hiddenSsid:(BOOL)hiddenSsid
resetExisting:(BOOL)resetExisting
context:(NSDictionary *)context API_AVAILABLE(ios(11.0))
{
NEHotspotConfigurationManager *manager = [NEHotspotConfigurationManager sharedManager];
if (!resetExisting) {
[self applyWifiConfigurationForCommand:command
manager:manager
ssid:ssid
password:password
isOpen:isOpen
isWep:isWep
joinOnce:joinOnce
hiddenSsid:hiddenSsid
context:context];
return;
}
[manager getConfiguredSSIDsWithCompletionHandler:^(NSArray<NSString *> *configuredSSIDs) {
BOOL configuredByApp = [configuredSSIDs containsObject:ssid];
NSMutableDictionary *updatedContext = [context mutableCopy];
updatedContext[@"configuredByApp"] = @(configuredByApp);
void (^apply)(void) = ^{
[self applyWifiConfigurationForCommand:command
manager:manager
ssid:ssid
password:password
isOpen:isOpen
isWep:isWep
joinOnce:joinOnce
hiddenSsid:hiddenSsid
context:updatedContext];
};
if (configuredByApp) {
[manager removeConfigurationForSSID:ssid];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(500 * NSEC_PER_MSEC)), dispatch_get_main_queue(), apply);
} else {
dispatch_async(dispatch_get_main_queue(), apply);
}
}];
}
- (void)applyWifiConfigurationForCommand:(CDVInvokedUrlCommand *)command
manager:(NEHotspotConfigurationManager *)manager
ssid:(NSString *)ssid
password:(NSString *)password
isOpen:(BOOL)isOpen
isWep:(BOOL)isWep
joinOnce:(BOOL)joinOnce
hiddenSsid:(BOOL)hiddenSsid
context:(NSDictionary *)context API_AVAILABLE(ios(11.0))
{
NEHotspotConfiguration *configuration = nil;
if (isOpen) {
configuration = [[NEHotspotConfiguration alloc] initWithSSID:ssid];
} else {
configuration = [[NEHotspotConfiguration alloc] initWithSSID:ssid passphrase:password isWEP:isWep];
}
if (@available(iOS 13.0, *)) {
configuration.hidden = hiddenSsid;
}
configuration.joinOnce = joinOnce;
[manager applyConfiguration:configuration completionHandler:^(NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error != nil && error.code != NEHotspotConfigurationErrorAlreadyAssociated) {
[self sendWifiApplyErrorForCommand:command error:error context:context];
return;
}
NSDictionary *result = @{
@"ssid": ssid,
@"platformMode": @"hotspotConfiguration",
@"connected": @YES,
@"saved": @(!joinOnce),
@"alreadyAssociated": @(error != nil && error.code == NEHotspotConfigurationErrorAlreadyAssociated)
};
[self sendSuccessForCommand:command dictionary:result];
});
}];
}
- (void)sendWifiApplyErrorForCommand:(CDVInvokedUrlCommand *)command error:(NSError *)error context:(NSDictionary *)context - (void)sendWifiApplyErrorForCommand:(CDVInvokedUrlCommand *)command error:(NSError *)error context:(NSDictionary *)context
{ {
NSMutableDictionary *details = [NSMutableDictionary dictionary]; NSMutableDictionary *details = [NSMutableDictionary dictionary];