diff --git a/README.md b/README.md index bfa66706..9cac3c6e 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ _📌  Note that these commands must be re-executed each time you update this "Camera", "Contacts", "FaceID", + "LocalNetworkPrivacy", "LocationAccuracy", "LocationAlways", "LocationWhenInUse", @@ -97,6 +98,8 @@ Then update your `Info.plist` with wanted permissions usage descriptions: YOUR TEXT NSFaceIDUsageDescription YOUR TEXT + NSLocalNetworkUsageDescription + YOUR TEXT NSLocationAlwaysAndWhenInUseUsageDescription YOUR TEXT NSLocationAlwaysUsageDescription @@ -125,6 +128,13 @@ Then update your `Info.plist` with wanted permissions usage descriptions: NSUserTrackingUsageDescription YOUR TEXT + + + NSBonjourServices + + _lnp._tcp. + + @@ -488,6 +498,7 @@ PERMISSIONS.IOS.CALENDARS; PERMISSIONS.IOS.CAMERA; PERMISSIONS.IOS.CONTACTS; PERMISSIONS.IOS.FACE_ID; +PERMISSIONS.IOS.LOCAL_NETWORK_PRIVACY; PERMISSIONS.IOS.LOCATION_ALWAYS; PERMISSIONS.IOS.LOCATION_WHEN_IN_USE; PERMISSIONS.IOS.MEDIA_LIBRARY; diff --git a/example/ios/RNPermissionsExample/Info.plist b/example/ios/RNPermissionsExample/Info.plist index ce57f966..bc76b70d 100644 --- a/example/ios/RNPermissionsExample/Info.plist +++ b/example/ios/RNPermissionsExample/Info.plist @@ -35,6 +35,10 @@ + NSBonjourServices + + _lnp._tcp. + NSAppleMusicUsageDescription Let me use your media library NSBluetoothAlwaysUsageDescription @@ -49,6 +53,8 @@ Let me use your contacts NSFaceIDUsageDescription Let me use FaceID + NSLocalNetworkUsageDescription + Let me use your local network NSLocationAlwaysAndWhenInUseUsageDescription Let me use your location, even in background NSLocationAlwaysUsageDescription diff --git a/example/package.json b/example/package.json index 45d05143..d3799d1f 100644 --- a/example/package.json +++ b/example/package.json @@ -17,6 +17,7 @@ "Camera", "Contacts", "FaceID", + "LocalNetworkPrivacy", "LocationAccuracy", "LocationAlways", "LocationWhenInUse", diff --git a/ios/LocalNetworkPrivacy/LocalNetworkPrivacy.h b/ios/LocalNetworkPrivacy/LocalNetworkPrivacy.h new file mode 100644 index 00000000..3c0a8b24 --- /dev/null +++ b/ios/LocalNetworkPrivacy/LocalNetworkPrivacy.h @@ -0,0 +1,5 @@ +@interface LocalNetworkPrivacy : NSObject + +- (void)checkAccessState:(void (^)(BOOL))completion; + +@end diff --git a/ios/LocalNetworkPrivacy/LocalNetworkPrivacy.m b/ios/LocalNetworkPrivacy/LocalNetworkPrivacy.m new file mode 100644 index 00000000..9ea9fa95 --- /dev/null +++ b/ios/LocalNetworkPrivacy/LocalNetworkPrivacy.m @@ -0,0 +1,47 @@ +#import +#import "LocalNetworkPrivacy.h" + +@interface LocalNetworkPrivacy () + +@property (nonatomic) NSNetService *service; +@property (nonatomic) void (^completion)(BOOL); +@property (nonatomic) NSTimer *timer; +@property (nonatomic) BOOL publishing; + +@end + +@implementation LocalNetworkPrivacy + +- (instancetype)init { + if (self = [super init]) { + self.service = [[NSNetService alloc] initWithDomain:@"local." type:@"_lnp._tcp." name:@"LocalNetworkPrivacy" port:1100]; + } + return self; +} + +- (void)dealloc { + [self.service stop]; +} + +- (void)checkAccessState:(void (^)(BOOL))completion { + self.completion = completion; + + self.publishing = YES; + self.service.delegate = self; + [self.service publish]; + + self.timer = [NSTimer scheduledTimerWithTimeInterval:2 repeats:NO block:^(NSTimer * _Nonnull timer) { + [self.timer invalidate]; + self.completion(NO); + }]; +} + + +#pragma mark - NSNetServiceDelegate + +- (void)netServiceDidPublish:(NSNetService *)sender { + [self.timer invalidate]; + self.completion(YES); +} + +@end diff --git a/ios/LocalNetworkPrivacy/Permission-LocalNetworkPrivacy.podspec b/ios/LocalNetworkPrivacy/Permission-LocalNetworkPrivacy.podspec new file mode 100644 index 00000000..52cefb09 --- /dev/null +++ b/ios/LocalNetworkPrivacy/Permission-LocalNetworkPrivacy.podspec @@ -0,0 +1,20 @@ +require 'json' +package = JSON.parse(File.read('../../package.json')) + +Pod::Spec.new do |s| + s.name = "Permission-LocalNetworkPrivacy" + s.dependency "RNPermissions" + + s.version = package["version"] + s.license = package["license"] + s.summary = package["description"] + s.authors = package["author"] + s.homepage = package["homepage"] + + s.ios.deployment_target = "10.0" + s.tvos.deployment_target = "11.0" + s.requires_arc = true + + s.source = { :git => package["repository"]["url"], :tag => s.version } + s.source_files = "*.{h,m}" +end diff --git a/ios/LocalNetworkPrivacy/RNPermissionHandlerLocalNetworkPrivacy.h b/ios/LocalNetworkPrivacy/RNPermissionHandlerLocalNetworkPrivacy.h new file mode 100644 index 00000000..c25281db --- /dev/null +++ b/ios/LocalNetworkPrivacy/RNPermissionHandlerLocalNetworkPrivacy.h @@ -0,0 +1,5 @@ +#import "RNPermissions.h" + +@interface RNPermissionHandlerLocalNetworkPrivacy : NSObject + +@end diff --git a/ios/LocalNetworkPrivacy/RNPermissionHandlerLocalNetworkPrivacy.m b/ios/LocalNetworkPrivacy/RNPermissionHandlerLocalNetworkPrivacy.m new file mode 100644 index 00000000..0e69ab09 --- /dev/null +++ b/ios/LocalNetworkPrivacy/RNPermissionHandlerLocalNetworkPrivacy.m @@ -0,0 +1,33 @@ +#import "RNPermissionHandlerLocalNetworkPrivacy.h" +#import "LocalNetworkPrivacy.h" + +@implementation RNPermissionHandlerLocalNetworkPrivacy + ++ (NSArray * _Nonnull)usageDescriptionKeys { + return @[@"NSLocalNetworkUsageDescription"]; +} + ++ (NSString * _Nonnull)handlerUniqueId { + return @"ios.permission.LOCAL_NETWORK_PRIVACY"; +} + +- (void)checkWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve + rejecter:(void (__unused ^ _Nonnull)(NSError * _Nonnull))reject { + if (![RNPermissionsHelper isFlaggedAsRequested:[[self class] handlerUniqueId]]) { + return resolve(RNPermissionStatusNotDetermined); + } + + [self requestWithResolver:resolve rejecter:reject]; +} + +- (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve + rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject { + [RNPermissionsHelper flagAsRequested:[[self class] handlerUniqueId]]; + + LocalNetworkPrivacy *local = [LocalNetworkPrivacy new]; + [local checkAccessState:^(BOOL granted) { + resolve(granted ? RNPermissionStatusAuthorized : RNPermissionStatusDenied); + }]; +} + +@end diff --git a/ios/RNPermissionsHelper.h b/ios/RNPermissionsHelper.h index f45c3dcf..19340823 100644 --- a/ios/RNPermissionsHelper.h +++ b/ios/RNPermissionsHelper.h @@ -53,6 +53,9 @@ typedef NS_ENUM(NSInteger, RNPermission) { #if __has_include("RNPermissionHandlerPhotoLibraryAddOnly.h") RNPermissionPhotoLibraryAddOnly = 17, #endif +#if __has_include("RNPermissionHandlerLocalNetworkPrivacy.h") + RNPermissionLocalNetworkPrivacy = 18, +#endif }; typedef enum { diff --git a/ios/RNPermissionsModule.mm b/ios/RNPermissionsModule.mm index c5faea9b..53d75062 100644 --- a/ios/RNPermissionsModule.mm +++ b/ios/RNPermissionsModule.mm @@ -58,6 +58,9 @@ #if __has_include("RNPermissionHandlerLocationAccuracy.h") #import "RNPermissionHandlerLocationAccuracy.h" #endif +#if __has_include("RNPermissionHandlerLocalNetworkPrivacy.h") +#import "RNPermissionHandlerLocalNetworkPrivacy.h" +#endif @implementation RCTConvert(RNPermission) @@ -113,6 +116,9 @@ @implementation RCTConvert(RNPermission) #if __has_include("RNPermissionHandlerPhotoLibraryAddOnly.h") [RNPermissionHandlerPhotoLibraryAddOnly handlerUniqueId]: @(RNPermissionPhotoLibraryAddOnly), #endif +#if __has_include("RNPermissionHandlerLocalNetworkPrivacy.h") + [RNPermissionHandlerLocalNetworkPrivacy handlerUniqueId]: @(RNPermissionLocalNetworkPrivacy), +#endif }), RNPermissionUnknown, integerValue); @end @@ -195,6 +201,9 @@ - (NSDictionary *)constantsToExport { #if __has_include("RNPermissionHandlerLocationAccuracy.h") [available addObject:[RNPermissionHandlerLocationAccuracy handlerUniqueId]]; #endif +#if __has_include("RNPermissionHandlerLocalNetworkPrivacy.h") + [available addObject:[RNPermissionHandlerLocalNetworkPrivacy handlerUniqueId]]; +#endif #if RCT_DEV if ([available count] == 0) { @@ -310,6 +319,11 @@ - (void)checkUsageDescriptionKeys:(NSArray * _Nonnull)keys { case RNPermissionPhotoLibraryAddOnly: handler = [RNPermissionHandlerPhotoLibraryAddOnly new]; break; +#endif +#if __has_include("RNPermissionHandlerLocalNetworkPrivacy.h") + case RNPermissionLocalNetworkPrivacy: + handler = [RNPermissionHandlerLocalNetworkPrivacy new]; + break; #endif case RNPermissionUnknown: break; // RCTConvert prevents this case diff --git a/src/permissions.ios.ts b/src/permissions.ios.ts index 87e6eb22..264bef72 100644 --- a/src/permissions.ios.ts +++ b/src/permissions.ios.ts @@ -8,6 +8,7 @@ const IOS = Object.freeze({ CAMERA: 'ios.permission.CAMERA', CONTACTS: 'ios.permission.CONTACTS', FACE_ID: 'ios.permission.FACE_ID', + LOCAL_NETWORK_PRIVACY: 'ios.permission.LOCAL_NETWORK_PRIVACY', LOCATION_ALWAYS: 'ios.permission.LOCATION_ALWAYS', LOCATION_WHEN_IN_USE: 'ios.permission.LOCATION_WHEN_IN_USE', MEDIA_LIBRARY: 'ios.permission.MEDIA_LIBRARY',