cordova.plugins.diagnostic 7.2.5 → 7.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +80 -55
- package/cordova.plugins.diagnostic.d.ts +9 -2
- package/package.json +1 -1
- package/plugin.xml +1 -1
- package/src/ios/Diagnostic_Wifi.m +119 -61
- package/www/android/diagnostic.js +2 -0
- package/www/ios/diagnostic.js +9 -5
- package/www/ios/diagnostic.wifi.js +28 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
**v7.2.7**
|
|
4
|
+
(ios) bugfix: Handle DNS PolicyDenied like EPERM for local network permission detection
|
|
5
|
+
|
|
6
|
+
**v7.2.6**
|
|
7
|
+
* (ios) fix: Local Network status check now accepts a configurable timeout, detects permission denials via NWBrowser errors/NSNetService failures, and returns `UNKNOWN` instead of `DENIED_ALWAYS` when the probe times out. This works around an issue where, if the network stack is under load, local network permission may be falsely reported as denied because iOS fails to resolve the Bonjour service within the default timeout period.
|
|
8
|
+
|
|
3
9
|
**v7.2.5**
|
|
4
10
|
* (ios) feat: add check/request local network authorization to Wifi module
|
|
5
11
|
* Resolves [#524](https://github.com/dpa99c/cordova-diagnostic-plugin/issues/524)
|
package/README.md
CHANGED
|
@@ -639,14 +639,17 @@ App can never ask for permission again.
|
|
|
639
639
|
The only way around this is to instruct the user to manually change the permission in Settings.
|
|
640
640
|
- `RESTRICTED` - Permission is unavailable and user cannot enable it.
|
|
641
641
|
For example, when parental controls are in effect for the current user.
|
|
642
|
-
- `GRANTED` - User granted access to this permission.
|
|
643
|
-
For location permission, this indicates the user has granted access to the permission "always" (when app is both in foreground and background).
|
|
644
|
-
- `GRANTED_WHEN_IN_USE` - Used only for location permission.
|
|
645
|
-
Indicates the user has granted access to the permission "when in use" (only when the app is in the foreground).
|
|
646
|
-
|
|
647
|
-
Addtionally, for notifications permissions:
|
|
648
|
-
- `PROVISIONAL` - The app is provisionally authorized to post non-interruptive user notifications.
|
|
649
|
-
- `EPHEMERAL` - The app is authorized to schedule or receive notifications for a limited amount of time.
|
|
642
|
+
- `GRANTED` - User granted access to this permission.
|
|
643
|
+
For location permission, this indicates the user has granted access to the permission "always" (when app is both in foreground and background).
|
|
644
|
+
- `GRANTED_WHEN_IN_USE` - Used only for location permission.
|
|
645
|
+
Indicates the user has granted access to the permission "when in use" (only when the app is in the foreground).
|
|
646
|
+
|
|
647
|
+
Addtionally, for notifications permissions:
|
|
648
|
+
- `PROVISIONAL` - The app is provisionally authorized to post non-interruptive user notifications.
|
|
649
|
+
- `EPHEMERAL` - The app is authorized to schedule or receive notifications for a limited amount of time.
|
|
650
|
+
|
|
651
|
+
For cases where the platform cannot return a definitive answer, the plugin also exposes:
|
|
652
|
+
- `UNKNOWN` (Android and iOS) - Returned when the underlying OS has not yet provided a concrete status (for example, if an iOS Local Network probe timed out). Treat this as a transient state and retry before surfacing a denial to the user.
|
|
650
653
|
|
|
651
654
|
#### Example
|
|
652
655
|
|
|
@@ -2455,61 +2458,80 @@ The function is passed a single string parameter containing the error message.
|
|
|
2455
2458
|
|
|
2456
2459
|
Platforms: iOS
|
|
2457
2460
|
|
|
2458
|
-
Checks if the app is authorised to access devices on the local network (iOS 14+).
|
|
2459
|
-
On iOS versions prior to 14 this will always return TRUE as no local network authorization is required.
|
|
2461
|
+
Checks if the app is authorised to access devices on the local network (iOS 14+).
|
|
2462
|
+
On iOS versions prior to 14 this will always return TRUE as no local network authorization is required.
|
|
2463
|
+
An optional third argument allows you to override the fallback timeout (defaults to 2 seconds) by passing `{ timeoutMs: <number> }`.
|
|
2460
2464
|
|
|
2461
2465
|
cordova.plugins.diagnostic.isLocalNetworkAuthorized(successCallback, errorCallback);
|
|
2462
2466
|
|
|
2463
|
-
#### Parameters
|
|
2464
|
-
|
|
2465
|
-
- {Function} successCallback - The callback which will be called when operation is successful.
|
|
2466
|
-
The function is passed a single boolean parameter which is TRUE if the app is authorised to use the Local Network.
|
|
2467
|
-
- {Function} errorCallback - The callback which will be called when operation encounters an error.
|
|
2468
|
-
The function is passed a single string parameter containing the error message.
|
|
2467
|
+
#### Parameters
|
|
2468
|
+
|
|
2469
|
+
- {Function} successCallback - The callback which will be called when operation is successful.
|
|
2470
|
+
The function is passed a single boolean parameter which is TRUE if the app is authorised to use the Local Network.
|
|
2471
|
+
- {Function} errorCallback - The callback which will be called when operation encounters an error.
|
|
2472
|
+
The function is passed a single string parameter containing the error message.
|
|
2473
|
+
- {Object} [options] - Optional timeout control object. Provide `timeoutMs` (milliseconds) to override the default 2000 ms timeout.
|
|
2469
2474
|
|
|
2470
2475
|
|
|
2471
2476
|
#### Example usage
|
|
2472
2477
|
|
|
2473
|
-
cordova.plugins.diagnostic.isLocalNetworkAuthorized(function(authorized){
|
|
2474
|
-
console.log("Local Network is " + (authorized ? "authorized" : "unauthorised"));
|
|
2475
|
-
}, function(error){
|
|
2476
|
-
console.error("The following error occurred: "+error);
|
|
2477
|
-
});
|
|
2478
|
+
cordova.plugins.diagnostic.isLocalNetworkAuthorized(function(authorized){
|
|
2479
|
+
console.log("Local Network is " + (authorized ? "authorized" : "unauthorised"));
|
|
2480
|
+
}, function(error){
|
|
2481
|
+
console.error("The following error occurred: "+error);
|
|
2482
|
+
});
|
|
2483
|
+
|
|
2484
|
+
To wait longer before treating a slow response as indeterminate:
|
|
2485
|
+
|
|
2486
|
+
```
|
|
2487
|
+
cordova.plugins.diagnostic.isLocalNetworkAuthorized(
|
|
2488
|
+
function(authorized){
|
|
2489
|
+
console.log("Local Network authorized? " + authorized);
|
|
2490
|
+
},
|
|
2491
|
+
console.error,
|
|
2492
|
+
{ timeoutMs: 8000 }
|
|
2493
|
+
);
|
|
2494
|
+
```
|
|
2478
2495
|
|
|
2479
2496
|
### getLocalNetworkAuthorizationStatus()
|
|
2480
2497
|
|
|
2481
2498
|
Platforms: iOS
|
|
2482
2499
|
|
|
2483
|
-
Returns the app's Local Network authorization status.
|
|
2484
|
-
On iOS 14+ this returns one of the values in `cordova.plugins.diagnostic.permissionStatus`: `NOT_REQUESTED`, `GRANTED`, `DENIED_ALWAYS`.
|
|
2485
|
-
|
|
2500
|
+
Returns the app's Local Network authorization status.
|
|
2501
|
+
On iOS 14+ this returns one of the values in `cordova.plugins.diagnostic.permissionStatus`: `NOT_REQUESTED`, `GRANTED`, `DENIED_ALWAYS`, `UNKNOWN`.
|
|
2502
|
+
`UNKNOWN` indicates that iOS did not return a definitive answer before the timeout elapsed, so the app can retry before warning the user.
|
|
2503
|
+
On iOS versions prior to 14 this will always return `GRANTED` as no authorization is required.
|
|
2486
2504
|
|
|
2487
2505
|
cordova.plugins.diagnostic.getLocalNetworkAuthorizationStatus(successCallback, errorCallback);
|
|
2488
2506
|
|
|
2489
2507
|
#### Parameters
|
|
2490
2508
|
|
|
2491
|
-
- {Function} successCallback - The callback which will be called when operation is successful.
|
|
2492
|
-
The function is passed a single string parameter which is one of the values in `cordova.plugins.diagnostic.permissionStatus`:
|
|
2493
|
-
`NOT_REQUESTED`, `GRANTED`, `DENIED_ALWAYS`.
|
|
2494
|
-
- {Function} errorCallback - The callback which will be called when operation encounters an error.
|
|
2495
|
-
The function is passed a single string parameter containing the error message.
|
|
2509
|
+
- {Function} successCallback - The callback which will be called when operation is successful.
|
|
2510
|
+
The function is passed a single string parameter which is one of the values in `cordova.plugins.diagnostic.permissionStatus`:
|
|
2511
|
+
`NOT_REQUESTED`, `GRANTED`, `DENIED_ALWAYS`, `UNKNOWN`.
|
|
2512
|
+
- {Function} errorCallback - The callback which will be called when operation encounters an error.
|
|
2513
|
+
The function is passed a single string parameter containing the error message.
|
|
2514
|
+
- {Object} [options] - Optional timeout override (defaults to 2 seconds). Provide `timeoutMs` (milliseconds) to customize the fallback duration.
|
|
2496
2515
|
|
|
2497
2516
|
|
|
2498
2517
|
#### Example usage
|
|
2499
2518
|
|
|
2500
2519
|
cordova.plugins.diagnostic.getLocalNetworkAuthorizationStatus(function(status){
|
|
2501
|
-
switch(status){
|
|
2502
|
-
case cordova.plugins.diagnostic.permissionStatus.NOT_REQUESTED:
|
|
2503
|
-
console.log("Local Network permission not requested");
|
|
2504
|
-
break;
|
|
2505
|
-
case cordova.plugins.diagnostic.permissionStatus.DENIED_ALWAYS:
|
|
2506
|
-
console.log("Local Network permission denied");
|
|
2507
|
-
break;
|
|
2508
|
-
case cordova.plugins.diagnostic.permissionStatus.
|
|
2509
|
-
console.log("Local Network permission
|
|
2510
|
-
break;
|
|
2511
|
-
|
|
2512
|
-
|
|
2520
|
+
switch(status){
|
|
2521
|
+
case cordova.plugins.diagnostic.permissionStatus.NOT_REQUESTED:
|
|
2522
|
+
console.log("Local Network permission not requested");
|
|
2523
|
+
break;
|
|
2524
|
+
case cordova.plugins.diagnostic.permissionStatus.DENIED_ALWAYS:
|
|
2525
|
+
console.log("Local Network permission denied");
|
|
2526
|
+
break;
|
|
2527
|
+
case cordova.plugins.diagnostic.permissionStatus.UNKNOWN:
|
|
2528
|
+
console.log("Local Network permission could not be determined (retry recommended)");
|
|
2529
|
+
break;
|
|
2530
|
+
case cordova.plugins.diagnostic.permissionStatus.GRANTED:
|
|
2531
|
+
console.log("Local Network permission granted");
|
|
2532
|
+
break;
|
|
2533
|
+
}
|
|
2534
|
+
}, function(error){
|
|
2513
2535
|
console.error("The following error occurred: "+error);
|
|
2514
2536
|
});
|
|
2515
2537
|
|
|
@@ -2517,31 +2539,34 @@ On iOS versions prior to 14 this will always return `GRANTED` as no authorizatio
|
|
|
2517
2539
|
|
|
2518
2540
|
Platforms: iOS
|
|
2519
2541
|
|
|
2520
|
-
Requests the user to authorise the app to access devices on the local network (iOS 14+).
|
|
2521
|
-
On iOS versions prior to 14 this does nothing and will return success as no authorization is required.
|
|
2542
|
+
Requests the user to authorise the app to access devices on the local network (iOS 14+).
|
|
2543
|
+
On iOS versions prior to 14 this does nothing and will return success as no authorization is required.
|
|
2544
|
+
May return `UNKNOWN` if iOS does not respond before the native APIs time out, allowing the app to retry.
|
|
2522
2545
|
|
|
2523
2546
|
cordova.plugins.diagnostic.requestLocalNetworkAuthorization(successCallback, errorCallback);
|
|
2524
2547
|
|
|
2525
2548
|
#### Parameters
|
|
2526
2549
|
|
|
2527
|
-
- {Function} successCallback - The callback which will be called when operation is successful.
|
|
2528
|
-
The function is passed a single string parameter which is one of the values in `cordova.plugins.diagnostic.permissionStatus`:
|
|
2529
|
-
`NOT_REQUESTED`, `GRANTED`, `DENIED_ALWAYS`.
|
|
2550
|
+
- {Function} successCallback - The callback which will be called when operation is successful.
|
|
2551
|
+
The function is passed a single string parameter which is one of the values in `cordova.plugins.diagnostic.permissionStatus`:
|
|
2552
|
+
`NOT_REQUESTED`, `GRANTED`, `DENIED_ALWAYS`, `UNKNOWN`.
|
|
2530
2553
|
- {Function} errorCallback - The callback which will be called when operation encounters an error.
|
|
2531
2554
|
The function is passed a single string parameter containing the error message.
|
|
2532
2555
|
|
|
2533
2556
|
|
|
2534
2557
|
#### Example usage
|
|
2535
2558
|
|
|
2536
|
-
cordova.plugins.diagnostic.requestLocalNetworkAuthorization(function(status){
|
|
2537
|
-
if(status === cordova.plugins.diagnostic.permissionStatus.GRANTED){
|
|
2538
|
-
console.log("Local Network access granted");
|
|
2539
|
-
}else{
|
|
2540
|
-
console.log("Local Network
|
|
2541
|
-
}
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
})
|
|
2559
|
+
cordova.plugins.diagnostic.requestLocalNetworkAuthorization(function(status){
|
|
2560
|
+
if(status === cordova.plugins.diagnostic.permissionStatus.GRANTED){
|
|
2561
|
+
console.log("Local Network access granted");
|
|
2562
|
+
}else if(status === cordova.plugins.diagnostic.permissionStatus.UNKNOWN){
|
|
2563
|
+
console.log("Local Network status could not be determined, retrying may succeed");
|
|
2564
|
+
}else{
|
|
2565
|
+
console.log("Local Network access not granted: " + status);
|
|
2566
|
+
}
|
|
2567
|
+
}, function(error){
|
|
2568
|
+
console.error("The following error occurred: "+error);
|
|
2569
|
+
});
|
|
2545
2570
|
|
|
2546
2571
|
### setWifiState()
|
|
2547
2572
|
|
|
@@ -78,6 +78,7 @@ interface Diagnostic {
|
|
|
78
78
|
"GRANTED_WHEN_IN_USE": "authorized_when_in_use";
|
|
79
79
|
"NOT_REQUESTED": "not_determined"|"NOT_REQUESTED";
|
|
80
80
|
"DENIED_ALWAYS": "denied_always"|"DENIED_ALWAYS";
|
|
81
|
+
"UNKNOWN": "unknown"|"UNKNOWN";
|
|
81
82
|
};
|
|
82
83
|
|
|
83
84
|
/**
|
|
@@ -1272,7 +1273,10 @@ interface Diagnostic {
|
|
|
1272
1273
|
*/
|
|
1273
1274
|
isLocalNetworkAuthorized?: (
|
|
1274
1275
|
successCallback: (authorized: boolean) => void,
|
|
1275
|
-
errorCallback: (error: string) => void
|
|
1276
|
+
errorCallback: (error: string) => void,
|
|
1277
|
+
options?: {
|
|
1278
|
+
timeoutMs?: number;
|
|
1279
|
+
}
|
|
1276
1280
|
) => void;
|
|
1277
1281
|
|
|
1278
1282
|
/**
|
|
@@ -1283,7 +1287,10 @@ interface Diagnostic {
|
|
|
1283
1287
|
*/
|
|
1284
1288
|
getLocalNetworkAuthorizationStatus?: (
|
|
1285
1289
|
successCallback: (status: string) => void,
|
|
1286
|
-
errorCallback: (error: string) => void
|
|
1290
|
+
errorCallback: (error: string) => void,
|
|
1291
|
+
options?: {
|
|
1292
|
+
timeoutMs?: number;
|
|
1293
|
+
}
|
|
1287
1294
|
) => void;
|
|
1288
1295
|
|
|
1289
1296
|
/**
|
package/package.json
CHANGED
package/plugin.xml
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0"
|
|
3
3
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
4
4
|
id="cordova.plugins.diagnostic"
|
|
5
|
-
version="7.2.
|
|
5
|
+
version="7.2.7">
|
|
6
6
|
|
|
7
7
|
<name>Diagnostic</name>
|
|
8
8
|
<description>Cordova/Phonegap plugin to check the state of Location/WiFi/Camera/Bluetooth device settings.</description>
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
#import <net/if.h> // For IFF_LOOPBACK
|
|
14
14
|
#import <Network/Network.h>
|
|
15
15
|
#import <Network/browser.h>
|
|
16
|
+
#import <dns_sd.h>
|
|
17
|
+
#import <errno.h>
|
|
16
18
|
|
|
17
19
|
// UserDefaults key for caching local network permission
|
|
18
20
|
static NSString*const kLocalNetworkPermissionKey = @"Diagnostic_LocalNetworkPermission";
|
|
@@ -21,6 +23,7 @@ typedef NS_ENUM(NSInteger, LocalNetworkPermissionState) {
|
|
|
21
23
|
LocalNetworkPermissionStateUnknown = 0,
|
|
22
24
|
LocalNetworkPermissionStateGranted = 1,
|
|
23
25
|
LocalNetworkPermissionStateDenied = -1,
|
|
26
|
+
LocalNetworkPermissionStateIndeterminate = -2,
|
|
24
27
|
};
|
|
25
28
|
@implementation Diagnostic_Wifi {
|
|
26
29
|
nw_browser_t _browser;
|
|
@@ -41,6 +44,7 @@ static Diagnostic* diagnostic;
|
|
|
41
44
|
|
|
42
45
|
// Internal constants
|
|
43
46
|
static NSString*const LOG_TAG = @"Diagnostic_Wifi[native]";
|
|
47
|
+
static NSTimeInterval const kLocalNetworkDefaultTimeoutSeconds = 2.0;
|
|
44
48
|
|
|
45
49
|
- (void)pluginInitialize {
|
|
46
50
|
|
|
@@ -83,6 +87,8 @@ static NSString*const LOG_TAG = @"Diagnostic_Wifi[native]";
|
|
|
83
87
|
return;
|
|
84
88
|
}
|
|
85
89
|
|
|
90
|
+
NSTimeInterval timeoutSeconds = [self resolveLocalNetworkTimeoutFromCommand:command];
|
|
91
|
+
|
|
86
92
|
// Create parameters, and allow browsing over peer-to-peer link.
|
|
87
93
|
if (@available(iOS 14.0, *)) {
|
|
88
94
|
// Create parameters, and allow browsing over peer-to-peer link.
|
|
@@ -101,7 +107,7 @@ static NSString*const LOG_TAG = @"Diagnostic_Wifi[native]";
|
|
|
101
107
|
self->_isRequesting = YES;
|
|
102
108
|
self->_isPublishing = NO;
|
|
103
109
|
|
|
104
|
-
[diagnostic logDebug:@"Starting local network permission status check"];
|
|
110
|
+
[diagnostic logDebug:[NSString stringWithFormat:@"Starting local network permission status check (timeout %.2fs)", timeoutSeconds]];
|
|
105
111
|
// Start the browsing/publish flow on the main queue immediately and create a single-shot timeout.
|
|
106
112
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
107
113
|
__weak __typeof__(self) weakSelf = self;
|
|
@@ -121,19 +127,11 @@ static NSString*const LOG_TAG = @"Diagnostic_Wifi[native]";
|
|
|
121
127
|
// Install a state handler so the browser emits state changes (silences the warning about missing handlers)
|
|
122
128
|
if (strongSelf->_browser) {
|
|
123
129
|
nw_browser_set_state_changed_handler(strongSelf->_browser, ^(nw_browser_state_t newState, nw_error_t error) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
nw_error_domain_t errorDomain = nw_error_get_error_domain(error);
|
|
128
|
-
[diagnostic logDebug:[NSString stringWithFormat:@"Browser failed (status check): domain=%d", (int)errorDomain]];
|
|
129
|
-
}
|
|
130
|
-
break;
|
|
131
|
-
case nw_browser_state_ready:
|
|
132
|
-
case nw_browser_state_cancelled:
|
|
133
|
-
case nw_browser_state_waiting:
|
|
134
|
-
default:
|
|
135
|
-
break;
|
|
130
|
+
__strong __typeof__(weakSelf) innerSelf = weakSelf;
|
|
131
|
+
if (!innerSelf) {
|
|
132
|
+
return;
|
|
136
133
|
}
|
|
134
|
+
[innerSelf handleBrowserState:newState error:error context:@"status check"];
|
|
137
135
|
});
|
|
138
136
|
|
|
139
137
|
nw_browser_start(strongSelf->_browser);
|
|
@@ -144,17 +142,17 @@ static NSString*const LOG_TAG = @"Diagnostic_Wifi[native]";
|
|
|
144
142
|
[strongSelf->_netService publish];
|
|
145
143
|
[strongSelf->_netService scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
|
146
144
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
145
|
+
if (timeoutSeconds > 0) {
|
|
146
|
+
strongSelf->_localNetworkTimer = [NSTimer scheduledTimerWithTimeInterval:timeoutSeconds
|
|
147
|
+
repeats:NO
|
|
148
|
+
block:^(NSTimer * _Nonnull timer) {
|
|
149
|
+
__strong __typeof__(weakSelf) innerSelf = weakSelf;
|
|
150
|
+
if (!innerSelf) return;
|
|
151
|
+
|
|
152
|
+
[diagnostic logDebug:[NSString stringWithFormat:@"Local network permission status check timed out after %.2fs", timeoutSeconds]];
|
|
153
|
+
[innerSelf completeLocalNetworkFlowWithState:LocalNetworkPermissionStateIndeterminate shouldCache:NO];
|
|
154
|
+
}];
|
|
155
|
+
}
|
|
158
156
|
});
|
|
159
157
|
}else{
|
|
160
158
|
[diagnostic logDebug:@"iOS version < 14.0, so local network permission is not required"];
|
|
@@ -199,33 +197,10 @@ static NSString*const LOG_TAG = @"Diagnostic_Wifi[native]";
|
|
|
199
197
|
__weak __typeof__(self) weakSelf = self;
|
|
200
198
|
nw_browser_set_state_changed_handler(self->_browser, ^(nw_browser_state_t newState, nw_error_t error) {
|
|
201
199
|
__strong __typeof__(weakSelf) strongSelf = weakSelf;
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if (error) {
|
|
205
|
-
nw_error_domain_t errorDomain = nw_error_get_error_domain(error);
|
|
206
|
-
[diagnostic logDebug:[NSString stringWithFormat:@"Browser failed: domain=%d", (int)errorDomain]];
|
|
207
|
-
}
|
|
208
|
-
break;
|
|
209
|
-
case nw_browser_state_ready:
|
|
210
|
-
case nw_browser_state_cancelled:
|
|
211
|
-
break;
|
|
212
|
-
case nw_browser_state_waiting:
|
|
213
|
-
if (error) {
|
|
214
|
-
nw_error_domain_t errorDomain = nw_error_get_error_domain(error);
|
|
215
|
-
[diagnostic logDebug:[NSString stringWithFormat:@"Local network permission has been denied: domain=%d", (int)errorDomain]];
|
|
216
|
-
} else {
|
|
217
|
-
[diagnostic logDebug:@"Local network permission has been denied"];
|
|
218
|
-
}
|
|
219
|
-
[strongSelf resetLocalNetwork];
|
|
220
|
-
// cache denied
|
|
221
|
-
[[NSUserDefaults standardUserDefaults] setInteger:LocalNetworkPermissionStateDenied forKey:kLocalNetworkPermissionKey];
|
|
222
|
-
[[NSUserDefaults standardUserDefaults] synchronize];
|
|
223
|
-
// send false result to all waiting commands
|
|
224
|
-
[self callLocalNetworkCallbacks:LocalNetworkPermissionStateDenied];
|
|
225
|
-
break;
|
|
226
|
-
default:
|
|
227
|
-
break;
|
|
200
|
+
if (!strongSelf) {
|
|
201
|
+
return;
|
|
228
202
|
}
|
|
203
|
+
[strongSelf handleBrowserState:newState error:error context:@"authorization request"];
|
|
229
204
|
});
|
|
230
205
|
|
|
231
206
|
self->_netService = [[NSNetService alloc] initWithDomain:@"local." type:@"_lnp._tcp." name:@"LocalNetworkPrivacy" port:1100];
|
|
@@ -281,6 +256,93 @@ static NSString*const LOG_TAG = @"Diagnostic_Wifi[native]";
|
|
|
281
256
|
}
|
|
282
257
|
}
|
|
283
258
|
|
|
259
|
+
- (void)completeLocalNetworkFlowWithState:(LocalNetworkPermissionState)state shouldCache:(BOOL)shouldCache
|
|
260
|
+
{
|
|
261
|
+
dispatch_block_t completion = ^{
|
|
262
|
+
[self resetLocalNetwork];
|
|
263
|
+
if (shouldCache && (state == LocalNetworkPermissionStateGranted || state == LocalNetworkPermissionStateDenied)) {
|
|
264
|
+
[[NSUserDefaults standardUserDefaults] setInteger:state forKey:kLocalNetworkPermissionKey];
|
|
265
|
+
[[NSUserDefaults standardUserDefaults] synchronize];
|
|
266
|
+
}
|
|
267
|
+
[self callLocalNetworkCallbacks:state];
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
if ([NSThread isMainThread]) {
|
|
271
|
+
completion();
|
|
272
|
+
} else {
|
|
273
|
+
dispatch_async(dispatch_get_main_queue(), completion);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
- (NSTimeInterval)resolveLocalNetworkTimeoutFromCommand:(CDVInvokedUrlCommand*)command
|
|
278
|
+
{
|
|
279
|
+
NSTimeInterval timeout = kLocalNetworkDefaultTimeoutSeconds;
|
|
280
|
+
if (!command || !command.arguments || command.arguments.count == 0) {
|
|
281
|
+
return timeout;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
id rawValue = command.arguments[0];
|
|
285
|
+
if (![rawValue isKindOfClass:[NSDictionary class]]) {
|
|
286
|
+
return timeout;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
NSDictionary *dict = (NSDictionary *)rawValue;
|
|
290
|
+
id timeoutMsValue = dict[@"timeoutMs"];
|
|
291
|
+
if ([timeoutMsValue isKindOfClass:[NSNumber class]]) {
|
|
292
|
+
double milliseconds = [timeoutMsValue doubleValue];
|
|
293
|
+
if (milliseconds < 0) {
|
|
294
|
+
milliseconds = 0;
|
|
295
|
+
}
|
|
296
|
+
return milliseconds / 1000.0;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return timeout;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
- (BOOL)isPermissionDeniedError:(nw_error_t)error
|
|
303
|
+
{
|
|
304
|
+
if (!error) {
|
|
305
|
+
return NO;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
nw_error_domain_t errorDomain = nw_error_get_error_domain(error);
|
|
309
|
+
int errorCode = (int)nw_error_get_error_code(error);
|
|
310
|
+
if (errorDomain == nw_error_domain_posix && errorCode == EPERM) {
|
|
311
|
+
return YES;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (errorDomain == nw_error_domain_dns && errorCode == kDNSServiceErr_PolicyDenied) {
|
|
315
|
+
return YES;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return NO;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
- (void)handleBrowserState:(nw_browser_state_t)newState error:(nw_error_t)error context:(NSString *)context
|
|
322
|
+
{
|
|
323
|
+
if (newState == nw_browser_state_waiting || newState == nw_browser_state_failed) {
|
|
324
|
+
if ([self isPermissionDeniedError:error]) {
|
|
325
|
+
nw_error_domain_t domain = nw_error_get_error_domain(error);
|
|
326
|
+
int code = (int)nw_error_get_error_code(error);
|
|
327
|
+
[diagnostic logDebug:[NSString stringWithFormat:@"Local network permission denied during %@ (domain=%d, code=%d)", context, (int)domain, code]];
|
|
328
|
+
[self completeLocalNetworkFlowWithState:LocalNetworkPermissionStateDenied shouldCache:YES];
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (error) {
|
|
333
|
+
nw_error_domain_t domain = nw_error_get_error_domain(error);
|
|
334
|
+
int code = (int)nw_error_get_error_code(error);
|
|
335
|
+
[diagnostic logDebug:[NSString stringWithFormat:@"Local network browser %@ state %ld error domain=%d code=%d", context, (long)newState, (int)domain, code]];
|
|
336
|
+
} else {
|
|
337
|
+
[diagnostic logDebug:[NSString stringWithFormat:@"Local network browser %@ entered state %ld without error", context, (long)newState]];
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (newState == nw_browser_state_failed) {
|
|
341
|
+
[self completeLocalNetworkFlowWithState:LocalNetworkPermissionStateIndeterminate shouldCache:NO];
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
284
346
|
/********************************/
|
|
285
347
|
#pragma mark - Wifi Plugin API
|
|
286
348
|
/********************************/
|
|
@@ -365,17 +427,13 @@ static NSString*const LOG_TAG = @"Diagnostic_Wifi[native]";
|
|
|
365
427
|
|
|
366
428
|
- (void)netServiceDidPublish:(NSNetService *)sender {
|
|
367
429
|
[diagnostic logDebug:@"netServiceDidPublish: Local network permission has been granted"];
|
|
368
|
-
[self
|
|
369
|
-
|
|
370
|
-
[_localNetworkTimer invalidate];
|
|
371
|
-
_localNetworkTimer = nil;
|
|
372
|
-
}
|
|
373
|
-
_isPublishing = NO;
|
|
374
|
-
|
|
375
|
-
// cache granted
|
|
376
|
-
[[NSUserDefaults standardUserDefaults] setInteger:LocalNetworkPermissionStateGranted forKey:kLocalNetworkPermissionKey];
|
|
377
|
-
[[NSUserDefaults standardUserDefaults] synchronize];
|
|
430
|
+
[self completeLocalNetworkFlowWithState:LocalNetworkPermissionStateGranted shouldCache:YES];
|
|
431
|
+
}
|
|
378
432
|
|
|
379
|
-
|
|
433
|
+
- (void)netService:(NSNetService *)sender didNotPublish:(NSDictionary<NSString *,NSNumber *> *)errorDict {
|
|
434
|
+
NSNumber *errorDomain = errorDict[NSNetServicesErrorDomain];
|
|
435
|
+
NSNumber *errorCode = errorDict[NSNetServicesErrorCode];
|
|
436
|
+
[diagnostic logDebug:[NSString stringWithFormat:@"netService didNotPublish (domain=%@, code=%@)", errorDomain, errorCode]];
|
|
437
|
+
[self completeLocalNetworkFlowWithState:LocalNetworkPermissionStateDenied shouldCache:YES];
|
|
380
438
|
}
|
|
381
439
|
@end
|
|
@@ -89,6 +89,8 @@ var Diagnostic = (function(){
|
|
|
89
89
|
"DENIED_ALWAYS": "DENIED_ALWAYS",
|
|
90
90
|
// App has not yet requested access to this permission.
|
|
91
91
|
"NOT_REQUESTED": "NOT_REQUESTED",
|
|
92
|
+
// Platform has not provided a definitive status (e.g. timeout/indeterminate)
|
|
93
|
+
"UNKNOWN": "unknown",
|
|
92
94
|
// Limited access to the photo library on Android 14 (API 34) and above
|
|
93
95
|
"LIMITED": "LIMITED"
|
|
94
96
|
};
|
package/www/ios/diagnostic.js
CHANGED
|
@@ -22,6 +22,7 @@ var Diagnostic = (function(){
|
|
|
22
22
|
*/
|
|
23
23
|
Diagnostic.permissionStatus = {
|
|
24
24
|
"NOT_REQUESTED": "not_determined", // App has not yet requested this permission
|
|
25
|
+
"UNKNOWN": "unknown", // Platform has not provided a definitive status (e.g. timeout/indeterminate)
|
|
25
26
|
"DENIED_ALWAYS": "denied_always", // User denied access to this permission
|
|
26
27
|
"RESTRICTED": "restricted", // Permission is unavailable and user cannot enable it. For example, when parental controls are in effect for the current user.
|
|
27
28
|
"GRANTED": "authorized", // User granted access to this permission
|
|
@@ -656,8 +657,9 @@ var Diagnostic = (function(){
|
|
|
656
657
|
* This callback function is passed a single boolean parameter which is TRUE if the app is authorized to use Local Network.
|
|
657
658
|
* @param {Function} errorCallback - The callback which will be called when operation encounters an error.
|
|
658
659
|
* This callback function is passed a single string parameter containing the error message.
|
|
660
|
+
* @param {Object} [options] - Optional timeout control object containing an optional `timeoutMs` number, matching the options accepted by `getLocalNetworkAuthorizationStatus()`.
|
|
659
661
|
*/
|
|
660
|
-
Diagnostic.isLocalNetworkAuthorized = function(successCallback, errorCallback) {
|
|
662
|
+
Diagnostic.isLocalNetworkAuthorized = function(successCallback, errorCallback, options) {
|
|
661
663
|
if(cordova.plugins.diagnostic.wifi){
|
|
662
664
|
cordova.plugins.diagnostic.wifi.isLocalNetworkAuthorized.apply(this, arguments);
|
|
663
665
|
}else{
|
|
@@ -667,16 +669,18 @@ var Diagnostic = (function(){
|
|
|
667
669
|
|
|
668
670
|
/**
|
|
669
671
|
* Returns the app's Local Network authorization status.
|
|
670
|
-
* On iOS 14+ this returns one of the values in Diagnostic.permissionStatus: NOT_REQUESTED, GRANTED, DENIED_ALWAYS.
|
|
672
|
+
* On iOS 14+ this returns one of the values in Diagnostic.permissionStatus: NOT_REQUESTED, GRANTED, DENIED_ALWAYS, UNKNOWN.
|
|
671
673
|
* On iOS versions prior to 14, this always returns GRANTED as no authorization is required.
|
|
672
674
|
*
|
|
673
675
|
* @param {Function} successCallback - The callback which will be called when operation is successful.
|
|
674
676
|
* This callback function is passed a single string parameter which is one of the values in Diagnostic.permissionStatus:
|
|
675
|
-
* NOT_REQUESTED, GRANTED, DENIED_ALWAYS.
|
|
677
|
+
* NOT_REQUESTED, GRANTED, DENIED_ALWAYS, UNKNOWN.
|
|
676
678
|
* @param {Function} errorCallback - The callback which will be called when operation encounters an error.
|
|
677
679
|
* This callback function is passed a single string parameter containing the error message.
|
|
680
|
+
* @param {Object} [options] - Optional control over the timeout (defaults to 2 seconds) used when inferring the permission state.
|
|
681
|
+
* Provide `{ timeoutMs: <number> }` to override the timeout in milliseconds.
|
|
678
682
|
*/
|
|
679
|
-
Diagnostic.getLocalNetworkAuthorizationStatus = function(successCallback, errorCallback) {
|
|
683
|
+
Diagnostic.getLocalNetworkAuthorizationStatus = function(successCallback, errorCallback, options) {
|
|
680
684
|
if(cordova.plugins.diagnostic.wifi){
|
|
681
685
|
cordova.plugins.diagnostic.wifi.getLocalNetworkAuthorizationStatus.apply(this, arguments);
|
|
682
686
|
}else{
|
|
@@ -691,7 +695,7 @@ var Diagnostic = (function(){
|
|
|
691
695
|
*
|
|
692
696
|
* @param {Function} successCallback - The callback which will be called when operation is successful.
|
|
693
697
|
* This callback function is passed a single string parameter which is one of the values in Diagnostic.permissionStatus:
|
|
694
|
-
* NOT_REQUESTED, GRANTED, DENIED_ALWAYS.
|
|
698
|
+
* NOT_REQUESTED, GRANTED, DENIED_ALWAYS, UNKNOWN.
|
|
695
699
|
* @param {Function} errorCallback - The callback which will be called when operation encounters an error.
|
|
696
700
|
* This callback function is passed a single string parameter containing the error message.
|
|
697
701
|
*/
|
|
@@ -36,6 +36,9 @@ var Diagnostic_Wifi = (function(){
|
|
|
36
36
|
case -1: // LocalNetworkPermissionStateDenied
|
|
37
37
|
status = Diagnostic.permissionStatus.DENIED_ALWAYS;
|
|
38
38
|
break;
|
|
39
|
+
case -2: // LocalNetworkPermissionStateIndeterminate
|
|
40
|
+
status = Diagnostic.permissionStatus.UNKNOWN;
|
|
41
|
+
break;
|
|
39
42
|
case 0: // LocalNetworkPermissionStateUnknown
|
|
40
43
|
default:
|
|
41
44
|
status = Diagnostic.permissionStatus.NOT_REQUESTED;
|
|
@@ -44,6 +47,18 @@ var Diagnostic_Wifi = (function(){
|
|
|
44
47
|
successCallback(status);
|
|
45
48
|
}
|
|
46
49
|
|
|
50
|
+
function buildLocalNetworkArgs(options) {
|
|
51
|
+
if (options && typeof options === "object" && options.timeoutMs != null) {
|
|
52
|
+
var timeoutMs = Number(options.timeoutMs);
|
|
53
|
+
if (isFinite(timeoutMs)) {
|
|
54
|
+
return [{
|
|
55
|
+
timeoutMs: Math.max(0, timeoutMs)
|
|
56
|
+
}];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
|
|
47
62
|
/*****************************
|
|
48
63
|
*
|
|
49
64
|
* Protected member functions
|
|
@@ -100,8 +115,10 @@ var Diagnostic_Wifi = (function(){
|
|
|
100
115
|
* This callback function is passed a single boolean parameter which is TRUE if the app is authorized to use Local Network.
|
|
101
116
|
* @param {Function} errorCallback - The callback which will be called when operation encounters an error.
|
|
102
117
|
* This callback function is passed a single string parameter containing the error message.
|
|
118
|
+
* @param {Object} [options] - Optional timeout control object containing an optional `timeoutMs` number.
|
|
103
119
|
*/
|
|
104
|
-
Diagnostic_Wifi.isLocalNetworkAuthorized = function(successCallback, errorCallback) {
|
|
120
|
+
Diagnostic_Wifi.isLocalNetworkAuthorized = function(successCallback, errorCallback, options) {
|
|
121
|
+
var args = buildLocalNetworkArgs(options);
|
|
105
122
|
return cordova.exec(function(status) {
|
|
106
123
|
var authorized = (status === 1); // LocalNetworkPermissionStateAuthorized
|
|
107
124
|
successCallback(authorized);
|
|
@@ -109,29 +126,32 @@ var Diagnostic_Wifi = (function(){
|
|
|
109
126
|
errorCallback,
|
|
110
127
|
'Diagnostic_Wifi',
|
|
111
128
|
'getLocalNetworkAuthorizationStatus',
|
|
112
|
-
|
|
129
|
+
args);
|
|
113
130
|
};
|
|
114
131
|
|
|
115
132
|
|
|
116
133
|
/**
|
|
117
134
|
* Returns the app's Local Network authorization status.
|
|
118
|
-
* On iOS 14+ this returns one of the values in Diagnostic.permissionStatus: NOT_REQUESTED, GRANTED, DENIED_ALWAYS.
|
|
135
|
+
* On iOS 14+ this returns one of the values in Diagnostic.permissionStatus: NOT_REQUESTED, GRANTED, DENIED_ALWAYS, UNKNOWN.
|
|
119
136
|
* On iOS versions prior to 14, this always returns GRANTED as no authorization is required.
|
|
120
137
|
*
|
|
121
138
|
* @param {Function} successCallback - The callback which will be called when operation is successful.
|
|
122
139
|
* This callback function is passed a single string parameter which is one of the values in Diagnostic.permissionStatus:
|
|
123
|
-
* NOT_REQUESTED, GRANTED, DENIED_ALWAYS.
|
|
140
|
+
* NOT_REQUESTED, GRANTED, DENIED_ALWAYS, UNKNOWN.
|
|
124
141
|
* @param {Function} errorCallback - The callback which will be called when operation encounters an error.
|
|
125
142
|
* This callback function is passed a single string parameter containing the error message.
|
|
143
|
+
* @param {Object} [options] - Optional control over the timeout used when inferring the permission state.
|
|
144
|
+
* Defaults to 2 seconds when omitted. Provide `{ timeoutMs: <number> }` to override the timeout in milliseconds.
|
|
126
145
|
*/
|
|
127
|
-
Diagnostic_Wifi.getLocalNetworkAuthorizationStatus = function(successCallback, errorCallback) {
|
|
146
|
+
Diagnostic_Wifi.getLocalNetworkAuthorizationStatus = function(successCallback, errorCallback, options) {
|
|
147
|
+
var args = buildLocalNetworkArgs(options);
|
|
128
148
|
return cordova.exec(function(nativeStatus) {
|
|
129
149
|
processLocalNetworkStatus(nativeStatus, successCallback);
|
|
130
150
|
},
|
|
131
151
|
errorCallback,
|
|
132
152
|
'Diagnostic_Wifi',
|
|
133
153
|
'getLocalNetworkAuthorizationStatus',
|
|
134
|
-
|
|
154
|
+
args);
|
|
135
155
|
};
|
|
136
156
|
|
|
137
157
|
/**
|
|
@@ -141,7 +161,7 @@ var Diagnostic_Wifi = (function(){
|
|
|
141
161
|
*
|
|
142
162
|
* @param {Function} successCallback - The callback which will be called when operation is successful.
|
|
143
163
|
* This callback function is passed a single string parameter which is one of the values in Diagnostic.permissionStatus:
|
|
144
|
-
* NOT_REQUESTED, GRANTED, DENIED_ALWAYS.
|
|
164
|
+
* NOT_REQUESTED, GRANTED, DENIED_ALWAYS, UNKNOWN.
|
|
145
165
|
* @param {Function} errorCallback - The callback which will be called when operation encounters an error.
|
|
146
166
|
* This callback function is passed a single string parameter containing the error message.
|
|
147
167
|
*/
|
|
@@ -157,4 +177,4 @@ var Diagnostic_Wifi = (function(){
|
|
|
157
177
|
|
|
158
178
|
return Diagnostic_Wifi;
|
|
159
179
|
});
|
|
160
|
-
module.exports = new Diagnostic_Wifi();
|
|
180
|
+
module.exports = new Diagnostic_Wifi();
|