cordova.plugins.diagnostic 7.2.4 → 7.2.5

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 CHANGED
@@ -1,5 +1,9 @@
1
1
  # CHANGELOG
2
2
 
3
+ **v7.2.5**
4
+ * (ios) feat: add check/request local network authorization to Wifi module
5
+ * Resolves [#524](https://github.com/dpa99c/cordova-diagnostic-plugin/issues/524)
6
+
3
7
  **v7.2.4**
4
8
  * (android & ios) feat: add `isCompassAvailable()` to detect availability of compass for device heading.
5
9
  * (doc) update getCameraRollAuthorizationStatus example to include accessLevel parameter
package/README.md CHANGED
@@ -206,145 +206,154 @@ Cordova diagnostic plugin [![Latest Stable Version](https://img.shields.io/npm/v
206
206
  - [isWifiEnabled()](#iswifienabled)
207
207
  - [Parameters](#parameters-51)
208
208
  - [Example usage](#example-usage-51)
209
- - [setWifiState()](#setwifistate)
209
+ - [isLocalNetworkAuthorized()](#islocalnetworkauthorized)
210
210
  - [Parameters](#parameters-52)
211
211
  - [Example usage](#example-usage-52)
212
- - [switchToWifiSettings()](#switchtowifisettings)
213
- - [Camera module](#camera-module)
214
- - [isCameraPresent()](#iscamerapresent)
212
+ - [getLocalNetworkAuthorizationStatus()](#getlocalnetworkauthorizationstatus)
215
213
  - [Parameters](#parameters-53)
216
214
  - [Example usage](#example-usage-53)
217
- - [isCameraAvailable()](#iscameraavailable)
215
+ - [requestLocalNetworkAuthorization()](#requestlocalnetworkauthorization)
218
216
  - [Parameters](#parameters-54)
219
217
  - [Example usage](#example-usage-54)
220
- - [isCameraAuthorized()](#iscameraauthorized)
218
+ - [setWifiState()](#setwifistate)
221
219
  - [Parameters](#parameters-55)
222
220
  - [Example usage](#example-usage-55)
223
- - [getCameraAuthorizationStatus()](#getcameraauthorizationstatus)
221
+ - [switchToWifiSettings()](#switchtowifisettings)
222
+ - [Camera module](#camera-module)
223
+ - [isCameraPresent()](#iscamerapresent)
224
224
  - [Parameters](#parameters-56)
225
225
  - [Example usage](#example-usage-56)
226
- - [getCameraAuthorizationStatuses()](#getcameraauthorizationstatuses)
226
+ - [isCameraAvailable()](#iscameraavailable)
227
227
  - [Parameters](#parameters-57)
228
228
  - [Example usage](#example-usage-57)
229
- - [requestCameraAuthorization()](#requestcameraauthorization)
229
+ - [isCameraAuthorized()](#iscameraauthorized)
230
230
  - [Parameters](#parameters-58)
231
231
  - [Example usage](#example-usage-58)
232
- - [isCameraRollAuthorized()](#iscamerarollauthorized)
232
+ - [getCameraAuthorizationStatus()](#getcameraauthorizationstatus)
233
233
  - [Parameters](#parameters-59)
234
234
  - [Example usage](#example-usage-59)
235
- - [getCameraRollAuthorizationStatus()](#getcamerarollauthorizationstatus)
235
+ - [getCameraAuthorizationStatuses()](#getcameraauthorizationstatuses)
236
236
  - [Parameters](#parameters-60)
237
237
  - [Example usage](#example-usage-60)
238
- - [requestCameraRollAuthorization()](#requestcamerarollauthorization)
238
+ - [requestCameraAuthorization()](#requestcameraauthorization)
239
239
  - [Parameters](#parameters-61)
240
240
  - [Example usage](#example-usage-61)
241
- - [presentLimitedLibraryPicker()](#presentlimitedlibrarypicker)
241
+ - [isCameraRollAuthorized()](#iscamerarollauthorized)
242
242
  - [Parameters](#parameters-62)
243
243
  - [Example usage](#example-usage-62)
244
- - [Notifications module](#notifications-module)
245
- - [remoteNotificationType constants](#remotenotificationtype-constants)
246
- - [Example](#example-4)
247
- - [isRemoteNotificationsEnabled()](#isremotenotificationsenabled)
244
+ - [getCameraRollAuthorizationStatus()](#getcamerarollauthorizationstatus)
248
245
  - [Parameters](#parameters-63)
249
246
  - [Example usage](#example-usage-63)
250
- - [isRegisteredForRemoteNotifications()](#isregisteredforremotenotifications)
247
+ - [requestCameraRollAuthorization()](#requestcamerarollauthorization)
251
248
  - [Parameters](#parameters-64)
252
249
  - [Example usage](#example-usage-64)
253
- - [getRemoteNotificationTypes()](#getremotenotificationtypes)
250
+ - [presentLimitedLibraryPicker()](#presentlimitedlibrarypicker)
254
251
  - [Parameters](#parameters-65)
255
252
  - [Example usage](#example-usage-65)
256
- - [getRemoteNotificationsAuthorizationStatus()](#getremotenotificationsauthorizationstatus)
253
+ - [Notifications module](#notifications-module)
254
+ - [remoteNotificationType constants](#remotenotificationtype-constants)
255
+ - [Example](#example-4)
256
+ - [isRemoteNotificationsEnabled()](#isremotenotificationsenabled)
257
257
  - [Parameters](#parameters-66)
258
258
  - [Example usage](#example-usage-66)
259
- - [requestRemoteNotificationsAuthorization()](#requestremotenotificationsauthorization)
259
+ - [isRegisteredForRemoteNotifications()](#isregisteredforremotenotifications)
260
260
  - [Parameters](#parameters-67)
261
261
  - [Example usage](#example-usage-67)
262
- - [switchToNotificationSettings()](#switchtonotificationsettings)
263
- - [Microphone module](#microphone-module)
264
- - [isMicrophoneAuthorized()](#ismicrophoneauthorized)
262
+ - [getRemoteNotificationTypes()](#getremotenotificationtypes)
265
263
  - [Parameters](#parameters-68)
266
264
  - [Example usage](#example-usage-68)
267
- - [getMicrophoneAuthorizationStatus()](#getmicrophoneauthorizationstatus)
265
+ - [getRemoteNotificationsAuthorizationStatus()](#getremotenotificationsauthorizationstatus)
268
266
  - [Parameters](#parameters-69)
269
267
  - [Example usage](#example-usage-69)
270
- - [requestMicrophoneAuthorization()](#requestmicrophoneauthorization)
268
+ - [requestRemoteNotificationsAuthorization()](#requestremotenotificationsauthorization)
271
269
  - [Parameters](#parameters-70)
272
270
  - [Example usage](#example-usage-70)
273
- - [Contacts module](#contacts-module)
274
- - [isContactsAuthorized()](#iscontactsauthorized)
271
+ - [switchToNotificationSettings()](#switchtonotificationsettings)
272
+ - [Microphone module](#microphone-module)
273
+ - [isMicrophoneAuthorized()](#ismicrophoneauthorized)
275
274
  - [Parameters](#parameters-71)
276
275
  - [Example usage](#example-usage-71)
277
- - [getContactsAuthorizationStatus()](#getcontactsauthorizationstatus)
276
+ - [getMicrophoneAuthorizationStatus()](#getmicrophoneauthorizationstatus)
278
277
  - [Parameters](#parameters-72)
279
278
  - [Example usage](#example-usage-72)
280
- - [requestContactsAuthorization()](#requestcontactsauthorization)
279
+ - [requestMicrophoneAuthorization()](#requestmicrophoneauthorization)
281
280
  - [Parameters](#parameters-73)
282
281
  - [Example usage](#example-usage-73)
283
- - [Calendar module](#calendar-module)
284
- - [isCalendarAuthorized()](#iscalendarauthorized)
282
+ - [Contacts module](#contacts-module)
283
+ - [isContactsAuthorized()](#iscontactsauthorized)
285
284
  - [Parameters](#parameters-74)
286
285
  - [Example usage](#example-usage-74)
287
- - [getCalendarAuthorizationStatus()](#getcalendarauthorizationstatus)
286
+ - [getContactsAuthorizationStatus()](#getcontactsauthorizationstatus)
288
287
  - [Parameters](#parameters-75)
289
288
  - [Example usage](#example-usage-75)
290
- - [requestCalendarAuthorization()](#requestcalendarauthorization)
289
+ - [requestContactsAuthorization()](#requestcontactsauthorization)
291
290
  - [Parameters](#parameters-76)
292
291
  - [Example usage](#example-usage-76)
293
- - [Reminders module](#reminders-module)
294
- - [isRemindersAuthorized()](#isremindersauthorized)
292
+ - [Calendar module](#calendar-module)
293
+ - [isCalendarAuthorized()](#iscalendarauthorized)
295
294
  - [Parameters](#parameters-77)
296
295
  - [Example usage](#example-usage-77)
297
- - [getRemindersAuthorizationStatus()](#getremindersauthorizationstatus)
296
+ - [getCalendarAuthorizationStatus()](#getcalendarauthorizationstatus)
298
297
  - [Parameters](#parameters-78)
299
298
  - [Example usage](#example-usage-78)
300
- - [requestRemindersAuthorization()](#requestremindersauthorization)
299
+ - [requestCalendarAuthorization()](#requestcalendarauthorization)
301
300
  - [Parameters](#parameters-79)
302
301
  - [Example usage](#example-usage-79)
303
- - [Motion module](#motion-module)
304
- - [motionStatus constants](#motionstatus-constants)
305
- - [Example](#example-5)
306
- - [isMotionAvailable()](#ismotionavailable)
302
+ - [Reminders module](#reminders-module)
303
+ - [isRemindersAuthorized()](#isremindersauthorized)
307
304
  - [Parameters](#parameters-80)
308
305
  - [Example usage](#example-usage-80)
309
- - [isMotionRequestOutcomeAvailable()](#ismotionrequestoutcomeavailable)
306
+ - [getRemindersAuthorizationStatus()](#getremindersauthorizationstatus)
310
307
  - [Parameters](#parameters-81)
311
308
  - [Example usage](#example-usage-81)
312
- - [requestMotionAuthorization()](#requestmotionauthorization)
309
+ - [requestRemindersAuthorization()](#requestremindersauthorization)
313
310
  - [Parameters](#parameters-82)
314
311
  - [Example usage](#example-usage-82)
315
- - [getMotionAuthorizationStatus()](#getmotionauthorizationstatus)
312
+ - [Motion module](#motion-module)
313
+ - [motionStatus constants](#motionstatus-constants)
314
+ - [Example](#example-5)
315
+ - [isMotionAvailable()](#ismotionavailable)
316
316
  - [Parameters](#parameters-83)
317
317
  - [Example usage](#example-usage-83)
318
- - [NFC module](#nfc-module)
319
- - [NFCState constants](#nfcstate-constants)
320
- - [Values](#values-3)
321
- - [Example](#example-6)
322
- - [isNFCPresent()](#isnfcpresent)
318
+ - [isMotionRequestOutcomeAvailable()](#ismotionrequestoutcomeavailable)
323
319
  - [Parameters](#parameters-84)
324
320
  - [Example usage](#example-usage-84)
325
- - [isNFCEnabled()](#isnfcenabled)
321
+ - [requestMotionAuthorization()](#requestmotionauthorization)
326
322
  - [Parameters](#parameters-85)
327
323
  - [Example usage](#example-usage-85)
328
- - [isNFCAvailable()](#isnfcavailable)
324
+ - [getMotionAuthorizationStatus()](#getmotionauthorizationstatus)
329
325
  - [Parameters](#parameters-86)
330
326
  - [Example usage](#example-usage-86)
331
- - [registerNFCStateChangeHandler()](#registernfcstatechangehandler)
327
+ - [NFC module](#nfc-module)
328
+ - [NFCState constants](#nfcstate-constants)
329
+ - [Values](#values-3)
330
+ - [Example](#example-6)
331
+ - [isNFCPresent()](#isnfcpresent)
332
332
  - [Parameters](#parameters-87)
333
333
  - [Example usage](#example-usage-87)
334
- - [switchToNFCSettings()](#switchtonfcsettings)
335
- - [External storage module](#external-storage-module)
336
- - [isExternalStorageAuthorized()](#isexternalstorageauthorized)
334
+ - [isNFCEnabled()](#isnfcenabled)
337
335
  - [Parameters](#parameters-88)
338
336
  - [Example usage](#example-usage-88)
339
- - [getExternalStorageAuthorizationStatus()](#getexternalstorageauthorizationstatus)
337
+ - [isNFCAvailable()](#isnfcavailable)
340
338
  - [Parameters](#parameters-89)
341
339
  - [Example usage](#example-usage-89)
342
- - [requestExternalStorageAuthorization()](#requestexternalstorageauthorization)
340
+ - [registerNFCStateChangeHandler()](#registernfcstatechangehandler)
343
341
  - [Parameters](#parameters-90)
344
342
  - [Example usage](#example-usage-90)
345
- - [getExternalSdCardDetails()](#getexternalsdcarddetails)
343
+ - [switchToNFCSettings()](#switchtonfcsettings)
344
+ - [External storage module](#external-storage-module)
345
+ - [isExternalStorageAuthorized()](#isexternalstorageauthorized)
346
346
  - [Parameters](#parameters-91)
347
347
  - [Example usage](#example-usage-91)
348
+ - [getExternalStorageAuthorizationStatus()](#getexternalstorageauthorizationstatus)
349
+ - [Parameters](#parameters-92)
350
+ - [Example usage](#example-usage-92)
351
+ - [requestExternalStorageAuthorization()](#requestexternalstorageauthorization)
352
+ - [Parameters](#parameters-93)
353
+ - [Example usage](#example-usage-93)
354
+ - [getExternalSdCardDetails()](#getexternalsdcarddetails)
355
+ - [Parameters](#parameters-94)
356
+ - [Example usage](#example-usage-94)
348
357
  - [Platform Notes](#platform-notes)
349
358
  - [Android](#android-3)
350
359
  - [Android permissions](#android-permissions)
@@ -2442,6 +2451,98 @@ The function is passed a single string parameter containing the error message.
2442
2451
  console.error("The following error occurred: "+error);
2443
2452
  });
2444
2453
 
2454
+ ### isLocalNetworkAuthorized()
2455
+
2456
+ Platforms: iOS
2457
+
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.
2460
+
2461
+ cordova.plugins.diagnostic.isLocalNetworkAuthorized(successCallback, errorCallback);
2462
+
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.
2469
+
2470
+
2471
+ #### Example usage
2472
+
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
+
2479
+ ### getLocalNetworkAuthorizationStatus()
2480
+
2481
+ Platforms: iOS
2482
+
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
+ On iOS versions prior to 14 this will always return `GRANTED` as no authorization is required.
2486
+
2487
+ cordova.plugins.diagnostic.getLocalNetworkAuthorizationStatus(successCallback, errorCallback);
2488
+
2489
+ #### Parameters
2490
+
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.
2496
+
2497
+
2498
+ #### Example usage
2499
+
2500
+ 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.GRANTED:
2509
+ console.log("Local Network permission granted");
2510
+ break;
2511
+ }
2512
+ }, function(error){
2513
+ console.error("The following error occurred: "+error);
2514
+ });
2515
+
2516
+ ### requestLocalNetworkAuthorization()
2517
+
2518
+ Platforms: iOS
2519
+
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.
2522
+
2523
+ cordova.plugins.diagnostic.requestLocalNetworkAuthorization(successCallback, errorCallback);
2524
+
2525
+ #### Parameters
2526
+
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`.
2530
+ - {Function} errorCallback - The callback which will be called when operation encounters an error.
2531
+ The function is passed a single string parameter containing the error message.
2532
+
2533
+
2534
+ #### Example usage
2535
+
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 access not granted: " + status);
2541
+ }
2542
+ }, function(error){
2543
+ console.error("The following error occurred: "+error);
2544
+ });
2545
+
2445
2546
  ### setWifiState()
2446
2547
 
2447
2548
  Platforms: Android
@@ -1263,6 +1263,39 @@ interface Diagnostic {
1263
1263
  successCallback: (status: string) => void,
1264
1264
  errorCallback: (error: string) => void
1265
1265
  ) => void;
1266
+
1267
+ /**
1268
+ * iOS ONLY
1269
+ * Checks if the application is authorized to use local network.
1270
+ * @param successCallback
1271
+ * @param errorCallback
1272
+ */
1273
+ isLocalNetworkAuthorized?: (
1274
+ successCallback: (authorized: boolean) => void,
1275
+ errorCallback: (error: string) => void
1276
+ ) => void;
1277
+
1278
+ /**
1279
+ * iOS ONLY
1280
+ * Returns the local network authorization status for the application.
1281
+ * @param successCallback
1282
+ * @param errorCallback
1283
+ */
1284
+ getLocalNetworkAuthorizationStatus?: (
1285
+ successCallback: (status: string) => void,
1286
+ errorCallback: (error: string) => void
1287
+ ) => void;
1288
+
1289
+ /**
1290
+ * iOS ONLY
1291
+ * Requests local network authorization for the application.
1292
+ * @param successCallback
1293
+ * @param errorCallback
1294
+ */
1295
+ requestLocalNetworkAuthorization?: (
1296
+ successCallback: (status: string) => void,
1297
+ errorCallback: (error: string) => void
1298
+ ) => void;
1266
1299
  }
1267
1300
 
1268
1301
  interface CordovaPlugins {
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "7.2.4",
2
+ "version": "7.2.5",
3
3
  "name": "cordova.plugins.diagnostic",
4
4
  "cordova_name": "Diagnostic",
5
5
  "description": "Cordova/Phonegap plugin to check the state of Location/WiFi/Camera/Bluetooth device settings.",
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.4">
5
+ version="7.2.5">
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>
@@ -104,6 +104,17 @@
104
104
 
105
105
  <header-file src="src/ios/Diagnostic_Wifi.h" />
106
106
  <source-file src="src/ios/Diagnostic_Wifi.m" />
107
+
108
+ <config-file parent="NSLocalNetworkUsageDescription" platform="ios" target="*-Info.plist">
109
+ <string>This app requires access to your local network in order to discover and connect to devices on the same network.</string>
110
+ </config-file>
111
+
112
+ <config-file parent="NSBonjourServices" platform="ios" target="*-Info.plist">
113
+ <array>
114
+ <string>_lnp._tcp.</string>
115
+ <string>_bonjour._tcp.</string>
116
+ </array>
117
+ </config-file>
107
118
  <!--END_MODULE WIFI-->
108
119
 
109
120
  <!--BEGIN_MODULE CAMERA-->
@@ -47,6 +47,8 @@ extern NSString*const AUTHORIZATION_LIMITED;
47
47
  - (void) sendPluginResultSuccess:(CDVInvokedUrlCommand*)command;
48
48
  - (void) sendPluginNoResultAndKeepCallback:(CDVInvokedUrlCommand*)command;
49
49
  - (void) sendPluginResultBool: (BOOL)result :(CDVInvokedUrlCommand*)command;
50
+ - (void) sendPluginResultInt: (int)result :(CDVInvokedUrlCommand*)command;
51
+ - (void) sendPluginResultObject: (NSDictionary*)result :(CDVInvokedUrlCommand*)command;
50
52
  - (void) sendPluginResultString: (NSString*)result :(CDVInvokedUrlCommand*)command;
51
53
  - (void) sendPluginError: (NSString*) errorMessage :(CDVInvokedUrlCommand*)command;
52
54
  - (void) handlePluginException: (NSException*) exception :(CDVInvokedUrlCommand*)command;
@@ -10,10 +10,11 @@
10
10
  #import <Cordova/CDVPlugin.h>
11
11
  #import "Diagnostic.h"
12
12
 
13
-
14
- @interface Diagnostic_Wifi : CDVPlugin
13
+ @interface Diagnostic_Wifi : CDVPlugin <NSNetServiceDelegate>
15
14
 
16
15
  - (void) isWifiAvailable: (CDVInvokedUrlCommand*)command;
17
16
  - (void) isWifiEnabled: (CDVInvokedUrlCommand*)command;
17
+ - (void) requestLocalNetworkAuthorization: (CDVInvokedUrlCommand*)command;
18
+ - (void) getLocalNetworkAuthorizationStatus: (CDVInvokedUrlCommand*)command;
18
19
 
19
20
  @end
@@ -11,8 +11,30 @@
11
11
  #import <arpa/inet.h> // For AF_INET, etc.
12
12
  #import <ifaddrs.h> // For getifaddrs()
13
13
  #import <net/if.h> // For IFF_LOOPBACK
14
+ #import <Network/Network.h>
15
+ #import <Network/browser.h>
14
16
 
15
- @implementation Diagnostic_Wifi
17
+ // UserDefaults key for caching local network permission
18
+ static NSString*const kLocalNetworkPermissionKey = @"Diagnostic_LocalNetworkPermission";
19
+
20
+ typedef NS_ENUM(NSInteger, LocalNetworkPermissionState) {
21
+ LocalNetworkPermissionStateUnknown = 0,
22
+ LocalNetworkPermissionStateGranted = 1,
23
+ LocalNetworkPermissionStateDenied = -1,
24
+ };
25
+ @implementation Diagnostic_Wifi {
26
+ nw_browser_t _browser;
27
+ NSNetService *_netService;
28
+ // Completion callbacks stored as CDV callbacks (we'll send results to all when done)
29
+ NSMutableArray<CDVInvokedUrlCommand*> *_localNetworkCommands;
30
+ NSTimer* _localNetworkTimer;
31
+
32
+ // If we have a cached granted/denied value, fall through to the normal path which will verify current status
33
+ // (this may trigger a prompt only if requestLocalNetworkAuthorization was previously called).
34
+ BOOL _isPublishing;
35
+
36
+ BOOL _isRequesting;
37
+ }
16
38
 
17
39
  // Internal reference to Diagnostic singleton instance
18
40
  static Diagnostic* diagnostic;
@@ -25,10 +47,242 @@ static NSString*const LOG_TAG = @"Diagnostic_Wifi[native]";
25
47
  [super pluginInitialize];
26
48
 
27
49
  diagnostic = [Diagnostic getInstance];
50
+ // initialize commands array
51
+ _localNetworkCommands = [NSMutableArray new];
52
+ }
53
+
54
+ /**************************************/
55
+ #pragma mark - Local Network Plugin API
56
+ /**************************************/
57
+
58
+ - (void) getLocalNetworkAuthorizationStatus: (CDVInvokedUrlCommand*)command
59
+ {
60
+ [self.commandDelegate runInBackground:^{
61
+ @try {
62
+
63
+ // Read cached permission state first
64
+ NSInteger cached = [[NSUserDefaults standardUserDefaults] integerForKey:kLocalNetworkPermissionKey];
65
+ LocalNetworkPermissionState state = (LocalNetworkPermissionState)cached;
66
+
67
+ if (state == LocalNetworkPermissionStateUnknown) {
68
+ // If unknown, do not attempt to start browsing/publishing (that would trigger the system prompt).
69
+ // respond with NO (unauthorized) when never requested.
70
+ [diagnostic sendPluginResultInt:LocalNetworkPermissionStateUnknown :command];
71
+ [diagnostic logDebug:@"Local network permission status is NOT_REQUESTED"];
72
+ return;
73
+ }
74
+
75
+ // Store command so we can send the result later
76
+ @synchronized(self->_localNetworkCommands) {
77
+ [self->_localNetworkCommands addObject:command];
78
+ }
79
+
80
+ if(self->_isRequesting){
81
+ // A request is already in progress so await the result
82
+ [diagnostic logDebug:@"A request is already in progress, will return result when done"];
83
+ return;
84
+ }
85
+
86
+ // Create parameters, and allow browsing over peer-to-peer link.
87
+ if (@available(iOS 14.0, *)) {
88
+ // Create parameters, and allow browsing over peer-to-peer link.
89
+ nw_parameters_t parameters = nw_parameters_create_secure_tcp(NW_PARAMETERS_DISABLE_PROTOCOL, NW_PARAMETERS_DEFAULT_CONFIGURATION);
90
+ nw_parameters_set_include_peer_to_peer(parameters, true);
91
+
92
+ // Browse for a custom service type.
93
+ nw_browse_descriptor_t descriptor =
94
+ nw_browse_descriptor_create_bonjour_service("_bonjour._tcp", NULL);
95
+ self->_browser = nw_browser_create(descriptor, parameters);
96
+
97
+ nw_browser_set_queue(self->_browser, dispatch_get_main_queue());
98
+
99
+ self->_netService = [[NSNetService alloc] initWithDomain:@"local." type:@"_lnp._tcp." name:@"LocalNetworkPrivacy" port:1100];
100
+
101
+ self->_isRequesting = YES;
102
+ self->_isPublishing = NO;
103
+
104
+ [diagnostic logDebug:@"Starting local network permission status check"];
105
+ // Start the browsing/publish flow on the main queue immediately and create a single-shot timeout.
106
+ dispatch_async(dispatch_get_main_queue(), ^{
107
+ __weak __typeof__(self) weakSelf = self;
108
+
109
+ __strong __typeof__(weakSelf) strongSelf = weakSelf;
110
+ if (!strongSelf) return;
111
+
112
+ // Ensure we only start once for this check
113
+ if (strongSelf->_isPublishing) {
114
+ [diagnostic logDebug:@"Local network permission request already publishing, skipping start"];
115
+ return;
116
+ }
117
+
118
+ strongSelf->_isPublishing = YES;
119
+ strongSelf->_netService.delegate = strongSelf;
120
+
121
+ // Install a state handler so the browser emits state changes (silences the warning about missing handlers)
122
+ if (strongSelf->_browser) {
123
+ nw_browser_set_state_changed_handler(strongSelf->_browser, ^(nw_browser_state_t newState, nw_error_t error) {
124
+ switch (newState) {
125
+ case nw_browser_state_failed:
126
+ if (error) {
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;
136
+ }
137
+ });
138
+
139
+ nw_browser_start(strongSelf->_browser);
140
+ } else {
141
+ [diagnostic logDebug:@"Attempted to start browser but browser is null"];
142
+ }
143
+
144
+ [strongSelf->_netService publish];
145
+ [strongSelf->_netService scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
146
+
147
+ // Set a single-shot timeout to consider the permission request failed
148
+ strongSelf->_localNetworkTimer = [NSTimer scheduledTimerWithTimeInterval:2.0
149
+ repeats:NO
150
+ block:^(NSTimer * _Nonnull timer) {
151
+ __strong __typeof__(weakSelf) innerSelf = weakSelf;
152
+ if (!innerSelf) return;
153
+
154
+ [diagnostic logDebug:@"Local network permission request timed out"];
155
+ [self callLocalNetworkCallbacks:LocalNetworkPermissionStateDenied];
156
+ [innerSelf resetLocalNetwork];
157
+ }];
158
+ });
159
+ }else{
160
+ [diagnostic logDebug:@"iOS version < 14.0, so local network permission is not required"];
161
+ [self callLocalNetworkCallbacks:LocalNetworkPermissionStateGranted];
162
+ }
163
+ }
164
+ @catch (NSException *exception) {
165
+ [diagnostic handlePluginException:exception :command];
166
+ }
167
+ }];
168
+ }
169
+
170
+ // This code is based on https://stackoverflow.com/a/67758105/2618437 with slight modifications
171
+ - (void) requestLocalNetworkAuthorization: (CDVInvokedUrlCommand*)command
172
+ {
173
+ [self.commandDelegate runInBackground:^{
174
+ @try {
175
+ if(self->_isRequesting){
176
+ // A request is already in progress
177
+ [diagnostic sendPluginError:@"A request is already in progress" :command];
178
+ return;
179
+ }
180
+ self->_isRequesting = YES;
181
+
182
+ // Store command so we can send the result later
183
+ @synchronized(self->_localNetworkCommands) {
184
+ [self->_localNetworkCommands addObject:command];
185
+ }
186
+
187
+ if (@available(iOS 14.0, *)) {
188
+ // Create parameters, and allow browsing over peer-to-peer link.
189
+ nw_parameters_t parameters = nw_parameters_create_secure_tcp(NW_PARAMETERS_DISABLE_PROTOCOL, NW_PARAMETERS_DEFAULT_CONFIGURATION);
190
+ nw_parameters_set_include_peer_to_peer(parameters, true);
191
+
192
+ // Browse for a custom service type.
193
+ nw_browse_descriptor_t descriptor =
194
+ nw_browse_descriptor_create_bonjour_service("_bonjour._tcp", NULL);
195
+ self->_browser = nw_browser_create(descriptor, parameters);
196
+
197
+ nw_browser_set_queue(self->_browser, dispatch_get_main_queue());
198
+
199
+ __weak __typeof__(self) weakSelf = self;
200
+ nw_browser_set_state_changed_handler(self->_browser, ^(nw_browser_state_t newState, nw_error_t error) {
201
+ __strong __typeof__(weakSelf) strongSelf = weakSelf;
202
+ switch (newState) {
203
+ case nw_browser_state_failed:
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;
228
+ }
229
+ });
230
+
231
+ self->_netService = [[NSNetService alloc] initWithDomain:@"local." type:@"_lnp._tcp." name:@"LocalNetworkPrivacy" port:1100];
232
+ self->_netService.delegate = self;
233
+
234
+ // Start browsing on main queue
235
+ nw_browser_start(self->_browser);
236
+ [self->_netService publish];
237
+ // the netService needs to be scheduled on a run loop, in this case the main runloop
238
+ [self->_netService scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
239
+ }else{
240
+ // iOS version < 14.0, so local network permission is not required
241
+ [self callLocalNetworkCallbacks:LocalNetworkPermissionStateGranted];
242
+ }
243
+ } @catch (NSException *exception) {
244
+ [diagnostic handlePluginException:exception :command];
245
+ }
246
+ }];
247
+ }
248
+
249
+ - (void) resetLocalNetwork
250
+ {
251
+ [diagnostic logDebug:@"resetting"];
252
+ // stop the timer if active so it doesn't keep firing
253
+ if (_localNetworkTimer) {
254
+ [_localNetworkTimer invalidate];
255
+ _localNetworkTimer = nil;
256
+ }
257
+
258
+ // reset state flags
259
+ self->_isPublishing = NO;
260
+ self->_isRequesting = NO;
261
+
262
+ if (_browser) {
263
+ if (@available(iOS 13.0, *)) {
264
+ nw_browser_cancel(_browser);
265
+ }
266
+ _browser = nil;
267
+ }
268
+ if (_netService) {
269
+ [_netService stop];
270
+ _netService = nil;
271
+ }
272
+ }
273
+
274
+ - (void) callLocalNetworkCallbacks:(LocalNetworkPermissionState)result
275
+ {
276
+ @synchronized(self->_localNetworkCommands) {
277
+ for (CDVInvokedUrlCommand *c in self->_localNetworkCommands) {
278
+ [diagnostic sendPluginResultInt:(int)result :c];
279
+ }
280
+ [self->_localNetworkCommands removeAllObjects];
281
+ }
28
282
  }
29
283
 
30
284
  /********************************/
31
- #pragma mark - Plugin API
285
+ #pragma mark - Wifi Plugin API
32
286
  /********************************/
33
287
 
34
288
  - (void) isWifiAvailable: (CDVInvokedUrlCommand*)command
@@ -105,4 +359,23 @@ static NSString*const LOG_TAG = @"Diagnostic_Wifi[native]";
105
359
  }
106
360
 
107
361
 
362
+ /********************************/
363
+ #pragma mark - NetServiceDelegate
364
+ /********************************/
365
+
366
+ - (void)netServiceDidPublish:(NSNetService *)sender {
367
+ [diagnostic logDebug:@"netServiceDidPublish: Local network permission has been granted"];
368
+ [self resetLocalNetwork];
369
+ if (_localNetworkTimer) {
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];
378
+
379
+ [self callLocalNetworkCallbacks:LocalNetworkPermissionStateGranted];
380
+ }
108
381
  @end
@@ -647,6 +647,62 @@ var Diagnostic = (function(){
647
647
  }
648
648
  };
649
649
 
650
+ /**
651
+ * Checks if the app is authorized to use Local Network.
652
+ * On iOS 14+ this returns true if the user has authorized the app to access devices on the local network.
653
+ * On iOS versions prior to 14, this always returns true as no authorization is required.
654
+ *
655
+ * @param {Function} successCallback - The callback which will be called when operation is successful.
656
+ * This callback function is passed a single boolean parameter which is TRUE if the app is authorized to use Local Network.
657
+ * @param {Function} errorCallback - The callback which will be called when operation encounters an error.
658
+ * This callback function is passed a single string parameter containing the error message.
659
+ */
660
+ Diagnostic.isLocalNetworkAuthorized = function(successCallback, errorCallback) {
661
+ if(cordova.plugins.diagnostic.wifi){
662
+ cordova.plugins.diagnostic.wifi.isLocalNetworkAuthorized.apply(this, arguments);
663
+ }else{
664
+ throw "Diagnostic Wifi module is not installed";
665
+ }
666
+ };
667
+
668
+ /**
669
+ * 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.
671
+ * On iOS versions prior to 14, this always returns GRANTED as no authorization is required.
672
+ *
673
+ * @param {Function} successCallback - The callback which will be called when operation is successful.
674
+ * This callback function is passed a single string parameter which is one of the values in Diagnostic.permissionStatus:
675
+ * NOT_REQUESTED, GRANTED, DENIED_ALWAYS.
676
+ * @param {Function} errorCallback - The callback which will be called when operation encounters an error.
677
+ * This callback function is passed a single string parameter containing the error message.
678
+ */
679
+ Diagnostic.getLocalNetworkAuthorizationStatus = function(successCallback, errorCallback) {
680
+ if(cordova.plugins.diagnostic.wifi){
681
+ cordova.plugins.diagnostic.wifi.getLocalNetworkAuthorizationStatus.apply(this, arguments);
682
+ }else{
683
+ throw "Diagnostic Wifi module is not installed";
684
+ }
685
+ };
686
+
687
+ /**
688
+ * Requests the user to authorize the app to use Local Network.
689
+ * On iOS 14+ this will prompt the user to authorize the app to access devices on the local network.
690
+ * On iOS versions prior to 14, this does nothing as no authorization is required and will return success.
691
+ *
692
+ * @param {Function} successCallback - The callback which will be called when operation is successful.
693
+ * This callback function is passed a single string parameter which is one of the values in Diagnostic.permissionStatus:
694
+ * NOT_REQUESTED, GRANTED, DENIED_ALWAYS.
695
+ * @param {Function} errorCallback - The callback which will be called when operation encounters an error.
696
+ * This callback function is passed a single string parameter containing the error message.
697
+ */
698
+ Diagnostic.requestLocalNetworkAuthorization = function(successCallback, errorCallback) {
699
+ if(cordova.plugins.diagnostic.wifi){
700
+ cordova.plugins.diagnostic.wifi.requestLocalNetworkAuthorization.apply(this, arguments);
701
+ }else{
702
+ throw "Diagnostic Wifi module is not installed";
703
+ }
704
+ };
705
+
650
706
  /***************
651
707
  * Bluetooth *
652
708
  ***************/
@@ -27,6 +27,22 @@ var Diagnostic_Wifi = (function(){
27
27
  * Internal functions
28
28
  *
29
29
  ********************/
30
+ function processLocalNetworkStatus(nativeStatus, successCallback) {
31
+ let status;
32
+ switch (nativeStatus) {
33
+ case 1: // LocalNetworkPermissionStateGranted
34
+ status = Diagnostic.permissionStatus.GRANTED;
35
+ break;
36
+ case -1: // LocalNetworkPermissionStateDenied
37
+ status = Diagnostic.permissionStatus.DENIED_ALWAYS;
38
+ break;
39
+ case 0: // LocalNetworkPermissionStateUnknown
40
+ default:
41
+ status = Diagnostic.permissionStatus.NOT_REQUESTED;
42
+ break;
43
+ }
44
+ successCallback(status);
45
+ }
30
46
 
31
47
  /*****************************
32
48
  *
@@ -75,6 +91,70 @@ var Diagnostic_Wifi = (function(){
75
91
  []);
76
92
  };
77
93
 
94
+ /**
95
+ * Checks if the app is authorized to use Local Network.
96
+ * On iOS 14+ this returns true if the user has authorized the app to access devices on the local network.
97
+ * On iOS versions prior to 14, this always returns true as no authorization is required.
98
+ *
99
+ * @param {Function} successCallback - The callback which will be called when operation is successful.
100
+ * This callback function is passed a single boolean parameter which is TRUE if the app is authorized to use Local Network.
101
+ * @param {Function} errorCallback - The callback which will be called when operation encounters an error.
102
+ * This callback function is passed a single string parameter containing the error message.
103
+ */
104
+ Diagnostic_Wifi.isLocalNetworkAuthorized = function(successCallback, errorCallback) {
105
+ return cordova.exec(function(status) {
106
+ var authorized = (status === 1); // LocalNetworkPermissionStateAuthorized
107
+ successCallback(authorized);
108
+ },
109
+ errorCallback,
110
+ 'Diagnostic_Wifi',
111
+ 'getLocalNetworkAuthorizationStatus',
112
+ []);
113
+ };
114
+
115
+
116
+ /**
117
+ * 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.
119
+ * On iOS versions prior to 14, this always returns GRANTED as no authorization is required.
120
+ *
121
+ * @param {Function} successCallback - The callback which will be called when operation is successful.
122
+ * This callback function is passed a single string parameter which is one of the values in Diagnostic.permissionStatus:
123
+ * NOT_REQUESTED, GRANTED, DENIED_ALWAYS.
124
+ * @param {Function} errorCallback - The callback which will be called when operation encounters an error.
125
+ * This callback function is passed a single string parameter containing the error message.
126
+ */
127
+ Diagnostic_Wifi.getLocalNetworkAuthorizationStatus = function(successCallback, errorCallback) {
128
+ return cordova.exec(function(nativeStatus) {
129
+ processLocalNetworkStatus(nativeStatus, successCallback);
130
+ },
131
+ errorCallback,
132
+ 'Diagnostic_Wifi',
133
+ 'getLocalNetworkAuthorizationStatus',
134
+ []);
135
+ };
136
+
137
+ /**
138
+ * Requests the user to authorize the app to use Local Network.
139
+ * On iOS 14+ this will prompt the user to authorize the app to access devices on the local network.
140
+ * On iOS versions prior to 14, this does nothing as no authorization is required and will return success.
141
+ *
142
+ * @param {Function} successCallback - The callback which will be called when operation is successful.
143
+ * This callback function is passed a single string parameter which is one of the values in Diagnostic.permissionStatus:
144
+ * NOT_REQUESTED, GRANTED, DENIED_ALWAYS.
145
+ * @param {Function} errorCallback - The callback which will be called when operation encounters an error.
146
+ * This callback function is passed a single string parameter containing the error message.
147
+ */
148
+ Diagnostic_Wifi.requestLocalNetworkAuthorization = function(successCallback, errorCallback) {
149
+ return cordova.exec(function(nativeStatus) {
150
+ processLocalNetworkStatus(nativeStatus, successCallback);
151
+ },
152
+ errorCallback,
153
+ 'Diagnostic_Wifi',
154
+ 'requestLocalNetworkAuthorization',
155
+ []);
156
+ };
157
+
78
158
  return Diagnostic_Wifi;
79
159
  });
80
160
  module.exports = new Diagnostic_Wifi();