From 072d3f494c8221d6c5a428f77bda86fe5a2d1c1b Mon Sep 17 00:00:00 2001 From: Pierre-Monier Date: Sat, 20 Jul 2024 16:20:30 +0200 Subject: [PATCH 01/16] feat: define getLocationAccuracy interface --- .../lib/permission_handler_platform_interface.dart | 1 + .../lib/src/location_accuracy_status.dart | 14 ++++++++++++++ .../src/permission_handler_platform_interface.dart | 5 +++++ 3 files changed, 20 insertions(+) create mode 100644 permission_handler_platform_interface/lib/src/location_accuracy_status.dart diff --git a/permission_handler_platform_interface/lib/permission_handler_platform_interface.dart b/permission_handler_platform_interface/lib/permission_handler_platform_interface.dart index 4f44f6143..e9b19bade 100644 --- a/permission_handler_platform_interface/lib/permission_handler_platform_interface.dart +++ b/permission_handler_platform_interface/lib/permission_handler_platform_interface.dart @@ -9,3 +9,4 @@ part 'src/permission_handler_platform_interface.dart'; part 'src/permission_status.dart'; part 'src/permissions.dart'; part 'src/service_status.dart'; +part 'src/location_accuracy_status.dart'; diff --git a/permission_handler_platform_interface/lib/src/location_accuracy_status.dart b/permission_handler_platform_interface/lib/src/location_accuracy_status.dart new file mode 100644 index 000000000..00e187017 --- /dev/null +++ b/permission_handler_platform_interface/lib/src/location_accuracy_status.dart @@ -0,0 +1,14 @@ +part of permission_handler_platform_interface; + +/// Represent the current Location Accuracy Status on iOS 14.0 and higher and +/// Android 12 and higher. +enum LocationAccuracyStatus { + /// An approximate location will be returned. + reduced, + + /// A precise location will be returned. + precise, + + /// We can't determine the location accuracy status. + unknown, +} diff --git a/permission_handler_platform_interface/lib/src/permission_handler_platform_interface.dart b/permission_handler_platform_interface/lib/src/permission_handler_platform_interface.dart index 65d965bf6..816cd229f 100644 --- a/permission_handler_platform_interface/lib/src/permission_handler_platform_interface.dart +++ b/permission_handler_platform_interface/lib/src/permission_handler_platform_interface.dart @@ -85,4 +85,9 @@ abstract class PermissionHandlerPlatform extends PlatformInterface { throw UnimplementedError( 'shouldShowRequestPermissionRationale() has not been implemented.'); } + + /// Get the location accuracy given to your app. + Future getLocationAccuracy() { + throw UnimplementedError('getLocationAccuracy() has not been implemented.'); + } } From 5acf4a11f62e49d6330a11173ffdcd1e24e0e273 Mon Sep 17 00:00:00 2001 From: Pierre-Monier Date: Sat, 20 Jul 2024 17:14:37 +0200 Subject: [PATCH 02/16] feat: add dummy test on example app --- .../example/lib/main.dart | 56 ++++++++++++++++--- permission_handler_apple/example/pubspec.yaml | 4 ++ .../method_channel_permission_handler.dart | 6 ++ ...permission_handler_platform_interface.dart | 2 + 4 files changed, 59 insertions(+), 9 deletions(-) diff --git a/permission_handler_apple/example/lib/main.dart b/permission_handler_apple/example/lib/main.dart index f35cf7592..3abbe0be9 100644 --- a/permission_handler_apple/example/lib/main.dart +++ b/permission_handler_apple/example/lib/main.dart @@ -104,6 +104,14 @@ class _PermissionState extends State { } } + Widget getCheckPermissionServiceStatus() { + return _InfoButton( + onPressed: () { + checkServiceStatus(context, _permission as PermissionWithService); + }, + ); + } + @override Widget build(BuildContext context) { return ListTile( @@ -116,15 +124,18 @@ class _PermissionState extends State { style: TextStyle(color: getPermissionColor()), ), trailing: (_permission is PermissionWithService) - ? IconButton( - icon: const Icon( - Icons.info, - color: Colors.white, - ), - onPressed: () { - checkServiceStatus( - context, _permission as PermissionWithService); - }) + ? _permission == Permission.location + ? Wrap( + children: [ + _InfoButton(onPressed: () { + checkLocationAccuracy( + context, + ); + }), + getCheckPermissionServiceStatus() + ], + ) + : getCheckPermissionServiceStatus() : null, onTap: () { requestPermission(_permission); @@ -140,6 +151,13 @@ class _PermissionState extends State { )); } + void checkLocationAccuracy(BuildContext context) async { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: + Text((await _permissionHandler.getLocationAccuracy()).toString()), + )); + } + Future requestPermission(Permission permission) async { final status = await _permissionHandler.requestPermissions([permission]); @@ -150,3 +168,23 @@ class _PermissionState extends State { }); } } + +class _InfoButton extends StatelessWidget { + const _InfoButton({ + Key? key, + required this.onPressed, + }) : super(key: key); + + final VoidCallback onPressed; + + @override + Widget build(BuildContext context) { + return IconButton( + icon: const Icon( + Icons.info, + color: Colors.white, + ), + onPressed: onPressed, + ); + } +} diff --git a/permission_handler_apple/example/pubspec.yaml b/permission_handler_apple/example/pubspec.yaml index 1a9636230..a6b7feffc 100644 --- a/permission_handler_apple/example/pubspec.yaml +++ b/permission_handler_apple/example/pubspec.yaml @@ -23,6 +23,10 @@ dev_dependencies: url_launcher: ^6.0.12 +dependency_overrides: + permission_handler_platform_interface: + path: ../../permission_handler_platform_interface + flutter: uses-material-design: true diff --git a/permission_handler_platform_interface/lib/src/method_channel/method_channel_permission_handler.dart b/permission_handler_platform_interface/lib/src/method_channel/method_channel_permission_handler.dart index 5f03e3e7a..86a6c47c1 100644 --- a/permission_handler_platform_interface/lib/src/method_channel/method_channel_permission_handler.dart +++ b/permission_handler_platform_interface/lib/src/method_channel/method_channel_permission_handler.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; +import 'package:meta/meta.dart'; import '../../permission_handler_platform_interface.dart'; import 'utils/codec.dart'; @@ -98,4 +99,9 @@ class MethodChannelPermissionHandler extends PermissionHandlerPlatform { return shouldShowRationale ?? false; } + + @override + Future getLocationAccuracy() async { + return LocationAccuracyStatus.unknown; + } } diff --git a/permission_handler_platform_interface/lib/src/permission_handler_platform_interface.dart b/permission_handler_platform_interface/lib/src/permission_handler_platform_interface.dart index 816cd229f..195e16349 100644 --- a/permission_handler_platform_interface/lib/src/permission_handler_platform_interface.dart +++ b/permission_handler_platform_interface/lib/src/permission_handler_platform_interface.dart @@ -87,6 +87,8 @@ abstract class PermissionHandlerPlatform extends PlatformInterface { } /// Get the location accuracy given to your app. + /// + /// Currently only supported on iOS 14.0 and higher. Future getLocationAccuracy() { throw UnimplementedError('getLocationAccuracy() has not been implemented.'); } From 0b402bb320e00f0aa9be76b2a4fb9180e0569b93 Mon Sep 17 00:00:00 2001 From: Pierre-Monier Date: Sat, 20 Jul 2024 17:43:02 +0200 Subject: [PATCH 03/16] feat: add native dart link --- .../ios/Classes/PermissionHandlerPlugin.m | 4 ++- .../lib/src/location_accuracy_status.dart | 26 +++++++++++++++++++ .../method_channel_permission_handler.dart | 9 ++++++- .../lib/src/method_channel/utils/codec.dart | 5 ++++ 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/permission_handler_apple/ios/Classes/PermissionHandlerPlugin.m b/permission_handler_apple/ios/Classes/PermissionHandlerPlugin.m index cfbad93cb..35cb4063c 100644 --- a/permission_handler_apple/ios/Classes/PermissionHandlerPlugin.m +++ b/permission_handler_apple/ios/Classes/PermissionHandlerPlugin.m @@ -57,7 +57,9 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result result(@false); } else if ([@"openAppSettings" isEqualToString:call.method]) { [PermissionManager openAppSettings:result]; - } else { + } else if ([@"getLocationAccuracy" isEqualToString:call.method]) { + result(@0); + } else { result(FlutterMethodNotImplemented); } } diff --git a/permission_handler_platform_interface/lib/src/location_accuracy_status.dart b/permission_handler_platform_interface/lib/src/location_accuracy_status.dart index 00e187017..1780b5347 100644 --- a/permission_handler_platform_interface/lib/src/location_accuracy_status.dart +++ b/permission_handler_platform_interface/lib/src/location_accuracy_status.dart @@ -12,3 +12,29 @@ enum LocationAccuracyStatus { /// We can't determine the location accuracy status. unknown, } + +/// Conversion extension methods for the [LocationAccuracyStatus] type. +extension LocationAccuracyStatusValue on LocationAccuracyStatus { + /// Converts the [LocationAccuracyStatus] value into an integer. + int get value { + switch (this) { + case LocationAccuracyStatus.reduced: + return 0; + case LocationAccuracyStatus.precise: + return 1; + case LocationAccuracyStatus.unknown: + return 2; + default: + throw UnimplementedError(); + } + } + + /// Converts the supplied integer value into a [LocationAccuracyStatus] enum. + static LocationAccuracyStatus statusByValue(int value) { + return [ + LocationAccuracyStatus.reduced, + LocationAccuracyStatus.precise, + LocationAccuracyStatus.unknown, + ][value]; + } +} diff --git a/permission_handler_platform_interface/lib/src/method_channel/method_channel_permission_handler.dart b/permission_handler_platform_interface/lib/src/method_channel/method_channel_permission_handler.dart index 86a6c47c1..0c0bcf5f6 100644 --- a/permission_handler_platform_interface/lib/src/method_channel/method_channel_permission_handler.dart +++ b/permission_handler_platform_interface/lib/src/method_channel/method_channel_permission_handler.dart @@ -102,6 +102,13 @@ class MethodChannelPermissionHandler extends PermissionHandlerPlatform { @override Future getLocationAccuracy() async { - return LocationAccuracyStatus.unknown; + if (defaultTargetPlatform != TargetPlatform.iOS) { + return LocationAccuracyStatus.unknown; + } + + final locationAccuracyStatus = + await _methodChannel.invokeMethod('getLocationAccuracy'); + + return decodeLocationAccuracyStatus(locationAccuracyStatus); } } diff --git a/permission_handler_platform_interface/lib/src/method_channel/utils/codec.dart b/permission_handler_platform_interface/lib/src/method_channel/utils/codec.dart index dc5db075c..877205510 100644 --- a/permission_handler_platform_interface/lib/src/method_channel/utils/codec.dart +++ b/permission_handler_platform_interface/lib/src/method_channel/utils/codec.dart @@ -18,6 +18,11 @@ Map decodePermissionRequestResult( Permission.byValue(key), PermissionStatusValue.statusByValue(value))); } +/// Convert the given [value] into a [LocationAccuracyStatus] instance. +LocationAccuracyStatus decodeLocationAccuracyStatus(int value) { + return LocationAccuracyStatusValue.statusByValue(value); +} + /// Converts the given [List] of [Permission]s into a [List] of [int]s which /// can be sent on the Flutter method channel. List encodePermissions(List permissions) { From 61ea8a263bdb12f94abc390f851e5b306e6e0dce Mon Sep 17 00:00:00 2001 From: Pierre-Monier Date: Mon, 27 Jan 2025 14:14:51 +0100 Subject: [PATCH 04/16] feat: add API design for location precision on iOS --- permission_handler_apple/example/lib/main.dart | 18 ++++++++++++++++-- .../ios/Classes/PermissionHandlerPlugin.m | 6 +++++- .../method_channel_permission_handler.dart | 12 ++++++++++++ .../permission_handler_platform_interface.dart | 6 ++++++ 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/permission_handler_apple/example/lib/main.dart b/permission_handler_apple/example/lib/main.dart index 3abbe0be9..864208d11 100644 --- a/permission_handler_apple/example/lib/main.dart +++ b/permission_handler_apple/example/lib/main.dart @@ -152,9 +152,23 @@ class _PermissionState extends State { } void checkLocationAccuracy(BuildContext context) async { + final locationAccuracyStatus = + await _permissionHandler.getLocationAccuracy(); + _showLocationAccuracySnackBar(context, locationAccuracyStatus); + } + + void _showLocationAccuracySnackBar( + BuildContext context, LocationAccuracyStatus locationAccuracyStatus) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: - Text((await _permissionHandler.getLocationAccuracy()).toString()), + content: Text(locationAccuracyStatus.toString()), + action: SnackBarAction( + label: 'Request', + onPressed: () async { + final locationAccuracyStatus = + await _permissionHandler.requestPreciseLocation(); + _showLocationAccuracySnackBar(context, locationAccuracyStatus); + }, + ), )); } diff --git a/permission_handler_apple/ios/Classes/PermissionHandlerPlugin.m b/permission_handler_apple/ios/Classes/PermissionHandlerPlugin.m index 35cb4063c..7701584b7 100644 --- a/permission_handler_apple/ios/Classes/PermissionHandlerPlugin.m +++ b/permission_handler_apple/ios/Classes/PermissionHandlerPlugin.m @@ -58,8 +58,12 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result } else if ([@"openAppSettings" isEqualToString:call.method]) { [PermissionManager openAppSettings:result]; } else if ([@"getLocationAccuracy" isEqualToString:call.method]) { + // TODO: Implement getLocationAccuracy to return the actual location accuracy status result(@0); - } else { + } else if ([@"requestPreciseLocation" isEqualToString:call.method]) { + // TODO: Implement requestPreciseLocation to request precise location access + result(@0); + } else { result(FlutterMethodNotImplemented); } } diff --git a/permission_handler_platform_interface/lib/src/method_channel/method_channel_permission_handler.dart b/permission_handler_platform_interface/lib/src/method_channel/method_channel_permission_handler.dart index 0c0bcf5f6..a29e25b7d 100644 --- a/permission_handler_platform_interface/lib/src/method_channel/method_channel_permission_handler.dart +++ b/permission_handler_platform_interface/lib/src/method_channel/method_channel_permission_handler.dart @@ -111,4 +111,16 @@ class MethodChannelPermissionHandler extends PermissionHandlerPlatform { return decodeLocationAccuracyStatus(locationAccuracyStatus); } + + @override + Future requestPreciseLocation() async { + if (defaultTargetPlatform != TargetPlatform.iOS) { + return LocationAccuracyStatus.unknown; + } + + final locationAccuracyStatus = + await _methodChannel.invokeMethod('requestPreciseLocation'); + + return decodeLocationAccuracyStatus(locationAccuracyStatus); + } } diff --git a/permission_handler_platform_interface/lib/src/permission_handler_platform_interface.dart b/permission_handler_platform_interface/lib/src/permission_handler_platform_interface.dart index 195e16349..4daab3307 100644 --- a/permission_handler_platform_interface/lib/src/permission_handler_platform_interface.dart +++ b/permission_handler_platform_interface/lib/src/permission_handler_platform_interface.dart @@ -92,4 +92,10 @@ abstract class PermissionHandlerPlatform extends PlatformInterface { Future getLocationAccuracy() { throw UnimplementedError('getLocationAccuracy() has not been implemented.'); } + + /// Request precise location access + Future requestPreciseLocation() { + throw UnimplementedError( + 'requestPreciseLocation() has not been implemented.'); + } } From 412de0f4dd91bcd65fbd78527ef2d2a9397d8c97 Mon Sep 17 00:00:00 2001 From: Pierre-Monier Date: Mon, 27 Jan 2025 14:36:00 +0100 Subject: [PATCH 05/16] feat: add LocationAccuracyStatus test --- .../lib/src/location_accuracy_status.dart | 25 ++++++ .../src/location_accuracy_status_test.dart | 76 +++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 permission_handler_platform_interface/test/src/location_accuracy_status_test.dart diff --git a/permission_handler_platform_interface/lib/src/location_accuracy_status.dart b/permission_handler_platform_interface/lib/src/location_accuracy_status.dart index 1780b5347..c168cb5b3 100644 --- a/permission_handler_platform_interface/lib/src/location_accuracy_status.dart +++ b/permission_handler_platform_interface/lib/src/location_accuracy_status.dart @@ -38,3 +38,28 @@ extension LocationAccuracyStatusValue on LocationAccuracyStatus { ][value]; } } + +/// Utility getter extensions for the [LocationAccuracyStatus] type. +extension LocationAccuracyStatusGetters on LocationAccuracyStatus { + /// If the location accuracy is reduced. + bool get isReduced => this == LocationAccuracyStatus.reduced; + + /// If the location accuracy is precise. + bool get isPrecise => this == LocationAccuracyStatus.precise; + + /// If the location accuracy status is unknown. + bool get isUnknown => this == LocationAccuracyStatus.unknown; +} + +/// Utility getter extensions for the `Future` type. +extension FutureLocationAccuracyStatusGetters + on Future { + /// If the location accuracy is reduced. + Future get isReduced async => (await this).isReduced; + + /// If the location accuracy is precise. + Future get isPrecise async => (await this).isPrecise; + + /// If the location accuracy status is unknown. + Future get isUnknown async => (await this).isUnknown; +} diff --git a/permission_handler_platform_interface/test/src/location_accuracy_status_test.dart b/permission_handler_platform_interface/test/src/location_accuracy_status_test.dart new file mode 100644 index 000000000..01560dbe0 --- /dev/null +++ b/permission_handler_platform_interface/test/src/location_accuracy_status_test.dart @@ -0,0 +1,76 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:permission_handler_platform_interface/permission_handler_platform_interface.dart'; + +void main() { + group('LocationAccuracyStatus', () { + test('LocationAccuracyStatus should contain 3 options', () { + const values = LocationAccuracyStatus.values; + + expect(values.length, 3); + }); + + test('LocationAccuracyStatus enum should have items in correct index', () { + const values = LocationAccuracyStatus.values; + + expect(values[0], LocationAccuracyStatus.reduced); + expect(values[1], LocationAccuracyStatus.precise); + expect(values[2], LocationAccuracyStatus.unknown); + }); + }); + + group('LocationAccuracyStatusValue', () { + test('LocationAccuracyStatusValue returns right integer', () { + expect(LocationAccuracyStatus.reduced.value, 0); + expect(LocationAccuracyStatus.precise.value, 1); + expect(LocationAccuracyStatus.unknown.value, 2); + }); + + test( + // ignore: lines_longer_than_80_chars + 'statusByValue should return right index int that corresponds with the right LocationAccuracyStatus', + () { + expect(LocationAccuracyStatusValue.statusByValue(0), + LocationAccuracyStatus.reduced); + expect(LocationAccuracyStatusValue.statusByValue(1), + LocationAccuracyStatus.precise); + expect(LocationAccuracyStatusValue.statusByValue(2), + LocationAccuracyStatus.unknown); + }); + }); + + group('LocationAccuracyStatusGetters', () { + test('Getters should return true if statement is met', () { + expect(LocationAccuracyStatus.reduced.isReduced, true); + expect(LocationAccuracyStatus.precise.isPrecise, true); + expect(LocationAccuracyStatus.unknown.isUnknown, true); + }); + + test('Getters should return false if statement is not met', () { + expect(LocationAccuracyStatus.reduced.isPrecise, false); + expect(LocationAccuracyStatus.reduced.isUnknown, false); + expect(LocationAccuracyStatus.precise.isReduced, false); + expect(LocationAccuracyStatus.precise.isUnknown, false); + expect(LocationAccuracyStatus.unknown.isReduced, false); + expect(LocationAccuracyStatus.unknown.isPrecise, false); + }); + }); + + group('FutureLocationAccuracyStatusGetters', () { + mockFuture(LocationAccuracyStatus status) => Future.value(status); + + test('Getters should return true if statement is met', () async { + expect(await mockFuture(LocationAccuracyStatus.reduced).isReduced, true); + expect(await mockFuture(LocationAccuracyStatus.precise).isPrecise, true); + expect(await mockFuture(LocationAccuracyStatus.unknown).isUnknown, true); + }); + + test('Getters should return false if statement is not met', () async { + expect(await mockFuture(LocationAccuracyStatus.reduced).isPrecise, false); + expect(await mockFuture(LocationAccuracyStatus.reduced).isUnknown, false); + expect(await mockFuture(LocationAccuracyStatus.precise).isReduced, false); + expect(await mockFuture(LocationAccuracyStatus.precise).isUnknown, false); + expect(await mockFuture(LocationAccuracyStatus.unknown).isReduced, false); + expect(await mockFuture(LocationAccuracyStatus.unknown).isPrecise, false); + }); + }); +} From 9cb415e4bcac845160cdb34636b69616085d620d Mon Sep 17 00:00:00 2001 From: Pierre-Monier Date: Mon, 27 Jan 2025 14:39:11 +0100 Subject: [PATCH 06/16] feat: add test for codec --- .../test/src/method_channel/utils/coded_test.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/permission_handler_platform_interface/test/src/method_channel/utils/coded_test.dart b/permission_handler_platform_interface/test/src/method_channel/utils/coded_test.dart index 1742b9fc6..86fed65d6 100644 --- a/permission_handler_platform_interface/test/src/method_channel/utils/coded_test.dart +++ b/permission_handler_platform_interface/test/src/method_channel/utils/coded_test.dart @@ -32,5 +32,10 @@ void main() { expect(integers.first, isA()); }); + + test('decodeLocationAccuracyStatus should return a LocationAccuracyStatus', + () { + expect(decodeLocationAccuracyStatus(0), LocationAccuracyStatus.reduced); + }); }); } From 60f51d9589daea9d1767dbed216f5c3f1449dc36 Mon Sep 17 00:00:00 2001 From: Pierre-Monier Date: Mon, 27 Jan 2025 15:17:06 +0100 Subject: [PATCH 07/16] feat: add test for permission handler --- ...ethod_channel_permission_handler_test.dart | 59 +++++++++++++++++++ ...ssion_handler_platform_interface_test.dart | 22 +++++++ 2 files changed, 81 insertions(+) diff --git a/permission_handler_platform_interface/test/src/method_channel/method_channel_permission_handler_test.dart b/permission_handler_platform_interface/test/src/method_channel/method_channel_permission_handler_test.dart index c03c279a1..8fa3097bc 100644 --- a/permission_handler_platform_interface/test/src/method_channel/method_channel_permission_handler_test.dart +++ b/permission_handler_platform_interface/test/src/method_channel/method_channel_permission_handler_test.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:permission_handler_platform_interface/permission_handler_platform_interface.dart'; import 'package:permission_handler_platform_interface/src/method_channel/method_channel_permission_handler.dart'; @@ -202,4 +203,62 @@ void main() { expect(shouldShowRationale, true); }); }); + + group('getLocationAccuracy:', () { + final supportedPlatforms = [TargetPlatform.iOS]; + tearDown(() { + debugDefaultTargetPlatformOverride = null; + }); + + group('Unsupported platform', () { + final unsupportedPlatforms = TargetPlatform.values + .where((element) => !supportedPlatforms.contains(element)); + for (final platform in unsupportedPlatforms) { + test('Should return unknown accuracy on $platform', () async { + debugDefaultTargetPlatformOverride = platform; + // We mock the return of a precise location accuracy status + // since this platform does not support location accuracy, + // we expect the result to be unknown. + MethodChannelMock( + channelName: 'flutter.baseflow.com/permissions/methods', + method: 'getLocationAccuracy', + result: LocationAccuracyStatus.precise.value, + ); + + final accuracy = + await MethodChannelPermissionHandler().getLocationAccuracy(); + expect(accuracy, LocationAccuracyStatus.unknown); + }); + } + }); + + group('Supported Platform', () { + for (final platform in supportedPlatforms) { + test('Should return precise accuracy on $platform', () async { + debugDefaultTargetPlatformOverride = platform; + MethodChannelMock( + channelName: 'flutter.baseflow.com/permissions/methods', + method: 'getLocationAccuracy', + result: LocationAccuracyStatus.precise.value, + ); + + final accuracy = + await MethodChannelPermissionHandler().getLocationAccuracy(); + expect(accuracy, LocationAccuracyStatus.precise); + }); + test('Should return reduced accuracy on $platform', () async { + debugDefaultTargetPlatformOverride = platform; + MethodChannelMock( + channelName: 'flutter.baseflow.com/permissions/methods', + method: 'getLocationAccuracy', + result: LocationAccuracyStatus.reduced.value, + ); + + final accuracy = + await MethodChannelPermissionHandler().getLocationAccuracy(); + expect(accuracy, LocationAccuracyStatus.reduced); + }); + } + }); + }); } diff --git a/permission_handler_platform_interface/test/src/permission_handler_platform_interface_test.dart b/permission_handler_platform_interface/test/src/permission_handler_platform_interface_test.dart index c965e72ed..d67b6fa90 100644 --- a/permission_handler_platform_interface/test/src/permission_handler_platform_interface_test.dart +++ b/permission_handler_platform_interface/test/src/permission_handler_platform_interface_test.dart @@ -85,6 +85,28 @@ void main() { Permission.accessMediaLocation); }, throwsUnimplementedError); }); + + test( + // ignore: lines_longer_than_80_chars + 'Default implementation of getLocationAccuracy should throw unimplemented error', + () { + final permissionHandlerPlatform = ExtendsPermissionHandlerPlatform(); + + expect(() { + permissionHandlerPlatform.getLocationAccuracy(); + }, throwsUnimplementedError); + }); + + test( + // ignore: lines_longer_than_80_chars + 'Default implementation of requestPreciseLocation should throw unimplemented error', + () { + final permissionHandlerPlatform = ExtendsPermissionHandlerPlatform(); + + expect(() { + permissionHandlerPlatform.requestPreciseLocation(); + }, throwsUnimplementedError); + }); }); } From bdfb00abd0ad16c3b263f12ef0f7308a93c92bb9 Mon Sep 17 00:00:00 2001 From: Pierre-Monier Date: Mon, 27 Jan 2025 15:32:16 +0100 Subject: [PATCH 08/16] feat: add test for requestPreciseLocation --- ...ethod_channel_permission_handler_test.dart | 118 ++++++++++-------- 1 file changed, 65 insertions(+), 53 deletions(-) diff --git a/permission_handler_platform_interface/test/src/method_channel/method_channel_permission_handler_test.dart b/permission_handler_platform_interface/test/src/method_channel/method_channel_permission_handler_test.dart index 8fa3097bc..8989fa821 100644 --- a/permission_handler_platform_interface/test/src/method_channel/method_channel_permission_handler_test.dart +++ b/permission_handler_platform_interface/test/src/method_channel/method_channel_permission_handler_test.dart @@ -205,60 +205,72 @@ void main() { }); group('getLocationAccuracy:', () { - final supportedPlatforms = [TargetPlatform.iOS]; - tearDown(() { - debugDefaultTargetPlatformOverride = null; - }); + _testLocationAccuracyMethod( + methodName: 'getLocationAccuracy', + methodUnderTest: () => + MethodChannelPermissionHandler().getLocationAccuracy()); + }); - group('Unsupported platform', () { - final unsupportedPlatforms = TargetPlatform.values - .where((element) => !supportedPlatforms.contains(element)); - for (final platform in unsupportedPlatforms) { - test('Should return unknown accuracy on $platform', () async { - debugDefaultTargetPlatformOverride = platform; - // We mock the return of a precise location accuracy status - // since this platform does not support location accuracy, - // we expect the result to be unknown. - MethodChannelMock( - channelName: 'flutter.baseflow.com/permissions/methods', - method: 'getLocationAccuracy', - result: LocationAccuracyStatus.precise.value, - ); - - final accuracy = - await MethodChannelPermissionHandler().getLocationAccuracy(); - expect(accuracy, LocationAccuracyStatus.unknown); - }); - } - }); + group('requestPreciseLocation:', () { + _testLocationAccuracyMethod( + methodName: 'requestPreciseLocation', + methodUnderTest: () => + MethodChannelPermissionHandler().requestPreciseLocation()); + }); +} - group('Supported Platform', () { - for (final platform in supportedPlatforms) { - test('Should return precise accuracy on $platform', () async { - debugDefaultTargetPlatformOverride = platform; - MethodChannelMock( - channelName: 'flutter.baseflow.com/permissions/methods', - method: 'getLocationAccuracy', - result: LocationAccuracyStatus.precise.value, - ); - - final accuracy = - await MethodChannelPermissionHandler().getLocationAccuracy(); - expect(accuracy, LocationAccuracyStatus.precise); - }); - test('Should return reduced accuracy on $platform', () async { - debugDefaultTargetPlatformOverride = platform; - MethodChannelMock( - channelName: 'flutter.baseflow.com/permissions/methods', - method: 'getLocationAccuracy', - result: LocationAccuracyStatus.reduced.value, - ); - - final accuracy = - await MethodChannelPermissionHandler().getLocationAccuracy(); - expect(accuracy, LocationAccuracyStatus.reduced); - }); - } - }); +void _testLocationAccuracyMethod({ + required String methodName, + required Future Function() methodUnderTest, +}) { + final supportedPlatforms = [TargetPlatform.iOS]; + group('Unsupported Platforms', () { + final unsupportedPlatforms = TargetPlatform.values + .where((element) => !supportedPlatforms.contains(element)); + + for (final platform in unsupportedPlatforms) { + test('$methodName should return unknown accuracy on $platform', () async { + debugDefaultTargetPlatformOverride = platform; + // We mock the return of a precise location accuracy status + // since this platform does not support location accuracy, + // we expect the result to be unknown. + MethodChannelMock( + channelName: 'flutter.baseflow.com/permissions/methods', + method: methodName, + result: LocationAccuracyStatus.precise.value, + ); + + final accuracy = await methodUnderTest(); + expect(accuracy, LocationAccuracyStatus.unknown); + }); + } + }); + + group('Supported Platform', () { + for (final platform in supportedPlatforms) { + test('$methodName should return precise accuracy on $platform', () async { + debugDefaultTargetPlatformOverride = platform; + MethodChannelMock( + channelName: 'flutter.baseflow.com/permissions/methods', + method: methodName, + result: LocationAccuracyStatus.precise.value, + ); + + final accuracy = await methodUnderTest(); + expect(accuracy, LocationAccuracyStatus.precise); + }); + + test('$methodName should return reduced accuracy on $platform', () async { + debugDefaultTargetPlatformOverride = platform; + MethodChannelMock( + channelName: 'flutter.baseflow.com/permissions/methods', + method: methodName, + result: LocationAccuracyStatus.reduced.value, + ); + + final accuracy = await methodUnderTest(); + expect(accuracy, LocationAccuracyStatus.reduced); + }); + } }); } From 8194c58a2c28644753d5e082501f3f8383062179 Mon Sep 17 00:00:00 2001 From: Pierre-Monier Date: Sun, 9 Feb 2025 14:39:17 +0100 Subject: [PATCH 09/16] chore: clean up locationPrecise permission --- permission_handler/README.md | 32 ++--- .../ios/Flutter/AppFrameworkInfo.plist | 2 +- permission_handler/example/ios/Podfile | 4 +- .../ios/Runner.xcodeproj/project.pbxproj | 26 +++- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- permission_handler_apple/example/ios/Podfile | 2 +- .../example/ios/Runner/Info.plist | 116 +++++++----------- .../strategies/LocationPermissionStrategy.m | 56 ++++++++- .../lib/src/permissions.dart | 2 +- 9 files changed, 146 insertions(+), 96 deletions(-) diff --git a/permission_handler/README.md b/permission_handler/README.md index 0ef5377b5..375766fd0 100644 --- a/permission_handler/README.md +++ b/permission_handler/README.md @@ -147,23 +147,23 @@ You must list the permission you want to use in your application: e.g. when you don't need camera permission, just delete 'NSCameraUsageDescription' The following lists the relationship between `Permission` and `The key of Info.plist`: -| Permission | Info.plist | Macro | -|---------------------------------------------------------------------------------------------| ------------------------------------------------------------------------------------------------------------- | ------------------------------------ | -| PermissionGroup.calendar (< iOS 17) | NSCalendarsUsageDescription | PERMISSION_EVENTS | -| PermissionGroup.calendarWriteOnly (iOS 17+) | NSCalendarsWriteOnlyAccessUsageDescription | PERMISSION_EVENTS | -| PermissionGroup.calendarFullAccess (iOS 17+) | NSCalendarsFullAccessUsageDescription | PERMISSION_EVENTS_FULL_ACCESS | -| PermissionGroup.reminders | NSRemindersUsageDescription | PERMISSION_REMINDERS | -| PermissionGroup.contacts | NSContactsUsageDescription | PERMISSION_CONTACTS | -| PermissionGroup.camera | NSCameraUsageDescription | PERMISSION_CAMERA | -| PermissionGroup.microphone | NSMicrophoneUsageDescription | PERMISSION_MICROPHONE | -| PermissionGroup.speech | NSSpeechRecognitionUsageDescription | PERMISSION_SPEECH_RECOGNIZER | -| PermissionGroup.photos | NSPhotoLibraryUsageDescription | PERMISSION_PHOTOS | -| PermissionGroup.photosAddOnly | NSPhotoLibraryAddUsageDescription | PERMISSION_PHOTOS_ADD_ONLY | -| PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse | NSLocationUsageDescription, NSLocationAlwaysAndWhenInUseUsageDescription, NSLocationWhenInUseUsageDescription | PERMISSION_LOCATION | -| PermissionGroup.locationWhenInUse | NSLocationWhenInUseUsageDescription | PERMISSION_LOCATION_WHENINUSE | -| PermissionGroup.notification | PermissionGroupNotification | PERMISSION_NOTIFICATIONS | +| Permission | Info.plist | Macro | +| ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ----------------------------- | +| PermissionGroup.calendar (< iOS 17) | NSCalendarsUsageDescription | PERMISSION_EVENTS | +| PermissionGroup.calendarWriteOnly (iOS 17+) | NSCalendarsWriteOnlyAccessUsageDescription | PERMISSION_EVENTS | +| PermissionGroup.calendarFullAccess (iOS 17+) | NSCalendarsFullAccessUsageDescription | PERMISSION_EVENTS_FULL_ACCESS | +| PermissionGroup.reminders | NSRemindersUsageDescription | PERMISSION_REMINDERS | +| PermissionGroup.contacts | NSContactsUsageDescription | PERMISSION_CONTACTS | +| PermissionGroup.camera | NSCameraUsageDescription | PERMISSION_CAMERA | +| PermissionGroup.microphone | NSMicrophoneUsageDescription | PERMISSION_MICROPHONE | +| PermissionGroup.speech | NSSpeechRecognitionUsageDescription | PERMISSION_SPEECH_RECOGNIZER | +| PermissionGroup.photos | NSPhotoLibraryUsageDescription | PERMISSION_PHOTOS | +| PermissionGroup.photosAddOnly | NSPhotoLibraryAddUsageDescription | PERMISSION_PHOTOS_ADD_ONLY | +| PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse | NSLocationUsageDescription, NSLocationAlwaysAndWhenInUseUsageDescription, NSLocationWhenInUseUsageDescription | PERMISSION_LOCATION | +| PermissionGroup.locationWhenInUse | NSLocationWhenInUseUsageDescription | PERMISSION_LOCATION_WHENINUSE | +| PermissionGroup.notification | PermissionGroupNotification | PERMISSION_NOTIFICATIONS | | PermissionGroup.mediaLibrary | NSAppleMusicUsageDescription, kTCCServiceMedia | -PERMISSION_MEDIA_LIBRARY | +| PERMISSION_MEDIA_LIBRARY | 4. Clean & Rebuild diff --git a/permission_handler/example/ios/Flutter/AppFrameworkInfo.plist b/permission_handler/example/ios/Flutter/AppFrameworkInfo.plist index 9625e105d..7c5696400 100644 --- a/permission_handler/example/ios/Flutter/AppFrameworkInfo.plist +++ b/permission_handler/example/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 12.0 diff --git a/permission_handler/example/ios/Podfile b/permission_handler/example/ios/Podfile index 008edb50d..a4fe59cbe 100644 --- a/permission_handler/example/ios/Podfile +++ b/permission_handler/example/ios/Podfile @@ -47,7 +47,7 @@ post_install do |installer| ## dart: [PermissionGroup.calendarWriteOnly, PermissionGroup.calendar (until iOS 16)] 'PERMISSION_EVENTS=1', - + ## dart: [PermissionGroup.calendarFullAccess, PermissionGroup.calendar (from iOS 17)] 'PERMISSION_EVENTS_FULL_ACCESS=1', @@ -69,7 +69,7 @@ post_install do |installer| ## dart: PermissionGroup.photos 'PERMISSION_PHOTOS=1', - ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse] + ## dart: [PermissionGroup.location, PermissionGroup.locationAlways] 'PERMISSION_LOCATION=1', ## dart: PermissionGroup.notification diff --git a/permission_handler/example/ios/Runner.xcodeproj/project.pbxproj b/permission_handler/example/ios/Runner.xcodeproj/project.pbxproj index 5b918732b..56eed4076 100644 --- a/permission_handler/example/ios/Runner.xcodeproj/project.pbxproj +++ b/permission_handler/example/ios/Runner.xcodeproj/project.pbxproj @@ -141,6 +141,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, D38B08CB85942E5D11545EE3 /* [CP] Embed Pods Frameworks */, + 2E66F0981C0A9CA5865C1D97 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -157,7 +158,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -199,6 +200,23 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 2E66F0981C0A9CA5865C1D97 /* [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; + }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -344,7 +362,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -430,7 +448,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -479,7 +497,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/permission_handler/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/permission_handler/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a6b826db2..5e31d3d34 100644 --- a/permission_handler/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/permission_handler/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ + NSLocationTemporaryUsageDescriptionDictionary + + YourPurposeKey + The example App requires temporary access to the device&apos;s precise location. + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable @@ -41,74 +46,47 @@ UIViewControllerBasedStatusBarAppearance - - - NSLocationWhenInUseUsageDescription - Need location when in use - NSLocationAlwaysAndWhenInUseUsageDescription - Always and when in use! - NSLocationUsageDescription - Older devices need location. - NSLocationAlwaysUsageDescription - Can I have location always? - - - NSAppleMusicUsageDescription - Music! - kTCCServiceMediaLibrary - media - - - NSCalendarsUsageDescription - Calendars - NSCalendarsFullAccessUsageDescription - Calendar full access - - - NSCameraUsageDescription - camera - - - NSContactsUsageDescription - contacts - - - NSMicrophoneUsageDescription - microphone - - - NSSpeechRecognitionUsageDescription - speech - - - NSMotionUsageDescription - motion - - - NSPhotoLibraryUsageDescription - photos - - - NSRemindersUsageDescription - reminders - - - NSBluetoothAlwaysUsageDescription - bluetooth - NSBluetoothPeripheralUsageDescription - bluetooth - - - NSUserTrackingUsageDescription - appTrackingTransparency - - - NSSiriUsageDescription - The example app would like access to Siri Kit to demonstrate requesting authorization. - - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - + NSLocationWhenInUseUsageDescription + Need location when in use + NSLocationAlwaysAndWhenInUseUsageDescription + Always and when in use! + NSLocationUsageDescription + Older devices need location. + NSLocationAlwaysUsageDescription + Can I have location always? + NSAppleMusicUsageDescription + Music! + kTCCServiceMediaLibrary + media + NSCalendarsUsageDescription + Calendars + NSCalendarsFullAccessUsageDescription + Calendar full access + NSCameraUsageDescription + camera + NSContactsUsageDescription + contacts + NSMicrophoneUsageDescription + microphone + NSSpeechRecognitionUsageDescription + speech + NSMotionUsageDescription + motion + NSPhotoLibraryUsageDescription + photos + NSRemindersUsageDescription + reminders + NSBluetoothAlwaysUsageDescription + bluetooth + NSBluetoothPeripheralUsageDescription + bluetooth + NSUserTrackingUsageDescription + appTrackingTransparency + NSSiriUsageDescription + The example app would like access to Siri Kit to demonstrate requesting authorization. + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + diff --git a/permission_handler_apple/ios/Classes/strategies/LocationPermissionStrategy.m b/permission_handler_apple/ios/Classes/strategies/LocationPermissionStrategy.m index a4f6b21f4..fb2e78dc8 100644 --- a/permission_handler_apple/ios/Classes/strategies/LocationPermissionStrategy.m +++ b/permission_handler_apple/ios/Classes/strategies/LocationPermissionStrategy.m @@ -11,6 +11,8 @@ @interface LocationPermissionStrategy () - (void) receiveActivityNotification:(NSNotification *)notification; +- (void)requestLocationPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler; +- (void)requestTemporaryFullAccuracy:(NSString * _Nullable)purposeKey completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler; @end @implementation LocationPermissionStrategy { @@ -32,8 +34,11 @@ - (instancetype)initWithLocationManager { } - (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission { - return [LocationPermissionStrategy permissionStatus:permission]; + PermissionStatus status = [LocationPermissionStrategy permissionStatus:permission]; + return status; + // return self.accuracyStatus; } + - (void)checkServiceStatus:(PermissionGroup)permission completionHandler:(ServiceStatusHandler)completionHandler { dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @@ -46,6 +51,11 @@ - (void)checkServiceStatus:(PermissionGroup)permission completionHandler:(Servic } - (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler { + // [self requestTemporaryFullAccuracy:@"YourPurposeKey" completionHandler: completionHandler errorHandler:errorHandler]; + [self requestLocationPermission:permission completionHandler:completionHandler errorHandler:errorHandler]; +} + +- (void)requestLocationPermission:(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 @@ -107,6 +117,29 @@ - (void)requestPermission:(PermissionGroup)permission completionHandler:(Permiss } } +- (void)requestTemporaryFullAccuracy:(NSString * _Nullable)purposeKey completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler { + if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationTemporaryUsageDescriptionDictionary"] == nil) { + return errorHandler(@"MISSING_USAGE_DESCRIPTION",@"The temporary accuracy dictionary key is not set in the infop.list"); + } + + #if TARGET_OS_OSX + return completionHandler(PermissionStatusGranted) + #else + if (@available(iOS 14.0, macOS 10.16, *)) { + [_locationManager requestTemporaryFullAccuracyAuthorizationWithPurposeKey:purposeKey + completion:^(NSError *_Nullable error) { + if ([self->_locationManager accuracyAuthorization] == CLAccuracyAuthorizationFullAccuracy) { + return completionHandler(PermissionStatusGranted); + } else { + return completionHandler(PermissionStatusDenied); + } + }]; + } else { + return completionHandler(PermissionStatusGranted); + } + #endif +} + - (void) receiveActivityNotification:(NSNotification *) notification { CLAuthorizationStatus status; if(@available(iOS 14.0, *)){ @@ -172,6 +205,27 @@ + (PermissionStatus)permissionStatus:(PermissionGroup)permission { return status; } +- (PermissionStatus) accuracyStatus { +#if TARGET_OS_OSX + return PermissionStatusGranted; +#else + if (@available(iOS 14, macOS 10.16, *)) { + switch (_locationManager.accuracyAuthorization) { + case CLAccuracyAuthorizationFullAccuracy: + return PermissionStatusGranted; + case CLAccuracyAuthorizationReducedAccuracy: + return PermissionStatusDenied; + default: + // Reduced location accuracy is the default on iOS 14+ and macOS 11+. + return PermissionStatusDenied; + } + } else { + // Approximate location is not available, return precise location. + return PermissionStatusGranted; + } +#endif +} + + (PermissionStatus)determinePermissionStatus:(PermissionGroup)permission authorizationStatus:(CLAuthorizationStatus)authorizationStatus { if (@available(iOS 8.0, *)) { diff --git a/permission_handler_platform_interface/lib/src/permissions.dart b/permission_handler_platform_interface/lib/src/permissions.dart index 15edb6ac7..b54895f28 100644 --- a/permission_handler_platform_interface/lib/src/permissions.dart +++ b/permission_handler_platform_interface/lib/src/permissions.dart @@ -411,7 +411,7 @@ class Permission { 'calendarWriteOnly', 'calendarFullAccess', 'assistant', - 'backgroundRefresh', + 'backgroundRefresh' ]; @override From 57a41ad7ffc461d59c92fa1e6a1b8bf84cea4bdc Mon Sep 17 00:00:00 2001 From: Pierre-Monier Date: Sun, 9 Feb 2025 16:32:47 +0100 Subject: [PATCH 10/16] refactor: use locationAccuracyHandler on the apple side --- .../example/lib/main.dart | 4 +- .../ios/Classes/LocationAccuracyHandler.h | 25 ++++++ .../ios/Classes/LocationAccuracyHandler.m | 78 +++++++++++++++++++ .../ios/Classes/PermissionHandlerEnums.h | 6 ++ .../ios/Classes/PermissionHandlerPlugin.m | 15 ++-- .../strategies/LocationPermissionStrategy.m | 25 +----- .../ios/Classes/util/Codec.h | 2 + .../ios/Classes/util/Codec.m | 4 + .../method_channel_permission_handler.dart | 11 ++- ...permission_handler_platform_interface.dart | 5 +- ...ethod_channel_permission_handler_test.dart | 8 +- ...ssion_handler_platform_interface_test.dart | 4 +- 12 files changed, 144 insertions(+), 43 deletions(-) create mode 100644 permission_handler_apple/ios/Classes/LocationAccuracyHandler.h create mode 100644 permission_handler_apple/ios/Classes/LocationAccuracyHandler.m diff --git a/permission_handler_apple/example/lib/main.dart b/permission_handler_apple/example/lib/main.dart index 864208d11..fa26f5e9f 100644 --- a/permission_handler_apple/example/lib/main.dart +++ b/permission_handler_apple/example/lib/main.dart @@ -164,8 +164,8 @@ class _PermissionState extends State { action: SnackBarAction( label: 'Request', onPressed: () async { - final locationAccuracyStatus = - await _permissionHandler.requestPreciseLocation(); + final locationAccuracyStatus = await _permissionHandler + .requestTemporaryFullAccuracy('YourPurposeKey'); _showLocationAccuracySnackBar(context, locationAccuracyStatus); }, ), diff --git a/permission_handler_apple/ios/Classes/LocationAccuracyHandler.h b/permission_handler_apple/ios/Classes/LocationAccuracyHandler.h new file mode 100644 index 000000000..08a241321 --- /dev/null +++ b/permission_handler_apple/ios/Classes/LocationAccuracyHandler.h @@ -0,0 +1,25 @@ +// +// LocationAccuracyHandler.h +// Pods +// +// Created by Pierre Monier on 09/02/2025. +// + +#ifndef LocationAccuracyHandler_h +#define LocationAccuracyHandler_h +#import "PermissionHandlerEnums.h" + +#if TARGET_OS_OSX +#import +#else +#import +#endif + +@interface LocationAccuracyHandler : NSObject + +- (LocationAccuracy) getLocationAccuracy; +- (void) requestTemporaryFullAccuracyWithResult:(FlutterResult _Nonnull)result purposeKey:(NSString * _Nullable)purposeKey; + +@end + +#endif /* LocationAccuracyHandler_h */ diff --git a/permission_handler_apple/ios/Classes/LocationAccuracyHandler.m b/permission_handler_apple/ios/Classes/LocationAccuracyHandler.m new file mode 100644 index 000000000..68c179603 --- /dev/null +++ b/permission_handler_apple/ios/Classes/LocationAccuracyHandler.m @@ -0,0 +1,78 @@ +// +// LocationAccuracyHandler.m +// permission_handler_apple +// +// Created by Pierre Monier on 09/02/2025. +// + +#import +#import +#import "LocationAccuracyHandler.h" +#import "PermissionHandlerEnums.h" +#import "util/Codec.h" + +@interface LocationAccuracyHandler() +@property (strong, nonatomic) CLLocationManager *locationManager; +@end + +@implementation LocationAccuracyHandler + +- (id) init { + self = [super init]; + + if (!self) { + return nil; + } + + self.locationManager = [[CLLocationManager alloc] init]; + return self; +} + +- (LocationAccuracy) getLocationAccuracy { +#if TARGET_OS_OSX + return LocationAccuracyPrecise; +#else + if (@available(iOS 14, macOS 10.16, *)) { + switch (_locationManager.accuracyAuthorization) { + case CLAccuracyAuthorizationFullAccuracy: + return LocationAccuracyPrecise; + case CLAccuracyAuthorizationReducedAccuracy: + return LocationAccuracyReduced; + default: + // Reduced location accuracy is the default on iOS 14+ and macOS 11+. + return LocationAccuracyReduced; + } + } else { + // Approximate location is not available, return precise location. + return LocationAccuracyPrecise; + } +#endif +} + +- (void)requestTemporaryFullAccuracyWithResult:(FlutterResult)result purposeKey:(NSString * _Nullable)purposeKey { + if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationTemporaryUsageDescriptionDictionary"] == nil) { + result([NSException exceptionWithName:@"MISSING_USAGE_DESCRIPTION" + reason:@"The temporary accuracy dictionary key is not set in the Info.plist" + userInfo:nil]); + } + + #if TARGET_OS_OSX + return result([Codec encodeLocationAccuracy:LocationAccuracyPrecise]); + #else + + if (@available(iOS 14.0, macOS 10.16, *)) { + [_locationManager requestTemporaryFullAccuracyAuthorizationWithPurposeKey:purposeKey + completion:^(NSError *_Nullable error) { + if ([self->_locationManager accuracyAuthorization] == CLAccuracyAuthorizationFullAccuracy) { + return result([Codec encodeLocationAccuracy:LocationAccuracyPrecise]); + } else { + return result([Codec encodeLocationAccuracy:LocationAccuracyReduced]); + } + }]; + } else { + return result([Codec encodeLocationAccuracy:LocationAccuracyPrecise]); + } + #endif +} + +@end diff --git a/permission_handler_apple/ios/Classes/PermissionHandlerEnums.h b/permission_handler_apple/ios/Classes/PermissionHandlerEnums.h index c153dc500..10ec596f5 100644 --- a/permission_handler_apple/ios/Classes/PermissionHandlerEnums.h +++ b/permission_handler_apple/ios/Classes/PermissionHandlerEnums.h @@ -180,3 +180,9 @@ typedef NS_ENUM(int, ServiceStatus) { ServiceStatusEnabled, ServiceStatusNotApplicable, }; + +typedef NS_ENUM(int, LocationAccuracy) { + LocationAccuracyReduced = 0, + LocationAccuracyPrecise = 1, + LocationAccuracyUnknown = 2 +}; diff --git a/permission_handler_apple/ios/Classes/PermissionHandlerPlugin.m b/permission_handler_apple/ios/Classes/PermissionHandlerPlugin.m index 7701584b7..f2f93d00a 100644 --- a/permission_handler_apple/ios/Classes/PermissionHandlerPlugin.m +++ b/permission_handler_apple/ios/Classes/PermissionHandlerPlugin.m @@ -1,8 +1,9 @@ #import "PermissionHandlerPlugin.h" - +#import "LocationAccuracyHandler.h" @implementation PermissionHandlerPlugin { PermissionManager *_Nonnull _permissionManager; + LocationAccuracyHandler *_Nonnull _locationAccuracyHandler; _Nullable FlutterResult _methodResult; } @@ -12,6 +13,7 @@ - (instancetype)initWithPermissionManager:(PermissionManager *)permissionManager _permissionManager = permissionManager; } + _locationAccuracyHandler = [[LocationAccuracyHandler alloc] init]; return self; } @@ -58,11 +60,12 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result } else if ([@"openAppSettings" isEqualToString:call.method]) { [PermissionManager openAppSettings:result]; } else if ([@"getLocationAccuracy" isEqualToString:call.method]) { - // TODO: Implement getLocationAccuracy to return the actual location accuracy status - result(@0); - } else if ([@"requestPreciseLocation" isEqualToString:call.method]) { - // TODO: Implement requestPreciseLocation to request precise location access - result(@0); + LocationAccuracy locationAccuracy = [self->_locationAccuracyHandler getLocationAccuracy]; + + result([Codec encodeLocationAccuracy:locationAccuracy]); + } else if ([@"requestTemporaryFullAccuracy" isEqualToString:call.method]) { + NSString* purposeKey = (NSString *)call.arguments[@"purposeKey"]; + [self->_locationAccuracyHandler requestTemporaryFullAccuracyWithResult:result purposeKey:purposeKey]; } else { result(FlutterMethodNotImplemented); } diff --git a/permission_handler_apple/ios/Classes/strategies/LocationPermissionStrategy.m b/permission_handler_apple/ios/Classes/strategies/LocationPermissionStrategy.m index fb2e78dc8..adf5c4168 100644 --- a/permission_handler_apple/ios/Classes/strategies/LocationPermissionStrategy.m +++ b/permission_handler_apple/ios/Classes/strategies/LocationPermissionStrategy.m @@ -34,9 +34,7 @@ - (instancetype)initWithLocationManager { } - (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission { - PermissionStatus status = [LocationPermissionStrategy permissionStatus:permission]; - return status; - // return self.accuracyStatus; + return [LocationPermissionStrategy permissionStatus:permission]; } @@ -205,27 +203,6 @@ + (PermissionStatus)permissionStatus:(PermissionGroup)permission { return status; } -- (PermissionStatus) accuracyStatus { -#if TARGET_OS_OSX - return PermissionStatusGranted; -#else - if (@available(iOS 14, macOS 10.16, *)) { - switch (_locationManager.accuracyAuthorization) { - case CLAccuracyAuthorizationFullAccuracy: - return PermissionStatusGranted; - case CLAccuracyAuthorizationReducedAccuracy: - return PermissionStatusDenied; - default: - // Reduced location accuracy is the default on iOS 14+ and macOS 11+. - return PermissionStatusDenied; - } - } else { - // Approximate location is not available, return precise location. - return PermissionStatusGranted; - } -#endif -} - + (PermissionStatus)determinePermissionStatus:(PermissionGroup)permission authorizationStatus:(CLAuthorizationStatus)authorizationStatus { if (@available(iOS 8.0, *)) { diff --git a/permission_handler_apple/ios/Classes/util/Codec.h b/permission_handler_apple/ios/Classes/util/Codec.h index ad930a490..49dc5067c 100644 --- a/permission_handler_apple/ios/Classes/util/Codec.h +++ b/permission_handler_apple/ios/Classes/util/Codec.h @@ -14,4 +14,6 @@ + (NSNumber *_Nullable)encodePermissionStatus:(enum PermissionStatus)permissionStatus; + (NSNumber *_Nullable)encodeServiceStatus:(enum ServiceStatus)serviceStatus; + ++ (NSNumber *_Nullable)encodeLocationAccuracy:(enum LocationAccuracy)locationAccuracy; @end diff --git a/permission_handler_apple/ios/Classes/util/Codec.m b/permission_handler_apple/ios/Classes/util/Codec.m index a7447fe01..f469fc75d 100644 --- a/permission_handler_apple/ios/Classes/util/Codec.m +++ b/permission_handler_apple/ios/Classes/util/Codec.m @@ -26,4 +26,8 @@ + (NSNumber *_Nullable)encodeServiceStatus:(enum ServiceStatus)serviceStatus { return [[NSNumber alloc] initWithInt:serviceStatus]; } ++ (NSNumber *_Nullable)encodeLocationAccuracy:(enum LocationAccuracy)locationAccuracy { + return [[NSNumber alloc] initWithInt:locationAccuracy]; +} + @end diff --git a/permission_handler_platform_interface/lib/src/method_channel/method_channel_permission_handler.dart b/permission_handler_platform_interface/lib/src/method_channel/method_channel_permission_handler.dart index a29e25b7d..b7d46e184 100644 --- a/permission_handler_platform_interface/lib/src/method_channel/method_channel_permission_handler.dart +++ b/permission_handler_platform_interface/lib/src/method_channel/method_channel_permission_handler.dart @@ -113,13 +113,18 @@ class MethodChannelPermissionHandler extends PermissionHandlerPlatform { } @override - Future requestPreciseLocation() async { + Future requestTemporaryFullAccuracy( + String purposeKey) async { if (defaultTargetPlatform != TargetPlatform.iOS) { return LocationAccuracyStatus.unknown; } - final locationAccuracyStatus = - await _methodChannel.invokeMethod('requestPreciseLocation'); + final locationAccuracyStatus = await _methodChannel.invokeMethod( + 'requestTemporaryFullAccuracy', + { + 'purposeKey': purposeKey, + }, + ); return decodeLocationAccuracyStatus(locationAccuracyStatus); } diff --git a/permission_handler_platform_interface/lib/src/permission_handler_platform_interface.dart b/permission_handler_platform_interface/lib/src/permission_handler_platform_interface.dart index 4daab3307..8b7207da6 100644 --- a/permission_handler_platform_interface/lib/src/permission_handler_platform_interface.dart +++ b/permission_handler_platform_interface/lib/src/permission_handler_platform_interface.dart @@ -94,8 +94,9 @@ abstract class PermissionHandlerPlatform extends PlatformInterface { } /// Request precise location access - Future requestPreciseLocation() { + Future requestTemporaryFullAccuracy( + String purposeKey) { throw UnimplementedError( - 'requestPreciseLocation() has not been implemented.'); + 'requestTemporaryFullAccuracy() has not been implemented.'); } } diff --git a/permission_handler_platform_interface/test/src/method_channel/method_channel_permission_handler_test.dart b/permission_handler_platform_interface/test/src/method_channel/method_channel_permission_handler_test.dart index 8989fa821..ccf38fd53 100644 --- a/permission_handler_platform_interface/test/src/method_channel/method_channel_permission_handler_test.dart +++ b/permission_handler_platform_interface/test/src/method_channel/method_channel_permission_handler_test.dart @@ -211,11 +211,11 @@ void main() { MethodChannelPermissionHandler().getLocationAccuracy()); }); - group('requestPreciseLocation:', () { + group('requestTemporaryFullAccuracy:', () { _testLocationAccuracyMethod( - methodName: 'requestPreciseLocation', - methodUnderTest: () => - MethodChannelPermissionHandler().requestPreciseLocation()); + methodName: 'requestTemporaryFullAccuracy', + methodUnderTest: () => MethodChannelPermissionHandler() + .requestTemporaryFullAccuracy('test')); }); } diff --git a/permission_handler_platform_interface/test/src/permission_handler_platform_interface_test.dart b/permission_handler_platform_interface/test/src/permission_handler_platform_interface_test.dart index d67b6fa90..9d82ac08c 100644 --- a/permission_handler_platform_interface/test/src/permission_handler_platform_interface_test.dart +++ b/permission_handler_platform_interface/test/src/permission_handler_platform_interface_test.dart @@ -99,12 +99,12 @@ void main() { test( // ignore: lines_longer_than_80_chars - 'Default implementation of requestPreciseLocation should throw unimplemented error', + 'Default implementation of requestTemporaryFullAccuracy should throw unimplemented error', () { final permissionHandlerPlatform = ExtendsPermissionHandlerPlatform(); expect(() { - permissionHandlerPlatform.requestPreciseLocation(); + permissionHandlerPlatform.requestTemporaryFullAccuracy('any'); }, throwsUnimplementedError); }); }); From 7b6be44129f09ac01dcec4f8415c21ba3bf5a660 Mon Sep 17 00:00:00 2001 From: Pierre-Monier Date: Sun, 9 Feb 2025 16:49:53 +0100 Subject: [PATCH 11/16] chore: remove useless changes --- README.md | 2 +- .../ios/Flutter/AppFrameworkInfo.plist | 2 +- permission_handler/example/ios/Podfile | 2 +- .../strategies/LocationPermissionStrategy.m | 33 +------------------ .../lib/src/permissions.dart | 2 +- 5 files changed, 5 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index a1e015c61..f5637e6ac 100644 --- a/README.md +++ b/README.md @@ -8,4 +8,4 @@ The Flutter permission_handler plugin is build following the federated plugin ar [1]: https://pub.dev/packages/permission_handler [2]: ./permission_handler/README.md [3]: https://pub.dev/packages/permission_handler_platform_interface -[4]: ./permission_handler_platform_interface/README.md +[4]: ./permission_handler_platform_interface/README.md \ No newline at end of file diff --git a/permission_handler/example/ios/Flutter/AppFrameworkInfo.plist b/permission_handler/example/ios/Flutter/AppFrameworkInfo.plist index 7c5696400..9625e105d 100644 --- a/permission_handler/example/ios/Flutter/AppFrameworkInfo.plist +++ b/permission_handler/example/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 12.0 + 11.0 diff --git a/permission_handler/example/ios/Podfile b/permission_handler/example/ios/Podfile index a4fe59cbe..56838fa0b 100644 --- a/permission_handler/example/ios/Podfile +++ b/permission_handler/example/ios/Podfile @@ -69,7 +69,7 @@ post_install do |installer| ## dart: PermissionGroup.photos 'PERMISSION_PHOTOS=1', - ## dart: [PermissionGroup.location, PermissionGroup.locationAlways] + ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse] 'PERMISSION_LOCATION=1', ## dart: PermissionGroup.notification diff --git a/permission_handler_apple/ios/Classes/strategies/LocationPermissionStrategy.m b/permission_handler_apple/ios/Classes/strategies/LocationPermissionStrategy.m index adf5c4168..d98f29ebe 100644 --- a/permission_handler_apple/ios/Classes/strategies/LocationPermissionStrategy.m +++ b/permission_handler_apple/ios/Classes/strategies/LocationPermissionStrategy.m @@ -11,8 +11,6 @@ @interface LocationPermissionStrategy () - (void) receiveActivityNotification:(NSNotification *)notification; -- (void)requestLocationPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler; -- (void)requestTemporaryFullAccuracy:(NSString * _Nullable)purposeKey completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler; @end @implementation LocationPermissionStrategy { @@ -36,7 +34,6 @@ - (instancetype)initWithLocationManager { - (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission { return [LocationPermissionStrategy permissionStatus:permission]; } - - (void)checkServiceStatus:(PermissionGroup)permission completionHandler:(ServiceStatusHandler)completionHandler { dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @@ -49,11 +46,6 @@ - (void)checkServiceStatus:(PermissionGroup)permission completionHandler:(Servic } - (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler { - // [self requestTemporaryFullAccuracy:@"YourPurposeKey" completionHandler: completionHandler errorHandler:errorHandler]; - [self requestLocationPermission:permission completionHandler:completionHandler errorHandler:errorHandler]; -} - -- (void)requestLocationPermission:(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 @@ -115,29 +107,6 @@ - (void)requestLocationPermission:(PermissionGroup)permission completionHandler: } } -- (void)requestTemporaryFullAccuracy:(NSString * _Nullable)purposeKey completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler { - if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationTemporaryUsageDescriptionDictionary"] == nil) { - return errorHandler(@"MISSING_USAGE_DESCRIPTION",@"The temporary accuracy dictionary key is not set in the infop.list"); - } - - #if TARGET_OS_OSX - return completionHandler(PermissionStatusGranted) - #else - if (@available(iOS 14.0, macOS 10.16, *)) { - [_locationManager requestTemporaryFullAccuracyAuthorizationWithPurposeKey:purposeKey - completion:^(NSError *_Nullable error) { - if ([self->_locationManager accuracyAuthorization] == CLAccuracyAuthorizationFullAccuracy) { - return completionHandler(PermissionStatusGranted); - } else { - return completionHandler(PermissionStatusDenied); - } - }]; - } else { - return completionHandler(PermissionStatusGranted); - } - #endif -} - - (void) receiveActivityNotification:(NSNotification *) notification { CLAuthorizationStatus status; if(@available(iOS 14.0, *)){ @@ -260,4 +229,4 @@ + (PermissionStatus)determinePermissionStatus:(PermissionGroup)permission author @implementation LocationPermissionStrategy @end -#endif +#endif \ No newline at end of file diff --git a/permission_handler_platform_interface/lib/src/permissions.dart b/permission_handler_platform_interface/lib/src/permissions.dart index b54895f28..15edb6ac7 100644 --- a/permission_handler_platform_interface/lib/src/permissions.dart +++ b/permission_handler_platform_interface/lib/src/permissions.dart @@ -411,7 +411,7 @@ class Permission { 'calendarWriteOnly', 'calendarFullAccess', 'assistant', - 'backgroundRefresh' + 'backgroundRefresh', ]; @override From 44fdf13f2641e4e8115c770b56369638fb0f9b4c Mon Sep 17 00:00:00 2001 From: Pierre-Monier Date: Sun, 9 Feb 2025 17:01:14 +0100 Subject: [PATCH 12/16] chore: remove unused import --- .../src/method_channel/method_channel_permission_handler.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/permission_handler_platform_interface/lib/src/method_channel/method_channel_permission_handler.dart b/permission_handler_platform_interface/lib/src/method_channel/method_channel_permission_handler.dart index b7d46e184..eb505ec79 100644 --- a/permission_handler_platform_interface/lib/src/method_channel/method_channel_permission_handler.dart +++ b/permission_handler_platform_interface/lib/src/method_channel/method_channel_permission_handler.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; -import 'package:meta/meta.dart'; import '../../permission_handler_platform_interface.dart'; import 'utils/codec.dart'; From 21e9ce7ea9831e3602b535fea9284015a818e0ff Mon Sep 17 00:00:00 2001 From: Pierre-Monier Date: Sun, 9 Feb 2025 17:02:07 +0100 Subject: [PATCH 13/16] chore: remove unused import --- permission_handler_apple/example/pubspec.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/permission_handler_apple/example/pubspec.yaml b/permission_handler_apple/example/pubspec.yaml index a6b7feffc..1a9636230 100644 --- a/permission_handler_apple/example/pubspec.yaml +++ b/permission_handler_apple/example/pubspec.yaml @@ -23,10 +23,6 @@ dev_dependencies: url_launcher: ^6.0.12 -dependency_overrides: - permission_handler_platform_interface: - path: ../../permission_handler_platform_interface - flutter: uses-material-design: true From 4762b0df631d21a1044eac605958806b298449cf Mon Sep 17 00:00:00 2001 From: Pierre-Monier Date: Sun, 9 Feb 2025 17:17:13 +0100 Subject: [PATCH 14/16] chore: update packages version --- permission_handler/CHANGELOG.md | 4 ++++ permission_handler/pubspec.yaml | 6 +++--- permission_handler_apple/pubspec.yaml | 2 +- permission_handler_platform_interface/pubspec.yaml | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/permission_handler/CHANGELOG.md b/permission_handler/CHANGELOG.md index 65b8ef989..636c563b9 100644 --- a/permission_handler/CHANGELOG.md +++ b/permission_handler/CHANGELOG.md @@ -1,3 +1,7 @@ +## 11.4.1 + +* Add `getLocationAccuracy` and `requestTemporaryFullAccuracy` methods. Implementation is done only for iOS. + ## 11.3.1 * Documents the use of the `PERMISSION_LOCAITON_WHENINUSE` macro on iOS. diff --git a/permission_handler/pubspec.yaml b/permission_handler/pubspec.yaml index e74fa4bf9..e85b558b4 100644 --- a/permission_handler/pubspec.yaml +++ b/permission_handler/pubspec.yaml @@ -2,7 +2,7 @@ name: permission_handler description: Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) 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: 11.3.1 +version: 11.4.1 environment: @@ -26,10 +26,10 @@ dependencies: sdk: flutter meta: ^1.7.0 permission_handler_android: ^12.0.3 - permission_handler_apple: ^9.4.3 + permission_handler_apple: ^9.5.3 permission_handler_html: ^0.1.1 permission_handler_windows: ^0.2.1 - permission_handler_platform_interface: ^4.2.0 + permission_handler_platform_interface: ^4.3.0 dev_dependencies: flutter_lints: ^1.0.4 diff --git a/permission_handler_apple/pubspec.yaml b/permission_handler_apple/pubspec.yaml index ef6679c56..6024f3a38 100644 --- a/permission_handler_apple/pubspec.yaml +++ b/permission_handler_apple/pubspec.yaml @@ -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.5 +version: 9.5.5 environment: sdk: ">=2.15.0 <4.0.0" diff --git a/permission_handler_platform_interface/pubspec.yaml b/permission_handler_platform_interface/pubspec.yaml index ca3aea932..9f3e3b55c 100644 --- a/permission_handler_platform_interface/pubspec.yaml +++ b/permission_handler_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the permission_handler plugin. homepage: https://github.com/baseflow/flutter-permission-handler/tree/master/permission_handler_platform_interface # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 4.2.3 +version: 4.3.3 dependencies: flutter: From cf28683229e87e2ae9cea17ec7f04dc925d77256 Mon Sep 17 00:00:00 2001 From: Pierre-Monier Date: Mon, 10 Feb 2025 18:16:41 +0100 Subject: [PATCH 15/16] docs: better comment on requestTemporaryFullAccuracy --- .../src/permission_handler_platform_interface.dart | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/permission_handler_platform_interface/lib/src/permission_handler_platform_interface.dart b/permission_handler_platform_interface/lib/src/permission_handler_platform_interface.dart index 8b7207da6..e99b75983 100644 --- a/permission_handler_platform_interface/lib/src/permission_handler_platform_interface.dart +++ b/permission_handler_platform_interface/lib/src/permission_handler_platform_interface.dart @@ -93,7 +93,18 @@ abstract class PermissionHandlerPlatform extends PlatformInterface { throw UnimplementedError('getLocationAccuracy() has not been implemented.'); } - /// Request precise location access + /// Requests temporary precise location when the user only gave permission + /// for approximate location (iOS 14+ only) + /// + /// When using this method, the value of the required property `purposeKey` + /// should match the value given in the + /// `NSLocationTemporaryUsageDescription` dictionary in the + /// Info.plist. + /// + /// Throws a [PermissionDefinitionsNotFoundException] when the necessary key + /// in the Info.plist is not added + /// Returns [LocationAccuracyStatus.precise] when using iOS 13 or below or + /// using other platforms. Future requestTemporaryFullAccuracy( String purposeKey) { throw UnimplementedError( From 040008160efb0e8ae326ba2eae47acbbdaac1e3b Mon Sep 17 00:00:00 2001 From: Pierre-Monier Date: Mon, 10 Feb 2025 18:34:46 +0100 Subject: [PATCH 16/16] docs: update changelogs --- permission_handler_apple/CHANGELOG.md | 4 ++++ permission_handler_platform_interface/CHANGELOG.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/permission_handler_apple/CHANGELOG.md b/permission_handler_apple/CHANGELOG.md index 05dd219d7..f6d4e269e 100644 --- a/permission_handler_apple/CHANGELOG.md +++ b/permission_handler_apple/CHANGELOG.md @@ -1,3 +1,7 @@ +## 9.5.5 + +* Implement `getLocationAccuracy` and `requestTemporaryFullAccuracy` methods. + ## 9.4.5 * Fixes issue #1002, Xcode warning of the unresponsive of main thread when checking isLocationEnabled. diff --git a/permission_handler_platform_interface/CHANGELOG.md b/permission_handler_platform_interface/CHANGELOG.md index 6e3b35cc9..343b38bb8 100644 --- a/permission_handler_platform_interface/CHANGELOG.md +++ b/permission_handler_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.3.3 + +* Add `getLocationAccuracy` and `requestTemporaryFullAccuracy` methods and `LocationAccuracyStatus` enum. + ## 4.2.3 * Fixes class name references in the API documentation.