Commit 7bde4009 by Maurits van Beusekom Committed by GitHub

Merge pull request #8 from BaseflowIT/feature/ios_request_permission

Implemented request permissions on iOS
parents 2fbc01a2 b86ec867
...@@ -444,7 +444,7 @@ ...@@ -444,7 +444,7 @@
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0; SWIFT_VERSION = 4.0;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
}; };
...@@ -471,7 +471,7 @@ ...@@ -471,7 +471,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.baseflow.permissionHandlerExample; PRODUCT_BUNDLE_IDENTIFIER = com.baseflow.permissionHandlerExample;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0; SWIFT_VERSION = 4.0;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
}; };
......
...@@ -46,7 +46,13 @@ ...@@ -46,7 +46,13 @@
<key>UIViewControllerBasedStatusBarAppearance</key> <key>UIViewControllerBasedStatusBarAppearance</key>
<false/> <false/>
<key>NSLocationWhenInUseUsageDescription</key> <key>NSLocationWhenInUseUsageDescription</key>
<string>Can I haz location?</string> <string>Need location when in use</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Always and when in use!</string>
<key>NSLocationUsageDescription</key>
<string>Older devices need location.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Can I haz location always?</string>
<key>NSAppleMusicUsageDescription</key> <key>NSAppleMusicUsageDescription</key>
<string>Music!</string> <string>Music!</string>
<key>NSBluetoothPeripheralUsageDescription</key> <key>NSBluetoothPeripheralUsageDescription</key>
......
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:permission_handler/permission_enums.dart'; import 'package:permission_handler/permission_enums.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
void main() => runApp(new MyApp()); void main() => runApp(new MyApp());
class MyApp extends StatefulWidget { class MyApp extends StatelessWidget {
@override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _permissionStatus = 'Unknown';
@override @override
void initState() { Widget build(BuildContext context) {
super.initState(); return new MaterialApp(
initPlatformState(); home: new Scaffold(
appBar: new AppBar(
title: const Text('Plugin example app'),
),
body: new Center(
child: new ListView(
children: PermissionGroup.values
.where((PermissionGroup permission) => permission != PermissionGroup.unknown)
.map((PermissionGroup permission) => new PermissionWidget(permission)).toList()
),
),
));
} }
}
// Platform messages are asynchronous, so we initialize in an async method. class PermissionWidget extends StatefulWidget {
Future<void> initPlatformState() async { final PermissionGroup _permissionGroup;
PermissionStatus permissionStatus;
// Platform messages may fail, so we use a try/catch PlatformException. const PermissionWidget(this._permissionGroup);
try {
permissionStatus = await PermissionHandler
.checkPermissionStatus(PermissionGroup.calendar);
/* @override
if (permissionStatus != PermissionStatus.granted) { _PermissionState createState() => _PermissionState(_permissionGroup);
final bool shouldShowRationale = await PermissionHandler }
.shouldShowRequestPermissionRationale(PermissionGroup.calendar);
if (shouldShowRationale) { class _PermissionState extends State<PermissionWidget> {
final Map<PermissionGroup, PermissionStatus> permissions = final PermissionGroup _permissionGroup;
await PermissionHandler.requestPermissions( PermissionStatus _permissionStatus = PermissionStatus.unknown;
<PermissionGroup>[PermissionGroup.calendar]);
if (permissions.containsKey(PermissionGroup.calendar)) { _PermissionState(this._permissionGroup);
permissionStatus = permissions[PermissionGroup.calendar];
} @override
} void initState() {
} super.initState();
*/
} on PlatformException {
permissionStatus = PermissionStatus.unknown;
}
// If the widget was removed from the tree while the asynchronous platform _listenForPermissionStatus();
// message was in flight, we want to discard the reply rather than calling }
// setState to update our non-existent appearance.
if (!mounted) {
return;
}
setState(() { void _listenForPermissionStatus() async {
_permissionStatus = permissionStatus.toString(); print(_permissionGroup.toString());
}); _permissionStatus = await PermissionHandler.checkPermissionStatus(_permissionGroup);
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new MaterialApp( return new ListTile(
home: new Scaffold( title: new Text(_permissionGroup.toString()),
appBar: new AppBar( subtitle: new Text(_permissionStatus.toString()),
title: const Text('Plugin example app'),
),
body: new Center(
child: new Column(
children: <Widget>[
new Text('Running on: $_permissionStatus\n'),
new RaisedButton(
child: const Text('Open settings'),
onPressed: () async =>
await PermissionHandler.openAppSettings(),
),
],
),
),
),
); );
} }
} }
\ No newline at end of file
...@@ -13,11 +13,40 @@ class PermissionManager: NSObject { ...@@ -13,11 +13,40 @@ class PermissionManager: NSObject {
static func checkPermissionStatus(permission: PermissionGroup, result: @escaping FlutterResult) { static func checkPermissionStatus(permission: PermissionGroup, result: @escaping FlutterResult) {
let permissionStrategy = PermissionManager.createPermissionStrategy(permission: permission) let permissionStrategy = PermissionManager.createPermissionStrategy(permission: permission)
let permissionStatus = permissionStrategy.checkPermissionStatus(permission: permission) let permissionStatus = permissionStrategy?.checkPermissionStatus(permission: permission) ?? PermissionStatus.unknown
result(Codec.encodePermissionStatus(permissionStatus: permissionStatus)) result(Codec.encodePermissionStatus(permissionStatus: permissionStatus))
} }
static func requestPermission(permissions: [PermissionGroup], result: @escaping FlutterResult) {
var requestQueue = Set(permissions.map { $0 })
var permissionStatusResult: [PermissionGroup: PermissionStatus] = [:]
for permission in permissions {
let permissionStrategy = PermissionManager.createPermissionStrategy(permission: permission)
if permissionStrategy == nil {
permissionStatusResult[permission] = PermissionStatus.unknown
requestQueue.remove(permission)
if requestQueue.count == 0 {
result(Codec.encodePermissionRequestResult(permissionStatusResult: permissionStatusResult))
return
}
} else {
permissionStrategy!.requestPermission(permission: permission) { (permissionStatus: PermissionStatus) in
permissionStatusResult[permission] = permissionStatus
requestQueue.remove(permission)
if requestQueue.count == 0 {
result(Codec.encodePermissionRequestResult(permissionStatusResult: permissionStatusResult))
return
}
}
}
}
}
static func openAppSettings(result: @escaping FlutterResult) { static func openAppSettings(result: @escaping FlutterResult) {
if #available(iOS 8.0, *) { if #available(iOS 8.0, *) {
if #available(iOS 10, *) { if #available(iOS 10, *) {
...@@ -34,7 +63,7 @@ class PermissionManager: NSObject { ...@@ -34,7 +63,7 @@ class PermissionManager: NSObject {
result(false) result(false)
} }
private static func createPermissionStrategy(permission: PermissionGroup) -> PermissionStrategy { private static func createPermissionStrategy(permission: PermissionGroup) -> PermissionStrategy? {
switch permission { switch permission {
case PermissionGroup.calendar: case PermissionGroup.calendar:
return EventPermissionStrategy() return EventPermissionStrategy()
...@@ -58,6 +87,8 @@ class PermissionManager: NSObject { ...@@ -58,6 +87,8 @@ class PermissionManager: NSObject {
return SensorPermissionStrategy() return SensorPermissionStrategy()
case PermissionGroup.speech: case PermissionGroup.speech:
return SpeechPermissionStrategy() return SpeechPermissionStrategy()
default:
return nil
} }
} }
} }
...@@ -19,8 +19,16 @@ public class SwiftPermissionHandlerPlugin: NSObject, FlutterPlugin { ...@@ -19,8 +19,16 @@ public class SwiftPermissionHandlerPlugin: NSObject, FlutterPlugin {
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
if call.method == "checkPermissionStatus" { if call.method == "checkPermissionStatus" {
PermissionManager.checkPermissionStatus( PermissionManager.checkPermissionStatus(
permission: Codec.decodePermissionGroup(from: call.arguments), permission: Codec.decodePermissionGroup(
result: result) from: call.arguments),
result: result)
} else if call.method == "requestPermissions" {
PermissionManager.requestPermission(
permissions: Codec.decodePermissionGroups(
from: call.arguments),
result: result)
} else if call.method == "shouldShowRequestPermissionRationale" {
result(false)
} else if call.method == "openAppSettings" { } else if call.method == "openAppSettings" {
PermissionManager.openAppSettings(result: result) PermissionManager.openAppSettings(result: result)
} else { } else {
......
...@@ -16,8 +16,11 @@ enum PermissionGroup : String, Codable { ...@@ -16,8 +16,11 @@ enum PermissionGroup : String, Codable {
case locationWhenInUse = "locationWhenInUse" case locationWhenInUse = "locationWhenInUse"
case mediaLibrary = "mediaLibrary" case mediaLibrary = "mediaLibrary"
case microphone = "microphone" case microphone = "microphone"
case phone = "phone"
case photos = "photos" case photos = "photos"
case reminders = "reminders" case reminders = "reminders"
case sensors = "sensors" case sensors = "sensors"
case sms = "sms"
case speech = "speech" case speech = "speech"
case storage = "storage"
} }
...@@ -19,11 +19,6 @@ class AudioVideoPermissionStrategy : NSObject, PermissionStrategy { ...@@ -19,11 +19,6 @@ class AudioVideoPermissionStrategy : NSObject, PermissionStrategy {
return PermissionStatus.unknown return PermissionStatus.unknown
} }
func requestPermission(permission: PermissionGroup) -> PermissionStatus {
// TODO: Add implementation
return PermissionStatus.unknown
}
private static func getPermissionStatus(mediaType: AVMediaType) -> PermissionStatus { private static func getPermissionStatus(mediaType: AVMediaType) -> PermissionStatus {
let status: AVAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: mediaType) let status: AVAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: mediaType)
...@@ -38,4 +33,33 @@ class AudioVideoPermissionStrategy : NSObject, PermissionStrategy { ...@@ -38,4 +33,33 @@ class AudioVideoPermissionStrategy : NSObject, PermissionStrategy {
return PermissionStatus.unknown return PermissionStatus.unknown
} }
} }
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
let permissionStatus = checkPermissionStatus(permission: permission)
if permissionStatus != PermissionStatus.unknown {
completionHandler(permissionStatus)
return
}
var mediaType: AVMediaType
if permission == PermissionGroup.camera {
mediaType = AVMediaType.video
} else if permission == PermissionGroup.microphone {
mediaType = AVMediaType.audio
} else {
completionHandler(PermissionStatus.unknown)
return
}
AVCaptureDevice.requestAccess(for: mediaType, completionHandler: {
(granted: Bool) in
if granted {
completionHandler(PermissionStatus.granted)
} else {
completionHandler(PermissionStatus.denied)
}
})
}
} }
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
// //
import AddressBook import AddressBook
import Contacts
import Foundation import Foundation
class ContactPermissionStrategy : NSObject, PermissionStrategy { class ContactPermissionStrategy : NSObject, PermissionStrategy {
...@@ -14,12 +15,22 @@ class ContactPermissionStrategy : NSObject, PermissionStrategy { ...@@ -14,12 +15,22 @@ class ContactPermissionStrategy : NSObject, PermissionStrategy {
return ContactPermissionStrategy.getPermissionStatus() return ContactPermissionStrategy.getPermissionStatus()
} }
func requestPermission(permission: PermissionGroup) -> PermissionStatus {
// TODO: Add implementation
return PermissionStatus.unknown
}
private static func getPermissionStatus() -> PermissionStatus { private static func getPermissionStatus() -> PermissionStatus {
if #available(iOS 9.0, *) {
let status: CNAuthorizationStatus = CNContactStore.authorizationStatus(for: .contacts)
switch status {
case CNAuthorizationStatus.authorized:
return PermissionStatus.granted
case CNAuthorizationStatus.denied:
return PermissionStatus.denied
case CNAuthorizationStatus.restricted:
return PermissionStatus.restricted
default:
return PermissionStatus.unknown
}
}
let status: ABAuthorizationStatus = ABAddressBookGetAuthorizationStatus() let status: ABAuthorizationStatus = ABAddressBookGetAuthorizationStatus()
switch status { switch status {
...@@ -33,4 +44,44 @@ class ContactPermissionStrategy : NSObject, PermissionStrategy { ...@@ -33,4 +44,44 @@ class ContactPermissionStrategy : NSObject, PermissionStrategy {
return PermissionStatus.unknown return PermissionStatus.unknown
} }
} }
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
let permissionStatus = checkPermissionStatus(permission: permission)
if permissionStatus != PermissionStatus.unknown {
completionHandler(permissionStatus)
return
}
if #available(iOS 9.0, *) {
ContactPermissionStrategy.requestPermissionsFromContactStore(completionHandler: completionHandler)
} else {
ContactPermissionStrategy.requestPermissionsFromAddressBook(completionHandler: completionHandler)
}
}
@available(iOS 9.0, *)
private static func requestPermissionsFromContactStore(completionHandler: @escaping PermissionStatusHandler) {
let contactStore = CNContactStore.init()
contactStore.requestAccess(for: .contacts, completionHandler: {
(authorized: Bool, error: Error?) in
if authorized {
completionHandler(PermissionStatus.granted)
} else {
completionHandler(PermissionStatus.denied)
}
})
}
private static func requestPermissionsFromAddressBook(completionHandler: @escaping PermissionStatusHandler) {
ABAddressBookRequestAccessWithCompletion(ABAddressBookCreate() as ABAddressBook, {
(granted: Bool, error: CFError?) in
if granted {
completionHandler(PermissionStatus.granted)
} else {
completionHandler(PermissionStatus.denied)
}
})
}
} }
...@@ -20,11 +20,6 @@ class EventPermissionStrategy : NSObject, PermissionStrategy { ...@@ -20,11 +20,6 @@ class EventPermissionStrategy : NSObject, PermissionStrategy {
return PermissionStatus.unknown return PermissionStatus.unknown
} }
func requestPermission(permission: PermissionGroup) -> PermissionStatus {
// TODO: Add implementation
return PermissionStatus.unknown
}
private static func getPermissionStatus(entityType: EKEntityType) -> PermissionStatus { private static func getPermissionStatus(entityType: EKEntityType) -> PermissionStatus {
let status: EKAuthorizationStatus = EKEventStore.authorizationStatus(for: entityType) let status: EKAuthorizationStatus = EKEventStore.authorizationStatus(for: entityType)
...@@ -40,4 +35,33 @@ class EventPermissionStrategy : NSObject, PermissionStrategy { ...@@ -40,4 +35,33 @@ class EventPermissionStrategy : NSObject, PermissionStrategy {
} }
} }
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
let permissionStatus = checkPermissionStatus(permission: permission)
if permissionStatus != PermissionStatus.unknown {
completionHandler(permissionStatus)
return
}
var entityType: EKEntityType
if permission == PermissionGroup.calendar {
entityType = EKEntityType.event
} else if permission == PermissionGroup.reminders {
entityType = EKEntityType.reminder
} else {
completionHandler(PermissionStatus.unknown)
return
}
let eventStore: EKEventStore = EKEventStore.init()
eventStore.requestAccess(to: entityType) { (granted: Bool, error: Error?) in
if granted {
completionHandler(PermissionStatus.granted)
} else {
completionHandler(PermissionStatus.denied)
}
}
}
} }
...@@ -8,17 +8,14 @@ ...@@ -8,17 +8,14 @@
import CoreLocation import CoreLocation
import Foundation import Foundation
class LocationPermissionStrategy : NSObject, PermissionStrategy { class LocationPermissionStrategy : NSObject, PermissionStrategy, CLLocationManagerDelegate {
private var _permissionStatusHandler: PermissionStatusHandler? = nil
private var _requestedPermission: PermissionGroup? = nil
func checkPermissionStatus(permission: PermissionGroup) -> PermissionStatus { func checkPermissionStatus(permission: PermissionGroup) -> PermissionStatus {
return LocationPermissionStrategy.getPermissionStatus(permission: permission) return LocationPermissionStrategy.getPermissionStatus(permission: permission)
} }
func requestPermission(permission: PermissionGroup) -> PermissionStatus {
// TODO: Add implementation
return PermissionStatus.unknown
}
private static func getPermissionStatus(permission: PermissionGroup) -> PermissionStatus { private static func getPermissionStatus(permission: PermissionGroup) -> PermissionStatus {
if !CLLocationManager.locationServicesEnabled() { if !CLLocationManager.locationServicesEnabled() {
return PermissionStatus.disabled return PermissionStatus.disabled
...@@ -26,9 +23,62 @@ class LocationPermissionStrategy : NSObject, PermissionStrategy { ...@@ -26,9 +23,62 @@ class LocationPermissionStrategy : NSObject, PermissionStrategy {
let status: CLAuthorizationStatus = CLLocationManager.authorizationStatus() let status: CLAuthorizationStatus = CLLocationManager.authorizationStatus()
return LocationPermissionStrategy.determinePermissionStatus(
permission: permission,
authorizationStatus: status)
}
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
let permissionStatus = checkPermissionStatus(permission: permission)
if CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse && permission == PermissionGroup.locationAlways {
// don't do anything and continue requesting permissions
} else if permissionStatus != PermissionStatus.unknown {
completionHandler(permissionStatus)
return
}
_permissionStatusHandler = completionHandler
_requestedPermission = permission
let locationManager = CLLocationManager.init()
locationManager.delegate = self
if(permission != PermissionGroup.location) {
if (Bundle.main.object(forInfoDictionaryKey: "NSLocationWhenInUseUsageDescription") != nil) {
locationManager.requestWhenInUseAuthorization()
} else if (Bundle.main.object(forInfoDictionaryKey: "NSLocationAlwaysUsageDescription") != nil) {
locationManager.requestAlwaysAuthorization();
} else {
NSException(name: NSExceptionName.internalInconsistencyException, 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()
}
} else if permission == PermissionGroup.locationAlways {
if (Bundle.main.object(forInfoDictionaryKey: "NSLocationAlwaysUsageDescription") != nil) {
locationManager.requestAlwaysAuthorization();
} else {
NSException(name: NSExceptionName.internalInconsistencyException, reason:"To use location in iOS8 you need to define NSLocationAlwaysUsageDescription in the app bundle's Info.plist file", userInfo: nil).raise()
}
} else if permission == PermissionGroup.locationWhenInUse {
if (Bundle.main.object(forInfoDictionaryKey: "NSLocationWhenInUseUsageDescription") != nil) {
locationManager.requestWhenInUseAuthorization();
} else {
NSException(name: NSExceptionName.internalInconsistencyException, reason:"To use location in iOS8 you need to define NSLocationWhenInUseUsageDescription in the app bundle's Info.plist file", userInfo: nil).raise()
}
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
guard let completionHandler = _permissionStatusHandler else { return }
completionHandler(
LocationPermissionStrategy.determinePermissionStatus(
permission: _requestedPermission!,
authorizationStatus: status))
}
private static func determinePermissionStatus(permission: PermissionGroup, authorizationStatus: CLAuthorizationStatus) -> PermissionStatus {
if #available(iOS 8.0, *) { if #available(iOS 8.0, *) {
if permission == PermissionGroup.locationAlways { if permission == PermissionGroup.locationAlways {
switch status { switch authorizationStatus {
case CLAuthorizationStatus.authorizedAlways: case CLAuthorizationStatus.authorizedAlways:
return PermissionStatus.granted return PermissionStatus.granted
case CLAuthorizationStatus.authorizedWhenInUse, case CLAuthorizationStatus.authorizedWhenInUse,
...@@ -41,7 +91,7 @@ class LocationPermissionStrategy : NSObject, PermissionStrategy { ...@@ -41,7 +91,7 @@ class LocationPermissionStrategy : NSObject, PermissionStrategy {
} }
} }
switch status { switch authorizationStatus {
case CLAuthorizationStatus.authorizedAlways, case CLAuthorizationStatus.authorizedAlways,
CLAuthorizationStatus.authorizedWhenInUse: CLAuthorizationStatus.authorizedWhenInUse:
return PermissionStatus.granted return PermissionStatus.granted
...@@ -54,7 +104,7 @@ class LocationPermissionStrategy : NSObject, PermissionStrategy { ...@@ -54,7 +104,7 @@ class LocationPermissionStrategy : NSObject, PermissionStrategy {
} }
} }
switch status { switch authorizationStatus {
case CLAuthorizationStatus.authorized: case CLAuthorizationStatus.authorized:
return PermissionStatus.granted return PermissionStatus.granted
case CLAuthorizationStatus.denied: case CLAuthorizationStatus.denied:
......
...@@ -14,27 +14,45 @@ class MediaLibraryPermissionStrategy : NSObject, PermissionStrategy { ...@@ -14,27 +14,45 @@ class MediaLibraryPermissionStrategy : NSObject, PermissionStrategy {
return MediaLibraryPermissionStrategy.getPermissionStatus() return MediaLibraryPermissionStrategy.getPermissionStatus()
} }
func requestPermission(permission: PermissionGroup) -> PermissionStatus {
// TODO: Add implementation
return PermissionStatus.unknown
}
private static func getPermissionStatus() -> PermissionStatus { private static func getPermissionStatus() -> PermissionStatus {
if #available(iOS 9.3, *) { if #available(iOS 9.3, *) {
let status: MPMediaLibraryAuthorizationStatus = MPMediaLibrary.authorizationStatus() let status: MPMediaLibraryAuthorizationStatus = MPMediaLibrary.authorizationStatus()
switch status { return MediaLibraryPermissionStrategy.determinePermissionStatus(authorizationStatus: status)
case MPMediaLibraryAuthorizationStatus.authorized:
return PermissionStatus.granted
case MPMediaLibraryAuthorizationStatus.denied:
return PermissionStatus.denied
case MPMediaLibraryAuthorizationStatus.restricted:
return PermissionStatus.restricted
default:
return PermissionStatus.unknown
}
} }
return PermissionStatus.unknown return PermissionStatus.unknown
} }
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) -> Void {
let status = checkPermissionStatus(permission: permission)
if status != PermissionStatus.unknown {
completionHandler(status)
return
}
if #available(iOS 9.3, *) {
MPMediaLibrary.requestAuthorization { (status: MPMediaLibraryAuthorizationStatus) in
completionHandler(
MediaLibraryPermissionStrategy.determinePermissionStatus(authorizationStatus: status))
}
} else {
completionHandler(PermissionStatus.unknown)
return
}
}
@available(iOS 9.3, *)
private static func determinePermissionStatus(authorizationStatus: MPMediaLibraryAuthorizationStatus) -> PermissionStatus {
switch authorizationStatus {
case MPMediaLibraryAuthorizationStatus.authorized:
return PermissionStatus.granted
case MPMediaLibraryAuthorizationStatus.denied:
return PermissionStatus.denied
case MPMediaLibraryAuthorizationStatus.restricted:
return PermissionStatus.restricted
default:
return PermissionStatus.unknown
}
}
} }
...@@ -7,7 +7,9 @@ ...@@ -7,7 +7,9 @@
import Foundation import Foundation
typealias PermissionStatusHandler = (_ permissionStatus: PermissionStatus) -> Void
protocol PermissionStrategy { protocol PermissionStrategy {
func checkPermissionStatus(permission: PermissionGroup) -> PermissionStatus func checkPermissionStatus(permission: PermissionGroup) -> PermissionStatus
func requestPermission(permission: PermissionGroup) -> PermissionStatus func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler)
} }
...@@ -14,15 +14,28 @@ class PhotoPermissionStrategy : NSObject, PermissionStrategy { ...@@ -14,15 +14,28 @@ class PhotoPermissionStrategy : NSObject, PermissionStrategy {
return PhotoPermissionStrategy.getPermissionStatus() return PhotoPermissionStrategy.getPermissionStatus()
} }
func requestPermission(permission: PermissionGroup) -> PermissionStatus {
// TODO: Add implementation
return PermissionStatus.unknown
}
private static func getPermissionStatus() -> PermissionStatus { private static func getPermissionStatus() -> PermissionStatus {
let status: PHAuthorizationStatus = PHPhotoLibrary.authorizationStatus() let status: PHAuthorizationStatus = PHPhotoLibrary.authorizationStatus()
switch status { return PhotoPermissionStrategy.determinePermissionStatus(authorizationStatus: status)
}
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
let status = checkPermissionStatus(permission: permission)
if status != PermissionStatus.unknown {
completionHandler(status)
return
}
PHPhotoLibrary.requestAuthorization { (authorizationStatus: PHAuthorizationStatus) in
completionHandler(
PhotoPermissionStrategy.determinePermissionStatus(authorizationStatus: authorizationStatus))
}
}
private static func determinePermissionStatus(authorizationStatus: PHAuthorizationStatus) -> PermissionStatus {
switch authorizationStatus {
case PHAuthorizationStatus.authorized: case PHAuthorizationStatus.authorized:
return PermissionStatus.granted return PermissionStatus.granted
case PHAuthorizationStatus.denied: case PHAuthorizationStatus.denied:
......
...@@ -14,11 +14,6 @@ class SensorPermissionStrategy : NSObject, PermissionStrategy { ...@@ -14,11 +14,6 @@ class SensorPermissionStrategy : NSObject, PermissionStrategy {
return SensorPermissionStrategy.getPermissionStatus() return SensorPermissionStrategy.getPermissionStatus()
} }
func requestPermission(permission: PermissionGroup) -> PermissionStatus {
// TODO: Add implementation
return PermissionStatus.unknown
}
private static func getPermissionStatus() -> PermissionStatus { private static func getPermissionStatus() -> PermissionStatus {
if !CMMotionActivityManager.isActivityAvailable() { if !CMMotionActivityManager.isActivityAvailable() {
return PermissionStatus.disabled return PermissionStatus.disabled
...@@ -41,4 +36,26 @@ class SensorPermissionStrategy : NSObject, PermissionStrategy { ...@@ -41,4 +36,26 @@ class SensorPermissionStrategy : NSObject, PermissionStrategy {
return PermissionStatus.unknown return PermissionStatus.unknown
} }
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
let status = checkPermissionStatus(permission: permission)
if status != PermissionStatus.unknown {
completionHandler(status)
return
}
if #available(iOS 11.0, *) {
let motionManager = CMMotionActivityManager.init()
motionManager.queryActivityStarting(from: NSDate.distantPast, to: NSDate.distantFuture, to: OperationQueue.main) {
(results: [CMMotionActivity]?, error: Error?) in
if results != nil {
completionHandler(PermissionStatus.granted)
} else {
completionHandler(PermissionStatus.denied)
}
}
}
}
} }
...@@ -14,27 +14,46 @@ class SpeechPermissionStrategy : NSObject, PermissionStrategy { ...@@ -14,27 +14,46 @@ class SpeechPermissionStrategy : NSObject, PermissionStrategy {
return SpeechPermissionStrategy.getPermissionStatus() return SpeechPermissionStrategy.getPermissionStatus()
} }
func requestPermission(permission: PermissionGroup) -> PermissionStatus {
// TODO: Add implementation
return PermissionStatus.unknown
}
private static func getPermissionStatus() -> PermissionStatus { private static func getPermissionStatus() -> PermissionStatus {
if #available(iOS 10.0, *) { if #available(iOS 10.0, *) {
let status: SFSpeechRecognizerAuthorizationStatus = SFSpeechRecognizer.authorizationStatus() let status: SFSpeechRecognizerAuthorizationStatus = SFSpeechRecognizer.authorizationStatus()
switch status { return SpeechPermissionStrategy.determinePermissionStatus(authorizationStatus: status)
case SFSpeechRecognizerAuthorizationStatus.authorized:
return PermissionStatus.granted
case SFSpeechRecognizerAuthorizationStatus.denied:
return PermissionStatus.denied
case SFSpeechRecognizerAuthorizationStatus.restricted:
return PermissionStatus.restricted
default:
return PermissionStatus.unknown
}
} }
return PermissionStatus.unknown return PermissionStatus.unknown
} }
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
let status = checkPermissionStatus(permission: permission)
if status != PermissionStatus.unknown {
completionHandler(status)
return
}
if #available(iOS 10.0, *) {
SFSpeechRecognizer.requestAuthorization { (authorizationStatus: SFSpeechRecognizerAuthorizationStatus) in
completionHandler(
SpeechPermissionStrategy.determinePermissionStatus(authorizationStatus: authorizationStatus))
return
}
}
completionHandler(PermissionStatus.unknown)
}
@available(iOS 10.0, *)
private static func determinePermissionStatus(authorizationStatus: SFSpeechRecognizerAuthorizationStatus) -> PermissionStatus {
switch authorizationStatus {
case SFSpeechRecognizerAuthorizationStatus.authorized:
return PermissionStatus.granted
case SFSpeechRecognizerAuthorizationStatus.denied:
return PermissionStatus.denied
case SFSpeechRecognizerAuthorizationStatus.restricted:
return PermissionStatus.restricted
default:
return PermissionStatus.unknown
}
}
} }
...@@ -19,8 +19,28 @@ struct Codec { ...@@ -19,8 +19,28 @@ struct Codec {
return PermissionGroup(rawValue: permissionString)! return PermissionGroup(rawValue: permissionString)!
} }
static func decodePermissionGroups(from arguments: Any?) -> [PermissionGroup] {
let data = (arguments as! String).data(using: .utf8)
let permissions = try! jsonDecoder.decode([PermissionGroup].self, from: data!)
return permissions
}
static func encodePermissionStatus(permissionStatus: PermissionStatus) -> String? { static func encodePermissionStatus(permissionStatus: PermissionStatus) -> String? {
let status = "\"" + permissionStatus.rawValue + "\"" let status = "\"" + permissionStatus.rawValue + "\""
return status return status
} }
static func encodePermissionRequestResult(permissionStatusResult: [PermissionGroup: PermissionStatus]) -> String? {
let jsonDict = Dictionary(uniqueKeysWithValues:
permissionStatusResult.map {
(key: PermissionGroup, value: PermissionStatus) in (key.rawValue, value.rawValue)
})
let jsonData = try! JSONSerialization.data(withJSONObject: jsonDict, options: [])
let jsonString = String(data: jsonData, encoding: .utf8)!
return jsonString
}
} }
...@@ -12,11 +12,11 @@ class Codec { ...@@ -12,11 +12,11 @@ class Codec {
static Map<PermissionGroup, PermissionStatus> decodePermissionRequestResult( static Map<PermissionGroup, PermissionStatus> decodePermissionRequestResult(
dynamic value) { dynamic value) {
final dynamic jsonObject = json.decode(value.toString()); final Map<String, dynamic> jsonObject = json.decode(value.toString());
final Map<PermissionGroup, PermissionStatus> permissionResults = final Map<PermissionGroup, PermissionStatus> permissionResults =
<PermissionGroup, PermissionStatus>{}; <PermissionGroup, PermissionStatus>{};
jsonObject.forEach((PermissionGroup key, PermissionStatus value) { jsonObject.forEach((String key, dynamic value) {
final PermissionGroup permissionGroup = PermissionGroup.values.firstWhere( final PermissionGroup permissionGroup = PermissionGroup.values.firstWhere(
(PermissionGroup e) => (PermissionGroup e) =>
e.toString().split('.').last == key.toString()); e.toString().split('.').last == key.toString());
......
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