fixed ios wifi part support. retry 11.
This commit is contained in:
1 parent
1c5946620f
commit
97c2a18c10
4 files changed
+125
-2
No files matched your search
@@ -106,6 +106,7 @@ WiFi options:
|
|||||||
- `hiddenSsid`:可选;Android 支持隐藏 SSID;iOS 15+ 会设置 `NEHotspotConfiguration.hidden`
|
- `hiddenSsid`:可选;Android 支持隐藏 SSID;iOS 15+ 会设置 `NEHotspotConfiguration.hidden`
|
||||||
- `bssid`:可选,仅 Android 10+ 临时连接使用
|
- `bssid`:可选,仅 Android 10+ 临时连接使用
|
||||||
- `joinOnce`:可选,仅 iOS;`connectWifi` 默认 `true`,`saveWifi` 默认 `false`
|
- `joinOnce`:可选,仅 iOS;`connectWifi` 默认 `true`,`saveWifi` 默认 `false`
|
||||||
|
- `iosReferenceFallback`:可选,仅 iOS,默认 `true`;当主实现返回 `NEHotspotConfigurationErrorDomain` code `8` 时,会按 `JGeraldoLima/cordova-wifi-plugin` 的最小 iOS 写法再尝试一次,用于区分本插件参数/分支问题和系统/API 问题
|
||||||
|
|
||||||
## Push Notifications
|
## Push Notifications
|
||||||
|
|
||||||
@@ -215,6 +216,8 @@ iOS WiFi:
|
|||||||
- 插件会向 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 返回 `NEHotspotConfigurationErrorDomain` code `8` / `internal error`,优先检查 App ID、entitlements、provisioning profile 是否都包含 `Hotspot Configuration`,并确认是在真机前台运行,不是在模拟器中测试。若签名和参数都正确,常见原因是真实热点使用 WPA2/WPA3 transition mode、WPA3 Personal、iPhone Personal Hotspot 默认安全模式,或其他 `NEHotspotConfiguration` 无法表达的 WiFi 能力。
|
- 如果 iOS 返回 `NEHotspotConfigurationErrorDomain` code `8` / `internal error`,优先检查 App ID、entitlements、provisioning profile 是否都包含 `Hotspot Configuration`,并确认是在真机前台运行,不是在模拟器中测试。若签名和参数都正确,常见原因是真实热点使用 WPA2/WPA3 transition mode、WPA3 Personal、iPhone Personal Hotspot 默认安全模式,或其他 `NEHotspotConfiguration` 无法表达的 WiFi 能力。
|
||||||
- iOS 错误结果会包含 `applicationState`、`ssidUtf8Length`、`passwordUtf8Length`、`passwordAsciiPrintable` 等诊断字段;WPA/WPA2 密码建议使用 8-63 位可打印 ASCII 字符。
|
- iOS 错误结果会包含 `applicationState`、`ssidUtf8Length`、`passwordUtf8Length`、`passwordAsciiPrintable` 等诊断字段;WPA/WPA2 密码建议使用 8-63 位可打印 ASCII 字符。
|
||||||
|
- iOS 错误结果会包含 `pluginVersion`,用于确认 IPA 中实际运行的原生插件版本。
|
||||||
|
- iOS code `8` 会自动启用 `iosReferenceFallback`。该 fallback 改编自 MIT 许可的 `JGeraldoLima/cordova-wifi-plugin`,只使用 `NEHotspotConfiguration(ssid:passphrase:isWEP:false)`、`joinOnce=false`,不设置 `hidden`,并会返回 `referenceNativeCode` / `referenceNativeError` 供对照。
|
||||||
- iOS 的 `NEHotspotConfiguration` password initializer 公开支持 WEP/WPA/WPA2 Personal,不提供 WPA3 Personal 参数。iOS 传入 `security` 包含 `wpa3` 时会返回 `UNSUPPORTED_WIFI_SECURITY`。WPA2/WPA3 mixed 通常只能按 `security: "wpa2"` 尝试;如果仍失败,需要用户手动加入,或改用配置描述文件/MDM 流程。
|
- iOS 的 `NEHotspotConfiguration` password initializer 公开支持 WEP/WPA/WPA2 Personal,不提供 WPA3 Personal 参数。iOS 传入 `security` 包含 `wpa3` 时会返回 `UNSUPPORTED_WIFI_SECURITY`。WPA2/WPA3 mixed 通常只能按 `security: "wpa2"` 尝试;如果仍失败,需要用户手动加入,或改用配置描述文件/MDM 流程。
|
||||||
- iOS 不提供第三方 App 断开当前 WiFi 的公开 API,因此 `disconnectWifi` 在 iOS 返回错误。
|
- iOS 不提供第三方 App 断开当前 WiFi 的公开 API,因此 `disconnectWifi` 在 iOS 返回错误。
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "bluememe-utils",
|
"name": "bluememe-utils",
|
||||||
"version": "0.1.9",
|
"version": "0.1.11",
|
||||||
"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": [
|
||||||
|
|||||||
+2
-1
@@ -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.9">
|
version="0.1.11">
|
||||||
<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>
|
||||||
@@ -108,6 +108,7 @@
|
|||||||
<header-file src="src/ios/CDVBluememeUtils.h" />
|
<header-file src="src/ios/CDVBluememeUtils.h" />
|
||||||
<source-file src="src/ios/CDVBluememeUtils.m" />
|
<source-file src="src/ios/CDVBluememeUtils.m" />
|
||||||
<framework src="NetworkExtension.framework" />
|
<framework src="NetworkExtension.framework" />
|
||||||
|
<framework src="SystemConfiguration.framework" />
|
||||||
<framework src="LocalAuthentication.framework" />
|
<framework src="LocalAuthentication.framework" />
|
||||||
<framework src="UserNotifications.framework" />
|
<framework src="UserNotifications.framework" />
|
||||||
<podspec>
|
<podspec>
|
||||||
|
|||||||
@@ -3,10 +3,12 @@
|
|||||||
#import <FirebaseCore/FirebaseCore.h>
|
#import <FirebaseCore/FirebaseCore.h>
|
||||||
#import <LocalAuthentication/LocalAuthentication.h>
|
#import <LocalAuthentication/LocalAuthentication.h>
|
||||||
#import <NetworkExtension/NetworkExtension.h>
|
#import <NetworkExtension/NetworkExtension.h>
|
||||||
|
#import <SystemConfiguration/CaptiveNetwork.h>
|
||||||
#import <TargetConditionals.h>
|
#import <TargetConditionals.h>
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
static NSString * const BluememeDeviceKeyDefaultsKey = @"bluememe_utils_device_key";
|
static NSString * const BluememeDeviceKeyDefaultsKey = @"bluememe_utils_device_key";
|
||||||
|
static NSString * const BluememeUtilsPluginVersion = @"0.1.11";
|
||||||
|
|
||||||
@interface CDVBluememeUtils ()
|
@interface CDVBluememeUtils ()
|
||||||
@property (nonatomic, copy) NSString *notificationCallbackId;
|
@property (nonatomic, copy) NSString *notificationCallbackId;
|
||||||
@@ -294,6 +296,7 @@ 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 referenceFallback = [self boolFromDictionary:options key:@"iosReferenceFallback" defaultValue:YES];
|
||||||
NSString *applicationState = [self applicationStateName];
|
NSString *applicationState = [self applicationStateName];
|
||||||
|
|
||||||
if (ssid.length == 0) {
|
if (ssid.length == 0) {
|
||||||
@@ -368,13 +371,25 @@ static NSString * const BluememeDeviceKeyDefaultsKey = @"bluememe_utils_device_k
|
|||||||
@"ssidUtf8Length": @([ssid lengthOfBytesUsingEncoding:NSUTF8StringEncoding]),
|
@"ssidUtf8Length": @([ssid lengthOfBytesUsingEncoding:NSUTF8StringEncoding]),
|
||||||
@"joinOnce": @(joinOnce),
|
@"joinOnce": @(joinOnce),
|
||||||
@"hiddenSsid": @(hiddenSsid),
|
@"hiddenSsid": @(hiddenSsid),
|
||||||
|
@"iosReferenceFallback": @(referenceFallback),
|
||||||
@"minimumIos": @"15.0",
|
@"minimumIos": @"15.0",
|
||||||
@"applicationState": applicationState
|
@"applicationState": applicationState
|
||||||
};
|
};
|
||||||
|
if (referenceFallback
|
||||||
|
&& [error.domain isEqualToString:NEHotspotConfigurationErrorDomain]
|
||||||
|
&& error.code == 8) {
|
||||||
|
[self applyReferenceWifiFallbackForCommand:command
|
||||||
|
ssid:ssid
|
||||||
|
password:password
|
||||||
|
primaryError:error
|
||||||
|
context:context];
|
||||||
|
return;
|
||||||
|
}
|
||||||
[self sendWifiApplyErrorForCommand:command error:error context:context];
|
[self sendWifiApplyErrorForCommand:command error:error context:context];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NSDictionary *result = @{
|
NSDictionary *result = @{
|
||||||
|
@"pluginVersion": BluememeUtilsPluginVersion,
|
||||||
@"ssid": ssid,
|
@"ssid": ssid,
|
||||||
@"platformMode": @"hotspotConfiguration",
|
@"platformMode": @"hotspotConfiguration",
|
||||||
@"connected": @YES,
|
@"connected": @YES,
|
||||||
@@ -396,6 +411,71 @@ static NSString * const BluememeDeviceKeyDefaultsKey = @"bluememe_utils_device_k
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Diagnostic fallback adapted from https://github.com/JGeraldoLima/cordova-wifi-plugin.
|
||||||
|
// Original project copyright (c) 2018 Jose Geraldo de Lima Junior, MIT License.
|
||||||
|
// It intentionally mirrors that plugin's minimal iOS path: passphrase initializer,
|
||||||
|
// isWEP=false, joinOnce=false, no hidden SSID setting.
|
||||||
|
- (void)applyReferenceWifiFallbackForCommand:(CDVInvokedUrlCommand *)command
|
||||||
|
ssid:(NSString *)ssid
|
||||||
|
password:(NSString *)password
|
||||||
|
primaryError:(NSError *)primaryError
|
||||||
|
context:(NSDictionary *)context API_AVAILABLE(ios(15.0))
|
||||||
|
{
|
||||||
|
NEHotspotConfiguration *configuration = nil;
|
||||||
|
if (password.length == 0) {
|
||||||
|
configuration = [[NEHotspotConfiguration alloc] initWithSSID:ssid];
|
||||||
|
} else {
|
||||||
|
configuration = [[NEHotspotConfiguration alloc] initWithSSID:ssid passphrase:password isWEP:NO];
|
||||||
|
}
|
||||||
|
configuration.joinOnce = NO;
|
||||||
|
|
||||||
|
[[NEHotspotConfigurationManager sharedManager] applyConfiguration:configuration completionHandler:^(NSError *fallbackError) {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
NSString *currentSSID = [self currentWifiSSID];
|
||||||
|
if (fallbackError == nil || fallbackError.code == NEHotspotConfigurationErrorAlreadyAssociated) {
|
||||||
|
NSMutableDictionary *result = [@{
|
||||||
|
@"pluginVersion": BluememeUtilsPluginVersion,
|
||||||
|
@"ssid": ssid,
|
||||||
|
@"platformMode": @"hotspotConfigurationReferenceFallback",
|
||||||
|
@"connected": @YES,
|
||||||
|
@"saved": @YES,
|
||||||
|
@"joinOnce": @NO,
|
||||||
|
@"iosReferenceFallback": @YES,
|
||||||
|
@"referenceFallbackSource": @"JGeraldoLima/cordova-wifi-plugin",
|
||||||
|
@"alreadyAssociated": @(fallbackError != nil && fallbackError.code == NEHotspotConfigurationErrorAlreadyAssociated)
|
||||||
|
} mutableCopy];
|
||||||
|
if (currentSSID.length > 0) {
|
||||||
|
result[@"currentSSID"] = currentSSID;
|
||||||
|
result[@"currentSSIDMatches"] = @([currentSSID isEqualToString:ssid]);
|
||||||
|
}
|
||||||
|
if (primaryError != nil) {
|
||||||
|
[self addWifiErrorDetailsForError:primaryError toDictionary:result prefix:@"primary"];
|
||||||
|
}
|
||||||
|
[self sendSuccessForCommand:command dictionary:result];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableDictionary *details = context == nil ? [NSMutableDictionary dictionary] : [context mutableCopy];
|
||||||
|
details[@"iosReferenceFallback"] = @YES;
|
||||||
|
details[@"referenceFallbackSource"] = @"JGeraldoLima/cordova-wifi-plugin";
|
||||||
|
details[@"referenceJoinOnce"] = @NO;
|
||||||
|
if (currentSSID.length > 0) {
|
||||||
|
details[@"currentSSID"] = currentSSID;
|
||||||
|
details[@"currentSSIDMatches"] = @([currentSSID isEqualToString:ssid]);
|
||||||
|
}
|
||||||
|
if (primaryError != nil) {
|
||||||
|
[self addWifiErrorDetailsForError:primaryError toDictionary:details prefix:@"primary"];
|
||||||
|
}
|
||||||
|
[self addWifiErrorDetailsForError:fallbackError toDictionary:details prefix:@"reference"];
|
||||||
|
|
||||||
|
[self sendErrorForCommand:command
|
||||||
|
code:@"WIFI_CONNECT_FAILED"
|
||||||
|
message:@"Primary iOS WiFi configuration failed, and the reference cordova-wifi-plugin fallback failed as well."
|
||||||
|
details:details];
|
||||||
|
});
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
- (NSString *)applicationStateName
|
- (NSString *)applicationStateName
|
||||||
{
|
{
|
||||||
UIApplicationState state = [[UIApplication sharedApplication] applicationState];
|
UIApplicationState state = [[UIApplication sharedApplication] applicationState];
|
||||||
@@ -426,6 +506,44 @@ static NSString * const BluememeDeviceKeyDefaultsKey = @"bluememe_utils_device_k
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)addWifiErrorDetailsForError:(NSError *)error toDictionary:(NSMutableDictionary *)dictionary prefix:(NSString *)prefix
|
||||||
|
{
|
||||||
|
if (error == nil || dictionary == nil || prefix.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *domainKey = [NSString stringWithFormat:@"%@NativeDomain", prefix];
|
||||||
|
NSString *codeKey = [NSString stringWithFormat:@"%@NativeCode", prefix];
|
||||||
|
NSString *errorKey = [NSString stringWithFormat:@"%@NativeError", prefix];
|
||||||
|
NSString *messageKey = [NSString stringWithFormat:@"%@NativeMessage", prefix];
|
||||||
|
|
||||||
|
if (error.domain.length > 0) {
|
||||||
|
dictionary[domainKey] = error.domain;
|
||||||
|
}
|
||||||
|
dictionary[codeKey] = @(error.code);
|
||||||
|
|
||||||
|
NSString *nativeError = [self hotspotConfigurationErrorNameForCode:error.code];
|
||||||
|
if (nativeError.length > 0) {
|
||||||
|
dictionary[errorKey] = nativeError;
|
||||||
|
}
|
||||||
|
if (error.localizedDescription.length > 0) {
|
||||||
|
dictionary[messageKey] = error.localizedDescription;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)currentWifiSSID
|
||||||
|
{
|
||||||
|
NSArray *interfaces = CFBridgingRelease(CNCopySupportedInterfaces());
|
||||||
|
for (id interface in interfaces) {
|
||||||
|
NSDictionary *networkInfo = CFBridgingRelease(CNCopyCurrentNetworkInfo((__bridge CFStringRef)interface));
|
||||||
|
NSString *ssid = [networkInfo objectForKey:(__bridge NSString *)kCNNetworkInfoKeySSID];
|
||||||
|
if (ssid.length > 0) {
|
||||||
|
return ssid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return @"";
|
||||||
|
}
|
||||||
|
|
||||||
- (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];
|
||||||
@@ -837,6 +955,7 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
|
|||||||
- (void)sendErrorForCommand:(CDVInvokedUrlCommand *)command code:(NSString *)code message:(NSString *)message details:(NSDictionary *)details
|
- (void)sendErrorForCommand:(CDVInvokedUrlCommand *)command code:(NSString *)code message:(NSString *)message details:(NSDictionary *)details
|
||||||
{
|
{
|
||||||
NSMutableDictionary *error = details == nil ? [NSMutableDictionary dictionary] : [details mutableCopy];
|
NSMutableDictionary *error = details == nil ? [NSMutableDictionary dictionary] : [details mutableCopy];
|
||||||
|
error[@"pluginVersion"] = BluememeUtilsPluginVersion;
|
||||||
error[@"code"] = code ? code : @"ERROR";
|
error[@"code"] = code ? code : @"ERROR";
|
||||||
error[@"message"] = message ? message : @"";
|
error[@"message"] = message ? message : @"";
|
||||||
CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:error];
|
CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:error];
|
||||||
|
|||||||
Reference in new issue
Block a user