Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
92735af955 | ||
|
|
41739ef881 |
No files matched your search
@@ -19,12 +19,14 @@
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"plugin": {
|
"plugin": {
|
||||||
"url": "https://<your-git-host>/cordova-plugin-bluememe-wifi-connector.git#v1.0.0"
|
"url": "git+https://<your-git-host>/cordova-plugin-bluememe-wifi-connector.git#v1.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
如果你直接使用当前仓库作为插件仓库,把 `<your-git-host>` 换成你的 Git 地址即可。
|
这里要使用 `git+https://` 前缀,让 Cordova 按 Git 仓库而不是普通下载地址处理这个 URL。
|
||||||
|
|
||||||
|
如果你直接使用当前仓库作为插件仓库,把 `<your-git-host>` 换成你的 Git 地址即可;开发阶段也可以临时写成 `#main`,正式发布建议固定到 tag。
|
||||||
|
|
||||||
## JavaScript 调用
|
## JavaScript 调用
|
||||||
|
|
||||||
@@ -45,6 +47,8 @@ document.addEventListener("deviceready", function () {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
iOS 成功时会额外返回 `connectionSucceeded`、`connectionStatus` 和 `details`。其中 `details` 会包含 `configuredSSIDs`、`requestedSSIDConfiguredByApp`、`passphraseLength` 等诊断字段;失败时同样会把输入摘要和 native 错误信息放进 `error.details`,便于定位是参数问题还是系统拒绝。
|
||||||
|
|
||||||
## 推荐模式
|
## 推荐模式
|
||||||
|
|
||||||
### 1. 设备级保存网络
|
### 1. 设备级保存网络
|
||||||
|
|||||||
+175
-24
@@ -23,7 +23,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
NSString *message = [NSString stringWithFormat:@"Mode '%@' is not supported on iOS. Use 'save' or 'localOnly'.", resolvedMode];
|
NSString *message = [NSString stringWithFormat:@"Mode '%@' is not supported on iOS. Use 'save' or 'localOnly'.", resolvedMode];
|
||||||
[self sendErrorCode:@"MODE_NOT_SUPPORTED" message:message details:nil command:command];
|
[self sendErrorCode:@"MODE_NOT_SUPPORTED"
|
||||||
|
message:message
|
||||||
|
details:@{
|
||||||
|
@"platform": @"ios",
|
||||||
|
@"requestedMode": requestedMode ?: @"",
|
||||||
|
@"resolvedMode": resolvedMode ?: @""
|
||||||
|
}
|
||||||
|
command:command];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)connectLocalOnly:(CDVInvokedUrlCommand *)command
|
- (void)connectLocalOnly:(CDVInvokedUrlCommand *)command
|
||||||
@@ -101,15 +108,22 @@
|
|||||||
{
|
{
|
||||||
if (@available(iOS 11.0, *)) {
|
if (@available(iOS 11.0, *)) {
|
||||||
NSString *ssid = [self stringForKey:@"ssid" inOptions:options];
|
NSString *ssid = [self stringForKey:@"ssid" inOptions:options];
|
||||||
|
NSString *security = [self normalizeSecurity:[self stringForKey:@"security" inOptions:options]];
|
||||||
|
NSMutableDictionary *requestDetails = [self requestDetailsForOptions:options
|
||||||
|
ssid:ssid
|
||||||
|
security:security
|
||||||
|
mode:mode
|
||||||
|
joinOnce:joinOnce];
|
||||||
|
|
||||||
if (ssid.length == 0) {
|
if (ssid.length == 0) {
|
||||||
|
requestDetails[@"invalidOption"] = @"ssid";
|
||||||
[self sendErrorCode:@"INVALID_OPTIONS"
|
[self sendErrorCode:@"INVALID_OPTIONS"
|
||||||
message:@"Missing required option: ssid"
|
message:@"Missing required option: ssid"
|
||||||
details:nil
|
details:requestDetails
|
||||||
command:command];
|
command:command];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *security = [self normalizeSecurity:[self stringForKey:@"security" inOptions:options]];
|
|
||||||
NEHotspotConfiguration *configuration = nil;
|
NEHotspotConfiguration *configuration = nil;
|
||||||
|
|
||||||
if ([security isEqualToString:@"OPEN"]) {
|
if ([security isEqualToString:@"OPEN"]) {
|
||||||
@@ -117,23 +131,36 @@
|
|||||||
} else if ([security isEqualToString:@"WPA2"]) {
|
} else if ([security isEqualToString:@"WPA2"]) {
|
||||||
NSString *passphrase = [self stringForKey:@"passphrase" inOptions:options];
|
NSString *passphrase = [self stringForKey:@"passphrase" inOptions:options];
|
||||||
if (passphrase.length == 0) {
|
if (passphrase.length == 0) {
|
||||||
|
requestDetails[@"invalidOption"] = @"passphrase";
|
||||||
[self sendErrorCode:@"INVALID_OPTIONS"
|
[self sendErrorCode:@"INVALID_OPTIONS"
|
||||||
message:@"Missing required option: passphrase"
|
message:@"Missing required option: passphrase"
|
||||||
details:nil
|
details:requestDetails
|
||||||
|
command:command];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (passphrase.length < 8 || passphrase.length > 63) {
|
||||||
|
requestDetails[@"invalidOption"] = @"passphrase";
|
||||||
|
requestDetails[@"validation"] = @"WPA2 passphrase must be between 8 and 63 characters.";
|
||||||
|
[self sendErrorCode:@"INVALID_OPTIONS"
|
||||||
|
message:@"Invalid passphrase length for WPA2 Wi-Fi."
|
||||||
|
details:requestDetails
|
||||||
command:command];
|
command:command];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
configuration = [[NEHotspotConfiguration alloc] initWithSSID:ssid passphrase:passphrase isWEP:NO];
|
configuration = [[NEHotspotConfiguration alloc] initWithSSID:ssid passphrase:passphrase isWEP:NO];
|
||||||
} else if ([security isEqualToString:@"WPA3"]) {
|
} else if ([security isEqualToString:@"WPA3"]) {
|
||||||
|
requestDetails[@"invalidOption"] = @"security";
|
||||||
[self sendErrorCode:@"MODE_NOT_SUPPORTED"
|
[self sendErrorCode:@"MODE_NOT_SUPPORTED"
|
||||||
message:@"iOS hotspot configuration supports OPEN, WEP, WPA, and WPA2. WPA3 is not exposed by this plugin on iOS."
|
message:@"iOS hotspot configuration supports OPEN, WEP, WPA, and WPA2. WPA3 is not exposed by this plugin on iOS."
|
||||||
details:nil
|
details:requestDetails
|
||||||
command:command];
|
command:command];
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
NSString *message = [NSString stringWithFormat:@"Unsupported security type on iOS: %@", security];
|
NSString *message = [NSString stringWithFormat:@"Unsupported security type on iOS: %@", security];
|
||||||
[self sendErrorCode:@"INVALID_SECURITY" message:message details:nil command:command];
|
requestDetails[@"invalidOption"] = @"security";
|
||||||
|
[self sendErrorCode:@"INVALID_SECURITY" message:message details:requestDetails command:command];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,26 +169,24 @@
|
|||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[[NEHotspotConfigurationManager sharedManager] applyConfiguration:configuration completionHandler:^(NSError * _Nullable error) {
|
[[NEHotspotConfigurationManager sharedManager] applyConfiguration:configuration completionHandler:^(NSError * _Nullable error) {
|
||||||
if (error != nil) {
|
if (error != nil && ![self isAlreadyAssociatedError:error]) {
|
||||||
[self sendNativeError:error code:@"IOS_WIFI_CONFIGURATION_FAILED" command:command];
|
[self sendNativeError:error
|
||||||
|
code:@"IOS_WIFI_CONFIGURATION_FAILED"
|
||||||
|
requestDetails:requestDetails
|
||||||
|
command:command];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSMutableDictionary *result = [@{
|
NSString *connectionStatus = error == nil ? @"APPLIED" : @"ALREADY_ASSOCIATED";
|
||||||
@"mode": mode,
|
[self sendApplyConfigurationSuccessForSSID:ssid
|
||||||
@"ssid": ssid,
|
security:security
|
||||||
@"apiName": @"NEHotspotConfigurationManager",
|
mode:mode
|
||||||
@"platform": @"ios",
|
joinOnce:joinOnce
|
||||||
@"joinOnce": @(joinOnce),
|
configuration:configuration
|
||||||
@"hidden": @(configuration.hidden),
|
requestDetails:requestDetails
|
||||||
@"saved": @(!joinOnce)
|
connectionStatus:connectionStatus
|
||||||
} mutableCopy];
|
nativeError:error
|
||||||
|
command:command];
|
||||||
if ([mode isEqualToString:@"localOnly"]) {
|
|
||||||
result[@"boundToProcess"] = @NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
[self sendSuccess:result command:command];
|
|
||||||
}];
|
}];
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -173,6 +198,99 @@
|
|||||||
command:command];
|
command:command];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSMutableDictionary *)requestDetailsForOptions:(NSDictionary *)options
|
||||||
|
ssid:(NSString *)ssid
|
||||||
|
security:(NSString *)security
|
||||||
|
mode:(NSString *)mode
|
||||||
|
joinOnce:(BOOL)joinOnce
|
||||||
|
{
|
||||||
|
NSString *passphrase = [self stringForKey:@"passphrase" inOptions:options];
|
||||||
|
BOOL hidden = [self boolForKey:@"hidden" inOptions:options defaultValue:NO];
|
||||||
|
NSMutableDictionary *details = [@{
|
||||||
|
@"platform": @"ios",
|
||||||
|
@"apiName": @"NEHotspotConfigurationManager",
|
||||||
|
@"resolvedMode": mode ?: @"",
|
||||||
|
@"security": security ?: @"",
|
||||||
|
@"joinOnce": @(joinOnce),
|
||||||
|
@"hidden": @(hidden),
|
||||||
|
@"ssidLength": @(ssid.length),
|
||||||
|
@"passphraseProvided": @(passphrase.length > 0),
|
||||||
|
@"systemVersion": [[NSProcessInfo processInfo] operatingSystemVersionString] ?: @""
|
||||||
|
} mutableCopy];
|
||||||
|
|
||||||
|
if (passphrase.length > 0) {
|
||||||
|
details[@"passphraseLength"] = @(passphrase.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options[@"localOnly"] != nil) {
|
||||||
|
details[@"localOnly"] = @([self boolForKey:@"localOnly" inOptions:options defaultValue:NO]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return details;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSMutableDictionary *)baseConnectionResultForSSID:(NSString *)ssid
|
||||||
|
security:(NSString *)security
|
||||||
|
mode:(NSString *)mode
|
||||||
|
joinOnce:(BOOL)joinOnce
|
||||||
|
configuration:(NEHotspotConfiguration *)configuration
|
||||||
|
requestDetails:(NSDictionary *)requestDetails
|
||||||
|
connectionStatus:(NSString *)connectionStatus
|
||||||
|
{
|
||||||
|
NSMutableDictionary *result = [@{
|
||||||
|
@"mode": mode ?: @"",
|
||||||
|
@"ssid": ssid ?: @"",
|
||||||
|
@"security": security ?: @"",
|
||||||
|
@"apiName": @"NEHotspotConfigurationManager",
|
||||||
|
@"platform": @"ios",
|
||||||
|
@"joinOnce": @(joinOnce),
|
||||||
|
@"hidden": @(configuration.hidden),
|
||||||
|
@"saved": @(!joinOnce),
|
||||||
|
@"connectionSucceeded": @YES,
|
||||||
|
@"connectionStatus": connectionStatus ?: @"UNKNOWN",
|
||||||
|
@"details": [requestDetails mutableCopy]
|
||||||
|
} mutableCopy];
|
||||||
|
|
||||||
|
if ([mode isEqualToString:@"localOnly"]) {
|
||||||
|
result[@"boundToProcess"] = @NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sendApplyConfigurationSuccessForSSID:(NSString *)ssid
|
||||||
|
security:(NSString *)security
|
||||||
|
mode:(NSString *)mode
|
||||||
|
joinOnce:(BOOL)joinOnce
|
||||||
|
configuration:(NEHotspotConfiguration *)configuration
|
||||||
|
requestDetails:(NSDictionary *)requestDetails
|
||||||
|
connectionStatus:(NSString *)connectionStatus
|
||||||
|
nativeError:(NSError * _Nullable)nativeError
|
||||||
|
command:(CDVInvokedUrlCommand *)command API_AVAILABLE(ios(11.0))
|
||||||
|
{
|
||||||
|
NSMutableDictionary *result = [self baseConnectionResultForSSID:ssid
|
||||||
|
security:security
|
||||||
|
mode:mode
|
||||||
|
joinOnce:joinOnce
|
||||||
|
configuration:configuration
|
||||||
|
requestDetails:requestDetails
|
||||||
|
connectionStatus:connectionStatus];
|
||||||
|
NSMutableDictionary *details = [result[@"details"] mutableCopy];
|
||||||
|
details[@"configurationApplied"] = @YES;
|
||||||
|
|
||||||
|
if (nativeError != nil) {
|
||||||
|
[details addEntriesFromDictionary:[self nativeErrorDetails:nativeError]];
|
||||||
|
}
|
||||||
|
|
||||||
|
[[NEHotspotConfigurationManager sharedManager] getConfiguredSSIDsWithCompletionHandler:^(NSArray<NSString *> * _Nonnull ssids) {
|
||||||
|
NSArray<NSString *> *configuredSsids = ssids ?: @[];
|
||||||
|
details[@"configuredSSIDs"] = configuredSsids;
|
||||||
|
details[@"requestedSSIDConfiguredByApp"] = @([configuredSsids containsObject:ssid]);
|
||||||
|
result[@"details"] = details;
|
||||||
|
[self sendSuccess:result command:command];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
- (NSDictionary *)optionsFromCommand:(CDVInvokedUrlCommand *)command
|
- (NSDictionary *)optionsFromCommand:(CDVInvokedUrlCommand *)command
|
||||||
{
|
{
|
||||||
if ([command.arguments count] == 0) {
|
if ([command.arguments count] == 0) {
|
||||||
@@ -279,19 +397,52 @@
|
|||||||
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)sendNativeError:(NSError *)error code:(NSString *)code command:(CDVInvokedUrlCommand *)command
|
- (NSDictionary *)nativeErrorDetails:(NSError *)error
|
||||||
{
|
{
|
||||||
NSMutableDictionary *details = [NSMutableDictionary dictionary];
|
NSMutableDictionary *details = [NSMutableDictionary dictionary];
|
||||||
if (error.domain.length > 0) {
|
if (error.domain.length > 0) {
|
||||||
details[@"domain"] = error.domain;
|
details[@"domain"] = error.domain;
|
||||||
}
|
}
|
||||||
details[@"nativeCode"] = @(error.code);
|
details[@"nativeCode"] = @(error.code);
|
||||||
|
if (error.localizedDescription.length > 0) {
|
||||||
|
details[@"nativeMessage"] = error.localizedDescription;
|
||||||
|
}
|
||||||
|
|
||||||
id failureReason = error.userInfo[NSLocalizedFailureReasonErrorKey];
|
id failureReason = error.userInfo[NSLocalizedFailureReasonErrorKey];
|
||||||
if ([failureReason isKindOfClass:[NSString class]] && [failureReason length] > 0) {
|
if ([failureReason isKindOfClass:[NSString class]] && [failureReason length] > 0) {
|
||||||
details[@"failureReason"] = failureReason;
|
details[@"failureReason"] = failureReason;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
id recoverySuggestion = error.userInfo[NSLocalizedRecoverySuggestionErrorKey];
|
||||||
|
if ([recoverySuggestion isKindOfClass:[NSString class]] && [recoverySuggestion length] > 0) {
|
||||||
|
details[@"recoverySuggestion"] = recoverySuggestion;
|
||||||
|
}
|
||||||
|
|
||||||
|
id debugDescription = error.userInfo[NSDebugDescriptionErrorKey];
|
||||||
|
if ([debugDescription isKindOfClass:[NSString class]] && [debugDescription length] > 0) {
|
||||||
|
details[@"debugDescription"] = debugDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
return details;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isAlreadyAssociatedError:(NSError *)error
|
||||||
|
{
|
||||||
|
return error != nil &&
|
||||||
|
[error.domain isEqualToString:NEHotspotConfigurationErrorDomain] &&
|
||||||
|
error.code == NEHotspotConfigurationErrorAlreadyAssociated;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sendNativeError:(NSError *)error
|
||||||
|
code:(NSString *)code
|
||||||
|
requestDetails:(NSDictionary *)requestDetails
|
||||||
|
command:(CDVInvokedUrlCommand *)command
|
||||||
|
{
|
||||||
|
NSMutableDictionary *details = [requestDetails mutableCopy] ?: [NSMutableDictionary dictionary];
|
||||||
|
[details addEntriesFromDictionary:[self nativeErrorDetails:error]];
|
||||||
|
details[@"connectionSucceeded"] = @NO;
|
||||||
|
details[@"connectionStatus"] = @"FAILED";
|
||||||
|
|
||||||
[self sendErrorCode:code
|
[self sendErrorCode:code
|
||||||
message:error.localizedDescription
|
message:error.localizedDescription
|
||||||
details:details
|
details:details
|
||||||
|
|||||||
Reference in new issue
Block a user