Commit 59fee216 by Maurits van Beusekom Committed by GitHub

Adds support for when in use only. (#1295)

* Adds support for when in use only

* Update permission_handler_apple/CHANGELOG.md

Co-authored-by: TimHoogstrate <tim566@hotmail.com>

* Update permission_handler_apple/CHANGELOG.md

Co-authored-by: TimHoogstrate <tim566@hotmail.com>

* Apply PR feedback

---------

Co-authored-by: TimHoogstrate <tim566@hotmail.com>
parent 22cddbea
## 9.4.3
* Adds the `PERMISSION_LOCATION_WHENINUSE` macro, which can be used instead of
the `PERMISSION_LOCATION` macro, and exclusively enables the `requestWhenInUseAuthorization`
and remove the `requestAlwaysAuthorization` when requesting location permission.
* Improves error handling when `Info.plist` doesn't contain the correct declarations.
* Adds support for the `NSLocationAlwaysAndWhenInUseUsageDescription` property list
key.
## 9.4.2
* Updates the privacy manifest to include the use of the `NSUserDefaults` API.
......
......@@ -69,8 +69,13 @@ post_install do |installer|
## dart: PermissionGroup.photos
'PERMISSION_PHOTOS=1',
## The 'PERMISSION_LOCATION' macro enables the `locationWhenInUse` and `locationAlways` permission. If
## the application only requires `locationWhenInUse`, only specify the `PERMISSION_LOCATION_WHENINUSE`
## macro.
##
## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
'PERMISSION_LOCATION=1',
'PERMISSION_LOCATION_WHENINUSE=0',
## dart: PermissionGroup.notification
'PERMISSION_NOTIFICATIONS=1',
......
......@@ -141,6 +141,7 @@
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
D38B08CB85942E5D11545EE3 /* [CP] Embed Pods Frameworks */,
A7B07F67421488A414C73AAD /* [CP] Copy Pods Resources */,
);
buildRules = (
);
......@@ -157,7 +158,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1430;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
......@@ -252,6 +253,23 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
A7B07F67421488A414C73AAD /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
D38B08CB85942E5D11545EE3 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
......
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1430"
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
......
......@@ -47,7 +47,11 @@
}
self->_methodResult = nil;
}];
} errorHandler:^(NSString *errorCode, NSString *errorDescription) {
self->_methodResult([FlutterError errorWithCode:errorCode message:errorDescription details:nil]);
self->_methodResult = nil;
}
];
} else if ([@"shouldShowRequestPermissionRationale" isEqualToString:call.method]) {
result(@false);
......
......@@ -35,7 +35,7 @@ typedef void (^PermissionRequestCompletion)(NSDictionary *permissionRequestResul
@interface PermissionManager : NSObject
- (instancetype)initWithStrategyInstances;
- (void)requestPermissions:(NSArray *)permissions completion:(PermissionRequestCompletion)completion;
- (void)requestPermissions:(NSArray *)permissions completion:(PermissionRequestCompletion)completion errorHandler:(PermissionErrorHandler)errorHandler;
+ (void)checkPermissionStatus:(enum PermissionGroup)permission result:(FlutterResult)result;
+ (void)checkServiceStatus:(enum PermissionGroup)permission result:(FlutterResult)result;
......
......@@ -39,7 +39,7 @@
}];
}
- (void)requestPermissions:(NSArray *)permissions completion:(PermissionRequestCompletion)completion {
- (void)requestPermissions:(NSArray *)permissions completion:(PermissionRequestCompletion)completion errorHandler:(PermissionErrorHandler)errorHandler {
NSMutableDictionary *permissionStatusResult = [[NSMutableDictionary alloc] init];
if (permissions.count == 0) {
......@@ -57,22 +57,24 @@
__block id <PermissionStrategy> permissionStrategy = [PermissionManager createPermissionStrategy:permission];
[_strategyInstances addObject:permissionStrategy];
[permissionStrategy requestPermission:permission completionHandler:^(PermissionStatus permissionStatus) {
permissionStatusResult[@(permission)] = @(permissionStatus);
[requestQueue removeObject:@(permission)];
[self->_strategyInstances removeObject:permissionStrategy];
if (requestQueue.count == 0) {
completion(permissionStatusResult);
}
// Make sure `completion` is called before cleaning up the reference
// otherwise the `completion` block is also dereferenced on iOS 12 and
// below (this is most likely a bug in Objective-C which is solved in
// later versions of the runtime).
permissionStrategy = nil;
} errorHandler: ^(NSString* errorCode, NSString* errorDesciption) {
errorHandler(errorCode, errorDesciption);
permissionStrategy = nil;
}];
}
}
......@@ -108,7 +110,7 @@
case PermissionGroupLocation:
case PermissionGroupLocationAlways:
case PermissionGroupLocationWhenInUse:
#if PERMISSION_LOCATION
#if PERMISSION_LOCATION || PERMISSION_LOCATION_WHENINUSE || PERMISSION_LOCATION_ALWAYS
return [[LocationPermissionStrategy alloc] initWithLocationManager];
#else
return [LocationPermissionStrategy new];
......
......@@ -24,7 +24,7 @@
completionHandler(ServiceStatusNotApplicable);
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler{
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusDenied) {
completionHandler(status);
......
......@@ -24,7 +24,7 @@
completionHandler(ServiceStatusNotApplicable);
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusDenied) {
completionHandler(status);
......
......@@ -26,7 +26,7 @@
completionHandler(ServiceStatusNotApplicable);
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusDenied) {
......
......@@ -17,7 +17,7 @@
completionHandler(ServiceStatusNotApplicable);
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler {
completionHandler([BackgroundRefreshStrategy permissionStatus]);
}
......
......@@ -70,7 +70,7 @@
_serviceStatusHandler(serviceStatus);
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler {
[self initManagerIfNeeded];
PermissionStatus status = [self checkPermissionStatus:permission];
......
......@@ -17,7 +17,7 @@
completionHandler(ServiceStatusNotApplicable);
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusDenied) {
......
......@@ -19,7 +19,7 @@
completionHandler(ServiceStatusNotApplicable);
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusDenied) {
completionHandler(status);
......
......@@ -17,7 +17,7 @@
completionHandler(ServiceStatusNotApplicable);
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler {
PermissionStatus permissionStatus = [self checkPermissionStatus:permission];
if (permissionStatus != PermissionStatusDenied) {
......
......@@ -6,7 +6,7 @@
#import <Foundation/Foundation.h>
#import "PermissionStrategy.h"
#if PERMISSION_LOCATION
#if PERMISSION_LOCATION || PERMISSION_LOCATION_WHENINUSE || PERMISSION_LOCATION_ALWAYS
#import <CoreLocation/CoreLocation.h>
......
......@@ -5,7 +5,7 @@
#import "LocationPermissionStrategy.h"
#if PERMISSION_LOCATION
#if PERMISSION_LOCATION || PERMISSION_LOCATION_WHENINUSE || PERMISSION_LOCATION_ALWAYS
NSString *const UserDefaultPermissionRequestedKey = @"org.baseflow.permission_handler_apple.permission_requested";
......@@ -39,7 +39,7 @@ NSString *const UserDefaultPermissionRequestedKey = @"org.baseflow.permission_ha
completionHandler([CLLocationManager locationServicesEnabled] ? ServiceStatusEnabled : ServiceStatusDisabled);
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse && permission == PermissionGroupLocationAlways) {
BOOL alreadyRequested = [[NSUserDefaults standardUserDefaults] boolForKey:UserDefaultPermissionRequestedKey]; // check if already requested the permantent permission
......@@ -56,26 +56,47 @@ NSString *const UserDefaultPermissionRequestedKey = @"org.baseflow.permission_ha
_requestedPermission = permission;
if (permission == PermissionGroupLocation) {
if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"] != nil) {
#if PERMISSION_LOCATION
bool hasAlwaysInInfoPlist = ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"] != nil || [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysAndWhenInUseUsageDescription"] != nil);
if (hasAlwaysInInfoPlist && [CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse) {
[_locationManager requestAlwaysAuthorization];
} else if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] != nil) {
[_locationManager requestWhenInUseAuthorization];
} else {
[[NSException exceptionWithName:NSInternalInconsistencyException reason:@"To use location in iOS8 you need to define either NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription in the app bundle's Info.plist file" userInfo:nil] raise];
errorHandler(@"MISSING_USAGE_DESCRIPTION", @"To use location from iOS8 you need to define at least NSLocationWhenInUseUsageDescription and optionally NSLocationAlwaysAndWhenInUseUsageDescription in the app bundle's Info.plist file");
return;
}
#else
if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] != nil ) {
[_locationManager requestWhenInUseAuthorization];
} else {
errorHandler(@"MISSING_USAGE_DESCRIPTION", @"To use location from iOS8 you need to define at least NSLocationWhenInUseUsageDescription and optionally NSLocationAlwaysAndWhenInUseUsageDescription in the app bundle's Info.plist file");
return;
}
#endif
} else if (permission == PermissionGroupLocationAlways) {
if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"] != nil) {
#if PERMISSION_LOCATION
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
errorHandler(@"MISSING_WHENINUSE_PERMISSION", @"Must have \"When in use\" permission before it is allowed to request \"Always\" permission.");
return;
}
if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"] != nil || [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysAndWhenInUseUsageDescription"] != nil ) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveActivityNotification:) name:UIApplicationDidBecomeActiveNotification object:nil];
[_locationManager requestAlwaysAuthorization];
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:UserDefaultPermissionRequestedKey];
} else {
[[NSException exceptionWithName:NSInternalInconsistencyException reason:@"To use location in iOS8 you need to define NSLocationAlwaysUsageDescription in the app bundle's Info.plist file" userInfo:nil] raise];
errorHandler(@"MISSING_USAGE_DESCRIPTION", @"To always use location from iOS8 you need to define at least NSLocationWhenInUseUsageDescription and optionally NSLocationAlwaysAndWhenInUseUsageDescription in the app bundle's Info.plist file");
return;
}
#endif
} else if (permission == PermissionGroupLocationWhenInUse) {
if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] != nil) {
if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] != nil ) {
[_locationManager requestWhenInUseAuthorization];
} else {
[[NSException exceptionWithName:NSInternalInconsistencyException reason:@"To use location in iOS8 you need to define NSLocationWhenInUseUsageDescription in the app bundle's Info.plist file" userInfo:nil] raise];
errorHandler(@"MISSING_USAGE_DESCRIPTION", @"To use location from iOS8 you need to define at least NSLocationWhenInUseUsageDescription and optionally NSLocationAlwaysAndWhenInUseUsageDescription in the app bundle's Info.plist file");
return;
}
}
}
......
......@@ -17,7 +17,7 @@
completionHandler(ServiceStatusNotApplicable);
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusDenied) {
completionHandler(status);
......
......@@ -19,7 +19,7 @@
completionHandler(ServiceStatusNotApplicable);
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (@available(iOS 12.0, *)) {
if (status != PermissionStatusDenied && status != PermissionStatusProvisional) {
......
......@@ -8,11 +8,12 @@
typedef void (^ServiceStatusHandler)(ServiceStatus serviceStatus);
typedef void (^PermissionStatusHandler)(PermissionStatus permissionStatus);
typedef void (^PermissionErrorHandler)(NSString* errorCode, NSString* errorDescription);
@protocol PermissionStrategy <NSObject>
- (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission;
- (void)checkServiceStatus:(PermissionGroup)permission completionHandler:(ServiceStatusHandler)completionHandler;
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler;
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler;
@end
......@@ -24,7 +24,7 @@
completionHandler([self canDevicePlaceAPhoneCall] ? ServiceStatusEnabled : ServiceStatusDisabled);
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler {
completionHandler(PermissionStatusPermanentlyDenied);
}
......
......@@ -28,7 +28,7 @@
completionHandler(ServiceStatusNotApplicable);
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusDenied) {
......
......@@ -23,7 +23,7 @@
completionHandler(ServiceStatusDisabled);
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusDenied) {
......
......@@ -16,7 +16,7 @@
completionHandler(ServiceStatusNotApplicable);
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusDenied) {
......
......@@ -17,7 +17,7 @@
completionHandler(ServiceStatusNotApplicable);
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler {
completionHandler([StoragePermissionStrategy permissionStatus]);
}
......
......@@ -16,7 +16,7 @@
completionHandler(ServiceStatusDisabled);
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler {
completionHandler(PermissionStatusPermanentlyDenied);
}
@end
......@@ -2,7 +2,7 @@ name: permission_handler_apple
description: Permission plugin for Flutter. This plugin provides the iOS API to request and check permissions.
repository: https://github.com/baseflow/flutter-permission-handler
issue_tracker: https://github.com/Baseflow/flutter-permission-handler/issues
version: 9.4.2
version: 9.4.3
environment:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment