├── PermissionsService ├── Assets │ └── .gitkeep └── Classes │ ├── .gitkeep │ ├── Extensions.swift │ ├── Core │ ├── Extensions.swift │ ├── ServiceDisplay.swift │ ├── PermissionConfiguration.swift │ ├── Structs.swift │ └── PermissionService.swift │ ├── ServiceDisplay.swift │ ├── Microphone.swift │ ├── Notifications.swift │ ├── Siri.swift │ ├── Gallery.swift │ ├── Reminder.swift │ ├── Events.swift │ ├── Camera │ └── Camera.swift │ ├── MediaLibrary.swift │ ├── SpeechRecognition.swift │ ├── LocationConfiguration.swift │ ├── Location │ ├── LocationConfiguration.swift │ └── Location.swift │ ├── Contacts.swift │ ├── PermissionConfiguration.swift │ ├── Bluetooth.swift │ ├── Structs.swift │ ├── PermissionService.swift │ └── Location.swift ├── _Pods.xcodeproj ├── PermissionsService.framework.zip ├── Example ├── Pods │ ├── Target Support Files │ │ ├── Pods-Example │ │ │ ├── Pods-Example.modulemap │ │ │ ├── Pods-Example-dummy.m │ │ │ ├── Pods-Example-umbrella.h │ │ │ ├── Pods-Example.debug.xcconfig │ │ │ ├── Pods-Example.release.xcconfig │ │ │ ├── Info.plist │ │ │ ├── Pods-Example-Info.plist │ │ │ ├── Pods-Example-acknowledgements.markdown │ │ │ ├── Pods-Example-acknowledgements.plist │ │ │ ├── Pods-Example-resources.sh │ │ │ └── Pods-Example-frameworks.sh │ │ └── PermissionsService │ │ │ ├── PermissionsService.modulemap │ │ │ ├── PermissionsService-dummy.m │ │ │ ├── PermissionsService-prefix.pch │ │ │ ├── PermissionsService-umbrella.h │ │ │ ├── PermissionsService.xcconfig │ │ │ ├── Info.plist │ │ │ └── PermissionsService-Info.plist │ ├── Pods.xcodeproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── PermissionsService.xcscheme │ ├── PermissionsServiceTests │ │ ├── Info.plist │ │ ├── PermissionResultTests.swift │ │ ├── PermissionServiceTests.swift │ │ ├── SiriTests.swift │ │ ├── GalleryTests.swift │ │ ├── ContactsTests.swift │ │ ├── MediaLibraryTests.swift │ │ ├── SpeechRecognitionTests.swift │ │ ├── CameraTests.swift │ │ ├── EventsTests.swift │ │ ├── MicrophoneTests.swift │ │ ├── ReminderTests.swift │ │ ├── LocationTests.swift │ │ ├── PermissionStatusTests.swift │ │ ├── ConfigurationTests.swift │ │ └── LocationConfigurationTests.swift │ ├── PermissionConfiguration.xcconfig │ ├── Manifest.lock │ └── Local Podspecs │ │ └── PermissionsService.podspec.json ├── PermissionsService.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── PermissionsService-Example.xcscheme │ └── project.pbxproj ├── Example │ ├── Example.entitlements │ ├── Enter Point │ │ ├── AppDelegate.h │ │ ├── main.m │ │ └── AppDelegate.m │ ├── Resourses │ │ ├── Assets.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ └── Info.plist │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ └── Sources │ │ └── Controller │ │ └── PermissionsController.swift ├── PermissionsService.xcworkspace │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── contents.xcworkspacedata ├── Podfile ├── README.md └── Podfile.lock ├── .travis.yml ├── Source ├── Core │ ├── Extensions.swift │ ├── Permissible.swift │ ├── PermissionConfiguration.swift │ ├── PermissionResult.swift │ └── PermissionService.swift ├── Microphone │ └── Microphone.swift ├── Gallery │ └── Gallery.swift ├── Camera │ └── Camera.swift ├── Reminder │ └── Reminder.swift ├── Events │ └── Events.swift ├── Siri │ └── Siri.swift ├── Notifications │ └── Notifications.swift ├── MediaLibrary │ └── MediaLibrary.swift ├── SpeechRecognition │ └── SpeechRecognition.swift ├── Location │ ├── LocationConfiguration.swift │ └── Location.swift ├── Contacts │ └── Contacts.swift └── Bluetooth │ └── Bluetooth.swift ├── .gitignore ├── LICENSE ├── PermissionsService.podspec └── README.md /PermissionsService/Assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PermissionsService/Classes/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_Pods.xcodeproj: -------------------------------------------------------------------------------- 1 | Example/Pods/Pods.xcodeproj -------------------------------------------------------------------------------- /PermissionsService.framework.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lemberg/ios-permissions-service/HEAD/PermissionsService.framework.zip -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Example/Pods-Example.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_Example { 2 | umbrella header "Pods-Example-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Example/Pods-Example-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_Example : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_Example 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/PermissionsService/PermissionsService.modulemap: -------------------------------------------------------------------------------- 1 | framework module PermissionsService { 2 | umbrella header "PermissionsService-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/PermissionsService/PermissionsService-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_PermissionsService : NSObject 3 | @end 4 | @implementation PodsDummy_PermissionsService 5 | @end 6 | -------------------------------------------------------------------------------- /Example/PermissionsService.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Example/Example.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.siri 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/PermissionsService/PermissionsService-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Example/PermissionsService.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/PermissionsService.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/Example/Enter Point/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // Example 4 | // 5 | // Created by Yuriy Trach on 10/11/16. 6 | // Copyright © 2016 CocoaPods. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Example/Example/Enter Point/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Example 4 | // 5 | // Created by Yuriy Trach on 10/11/16. 6 | // Copyright © 2016 CocoaPods. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Example/Pods-Example-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_ExampleVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_ExampleVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/PermissionsService/PermissionsService-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double PermissionsServiceVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char PermissionsServiceVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # references: 2 | # * http://www.objc.io/issue-6/travis-ci.html 3 | # * https://github.com/supermarin/xcpretty#usage 4 | 5 | osx_image: xcode7.3 6 | language: objective-c 7 | # cache: cocoapods 8 | # podfile: Example/Podfile 9 | # before_install: 10 | # - gem install cocoapods # Since Travis is not always on latest version 11 | # - pod install --project-directory=Example 12 | script: 13 | - set -o pipefail && xcodebuild test -workspace Example/PermissionsService.xcworkspace -scheme PermissionsService-Example -sdk iphonesimulator9.3 ONLY_ACTIVE_ARCH=NO | xcpretty 14 | - pod lib lint 15 | -------------------------------------------------------------------------------- /Source/Core/Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.swift 3 | // 4 | // Created by Hellen Soloviy on 7/24/17. 5 | // 6 | // 7 | 8 | import Foundation 9 | 10 | extension Int { 11 | 12 | func permissionStatus() -> PermissionStatus { 13 | 14 | switch self { 15 | case 0: return .notDetermined 16 | case 1: return .restricted 17 | case 2: return .denied 18 | case 3, 4: return .authorized 19 | default: return .unknown 20 | 21 | } 22 | 23 | } 24 | 25 | 26 | } 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /PermissionsService/Classes/Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.swift 3 | // 4 | // Created by Hellen Soloviy on 7/24/17. 5 | // 6 | // 7 | 8 | import Foundation 9 | 10 | extension Int { 11 | 12 | func permissionStatus() -> PermissionStatus { 13 | 14 | switch self { 15 | case 0: return .notDetermined 16 | case 1: return .restricted 17 | case 2: return .denied 18 | case 3: return .authorized 19 | default: return .unknown 20 | 21 | } 22 | 23 | } 24 | 25 | } 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /PermissionsService/Classes/Core/Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.swift 3 | // 4 | // Created by Hellen Soloviy on 7/24/17. 5 | // 6 | // 7 | 8 | import Foundation 9 | 10 | extension Int { 11 | 12 | func permissionStatus() -> PermissionStatus { 13 | 14 | switch self { 15 | case 0: return .notDetermined 16 | case 1: return .restricted 17 | case 2: return .denied 18 | case 3: return .authorized 19 | default: return .unknown 20 | 21 | } 22 | 23 | } 24 | 25 | } 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | platform :ios, '10.0' 3 | 4 | target 'Example' do 5 | 6 | pod 'PermissionsService/Location’, :path => '../' 7 | pod 'PermissionsService/Camera’, :path => '../' 8 | pod 'PermissionsService/Contacts’, :path => '../' 9 | pod 'PermissionsService/Events’, :path => '../' 10 | pod 'PermissionsService/MediaLibrary’, :path => '../' 11 | pod 'PermissionsService/Gallery’, :path => '../' 12 | pod 'PermissionsService/Microphone’, :path => '../' 13 | pod 'PermissionsService/Reminder’, :path => '../' 14 | pod 'PermissionsService/Siri’, :path => '../' 15 | pod 'PermissionsService/SpeechRecognition’, :path => '../' 16 | 17 | end 18 | -------------------------------------------------------------------------------- /PermissionsService/Classes/ServiceDisplay.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ServiceDisplay.swift 3 | // 4 | // Created by Hellen Soloviy on 7/24/17. 5 | // 6 | // 7 | 8 | import Foundation 9 | 10 | public protocol ServiceMessages { 11 | 12 | var restrictedMessage: String { get } 13 | var restrictedTitle: String { get } 14 | var deniedMessage: String { get } 15 | var deniedTitle: String { get } 16 | } 17 | 18 | public protocol ServiceDisplay { 19 | 20 | func showAlert(vc: UIAlertController) 21 | } 22 | 23 | public extension ServiceDisplay where Self: UIViewController { 24 | 25 | public func showAlert(vc: UIAlertController) { 26 | self.present(vc, animated: true, completion: nil) 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /PermissionsService/Classes/Core/ServiceDisplay.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ServiceDisplay.swift 3 | // 4 | // Created by Hellen Soloviy on 7/24/17. 5 | // 6 | // 7 | 8 | import Foundation 9 | 10 | public protocol ServiceMessages { 11 | 12 | var restrictedMessage: String { get } 13 | var restrictedTitle: String { get } 14 | var deniedMessage: String { get } 15 | var deniedTitle: String { get } 16 | } 17 | 18 | public protocol ServiceDisplay { 19 | 20 | func showAlert(vc: UIAlertController) 21 | } 22 | 23 | public extension ServiceDisplay where Self: UIViewController { 24 | 25 | public func showAlert(vc: UIAlertController) { 26 | self.present(vc, animated: true, completion: nil) 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata/ 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | 22 | # Bundler 23 | .bundle 24 | 25 | Carthage 26 | # We recommend against adding the Pods directory to your .gitignore. However 27 | # you should judge for yourself, the pros and cons are mentioned at: 28 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 29 | # 30 | # Note: if you ignore the Pods directory, make sure to uncomment 31 | # `pod install` in .travis.yml 32 | # 33 | # Pods/ 34 | -------------------------------------------------------------------------------- /Example/Pods/PermissionsServiceTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/PermissionsService/PermissionsService.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PermissionsService 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = PERMISSION_CAMERA PERMISSION_CONTACTS PERMISSION_EVENTS PERMISSION_GALLERY PERMISSION_LOCATION PERMISSION_MEDIA_LIBRARY PERMISSION_MICROPHONE PERMISSION_REMINDER PERMISSION_SIRI PERMISSION_SPEECH_RECOGNITION 11 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Example/Pods-Example.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PermissionsService" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PermissionsService/PermissionsService.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_LDFLAGS = $(inherited) -framework "PermissionsService" 7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Example/Pods-Example.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PermissionsService" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PermissionsService/PermissionsService.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_LDFLAGS = $(inherited) -framework "PermissionsService" 7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | -------------------------------------------------------------------------------- /Source/Microphone/Microphone.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Microphone.swift 3 | // 4 | // Created by Hellen Soloviy on 6/6/17. 5 | // 6 | 7 | #if PERMISSION_MICROPHONE 8 | import Foundation 9 | import Photos 10 | 11 | public final class Microphone: PermissionService { 12 | 13 | let type = AVMediaType.audio 14 | 15 | public required init(with configuration: PermissionConfiguration) { } 16 | 17 | public func status() -> PermissionStatus { 18 | let status = AVCaptureDevice.authorizationStatus(for: type) 19 | return status.rawValue.permissionStatus() 20 | } 21 | 22 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 23 | 24 | AVCaptureDevice.requestAccess(for: type) { (granted) -> Void in 25 | callback(granted) 26 | } 27 | } 28 | 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /Source/Gallery/Gallery.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Gallery.swift 3 | // 4 | // Created by Volodymyr Hyrka on 2/9/16. 5 | // Copyright © 2016 LembergSolutions. All rights reserved. 6 | // 7 | 8 | #if PERMISSION_GALLERY 9 | import Foundation 10 | import Photos 11 | 12 | public final class Gallery: PermissionService { 13 | 14 | public required init(with configuration: PermissionConfiguration) { } 15 | 16 | public func status() -> PermissionStatus { 17 | let status = PHPhotoLibrary.authorizationStatus() 18 | return status.rawValue.permissionStatus() 19 | } 20 | 21 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 22 | 23 | PHPhotoLibrary.requestAuthorization({ (newStatus) -> Void in 24 | let success = newStatus == PHAuthorizationStatus.authorized 25 | callback(success) 26 | }) 27 | } 28 | 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /Source/Camera/Camera.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Camera.swift 3 | // 4 | // Created by Volodymyr Hyrka on 2/9/16. 5 | // Copyright © 2016 LembergSolutions. All rights reserved. 6 | // 7 | 8 | #if PERMISSION_CAMERA 9 | import Foundation 10 | import Photos 11 | 12 | public final class Camera: PermissionService { 13 | 14 | public required init(with configuration: PermissionConfiguration) { } 15 | 16 | let type = AVMediaType.video 17 | 18 | public init() {} 19 | 20 | public func status() -> PermissionStatus { 21 | let status = AVCaptureDevice.authorizationStatus(for: type) 22 | return status.rawValue.permissionStatus() 23 | } 24 | 25 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 26 | 27 | AVCaptureDevice.requestAccess(for: type) { (granted) -> Void in 28 | callback(granted) 29 | } 30 | } 31 | 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /Source/Reminder/Reminder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Reminder.swift 3 | // 4 | // Created by Hellen Soloviy on 6/6/17. 5 | // Copyright © 2016 LembergSolutions. All rights reserved. 6 | // 7 | 8 | #if PERMISSION_REMINDER 9 | import UIKit 10 | import EventKit 11 | 12 | public final class Reminder: PermissionService { 13 | 14 | let type = EKEntityType.reminder 15 | 16 | public required init(with configuration: PermissionConfiguration) { } 17 | 18 | public func status() -> PermissionStatus { 19 | let status = EKEventStore.authorizationStatus(for: type) 20 | return status.rawValue.permissionStatus() 21 | } 22 | 23 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 24 | 25 | EKEventStore().requestAccess(to: type) { 26 | (accessGranted: Bool, error: Error?) in 27 | callback(accessGranted) 28 | } 29 | } 30 | 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/PermissionsService/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.9.6 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Source/Events/Events.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CalendarEvent.swift 3 | // 4 | // Created by Les Melnychuk on 2/19/16. 5 | // Copyright © 2016 LembergSolutions. All rights reserved. 6 | // 7 | 8 | #if PERMISSION_EVENTS 9 | import UIKit 10 | import EventKit 11 | 12 | public final class Events: PermissionService { 13 | 14 | public required init(with configuration: PermissionConfiguration) { } 15 | 16 | let type = EKEntityType.event 17 | 18 | public func requestPermission(_ requestGranted: @escaping (_ successRequestResult: Bool) -> Void) { 19 | 20 | EKEventStore().requestAccess(to: type) { 21 | (accessGranted: Bool, error: Error?) in 22 | requestGranted(accessGranted) 23 | } 24 | } 25 | 26 | public func status() -> PermissionStatus { 27 | let status = EKEventStore.authorizationStatus(for: type) 28 | return status.rawValue.permissionStatus() 29 | } 30 | 31 | 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Example/Pods-Example-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/PermissionsService/PermissionsService-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.9.61 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /PermissionsService/Classes/Microphone.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Microphone.swift 3 | // 4 | // Created by Hellen Soloviy on 6/6/17. 5 | // 6 | 7 | 8 | import Foundation 9 | import Photos 10 | 11 | public final class Microphone: PermissionService { 12 | 13 | let mediaType = AVMediaTypeAudio 14 | 15 | public required init(with configuration: PermissionConfiguration) { } 16 | 17 | public func status() -> PermissionStatus { 18 | let statusInt = AVCaptureDevice.authorizationStatus(forMediaType: mediaType).rawValue 19 | guard let status = PermissionStatus(rawValue: statusInt), (0...3) ~= statusInt else { 20 | assertionFailure("Impossible status") 21 | return .notDetermined 22 | } 23 | return status 24 | } 25 | 26 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 27 | 28 | AVCaptureDevice.requestAccess(forMediaType: mediaType) { (granted) -> Void in 29 | callback(granted) 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Source/Siri/Siri.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Siri.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/24/17. 6 | // 7 | // 8 | 9 | #if PERMISSION_SIRI 10 | import Foundation 11 | import Intents 12 | 13 | @available(iOS 10.0, *) 14 | public final class Siri: PermissionService { 15 | 16 | public required init(with configuration: PermissionConfiguration) { } 17 | 18 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 19 | 20 | INPreferences.requestSiriAuthorization { status in 21 | switch status { 22 | case .authorized: 23 | callback(true) 24 | case .denied, .restricted, .notDetermined: 25 | callback(false) 26 | } 27 | } 28 | } 29 | 30 | 31 | public func status() -> PermissionStatus { 32 | let status = INPreferences.siriAuthorizationStatus() 33 | return status.rawValue.permissionStatus() 34 | } 35 | 36 | 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /Source/Notifications/Notifications.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Notifications.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/25/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | import UserNotifications 11 | 12 | //TODO: Not End 13 | private final class Notifications: PermissionService { 14 | 15 | public required init(with configuration: PermissionConfiguration) { } 16 | 17 | /** 18 | */ 19 | 20 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 21 | //TODO: Error handling 22 | 23 | if #available(iOS 10.0, *) { 24 | UNUserNotificationCenter.current().requestAuthorization(options: [.alert]) { (result, error) in 25 | 26 | } 27 | } else { 28 | // Fallback on earlier version 29 | 30 | } 31 | 32 | } 33 | 34 | /** 35 | 36 | */ 37 | 38 | public func status() -> PermissionStatus { 39 | return .notDetermined 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /PermissionsService/Classes/Notifications.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Notifications.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/25/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | import UserNotifications 11 | 12 | //TODO: Not End 13 | private final class Notifications: PermissionService { 14 | 15 | public required init(with configuration: PermissionConfiguration) { } 16 | 17 | /** 18 | */ 19 | 20 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 21 | //TODO: Error handling 22 | 23 | if #available(iOS 10.0, *) { 24 | UNUserNotificationCenter.current().requestAuthorization(options: [.alert]) { (result, error) in 25 | 26 | } 27 | } else { 28 | // Fallback on earlier version 29 | 30 | } 31 | 32 | } 33 | 34 | /** 35 | 36 | */ 37 | 38 | public func status() -> PermissionStatus { 39 | return .notDetermined 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /PermissionsService/Classes/Siri.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Siri.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/24/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | import Intents 11 | 12 | @available(iOS 10.0, *) 13 | public final class Siri: PermissionService { 14 | 15 | public required init(with configuration: PermissionConfiguration) { } 16 | 17 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 18 | 19 | INPreferences.requestSiriAuthorization { status in 20 | switch status { 21 | case .authorized: 22 | callback(true) 23 | break 24 | case .denied, .restricted, .notDetermined: 25 | callback(false) 26 | break 27 | } 28 | } 29 | } 30 | 31 | 32 | public func status() -> PermissionStatus { 33 | let status = INPreferences.siriAuthorizationStatus() 34 | return status.rawValue.permissionStatus() 35 | } 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /PermissionsService/Classes/Gallery.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Gallery.swift 3 | // 4 | // Created by Volodymyr Hyrka on 2/9/16. 5 | // Copyright © 2016 LembergSolutions. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | import Photos 10 | 11 | public final class Gallery: PermissionService { 12 | 13 | public required init(with configuration: PermissionConfiguration) { } 14 | 15 | public func status() -> PermissionStatus { 16 | let statusInt = PHPhotoLibrary.authorizationStatus().rawValue 17 | guard let status = PermissionStatus(rawValue: statusInt), (0...3) ~= statusInt else { 18 | assertionFailure("Impossible status") 19 | return .notDetermined 20 | } 21 | return status 22 | } 23 | 24 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 25 | 26 | PHPhotoLibrary.requestAuthorization({ (newStatus) -> Void in 27 | let success = newStatus == PHAuthorizationStatus.authorized 28 | callback(success) 29 | }) 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Example/Pods/PermissionConfiguration.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // PermissionConfiguration.swift 3 | // 4 | 5 | PERMISSION_CAMERA = PERMISSION_CAMERA 6 | PERMISSION_CONTACTS = PERMISSION_CONTACTS 7 | PERMISSION_EVENTS = PERMISSION_EVENTS 8 | PERMISSION_LOCATION = PERMISSION_LOCATION 9 | PERMISSION_MICROPHONE = PERMISSION_MICROPHONE 10 | PERMISSION_MEDIA_LIBRARY = PERMISSION_MEDIA_LIBRARY 11 | PERMISSION_GALLERY = PERMISSION_GALLERY 12 | PERMISSION_REMINDER = PERMISSION_REMINDER 13 | PERMISSION_SPEECH_RECOGNITION = PERMISSION_SPEECH_RECOGNITION 14 | PERMISSION_SIRI = PERMISSION_SIRI 15 | 16 | //// Do not modify this line. Instead, remove comments above as needed to enable the categories your app uses. 17 | PERMISSION_FLAGS = $(PERMISSION_CAMERA) $(PERMISSION_CONTACTS) $(PERMISSION_EVENTS) $(PERMISSION_LOCATION) $(PERMISSION_MICROPHONE) $(PERMISSION_MEDIA_LIBRARY) $(PERMISSION_GALLERY) $(PERMISSION_REMINDER) $(PERMISSION_SPEECH_RECOGNITION) $(PERMISSION_SIRI) 18 | 19 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) $(PERMISSION_FLAGS) 20 | -------------------------------------------------------------------------------- /Example/Pods/PermissionsServiceTests/PermissionResultTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PermissionResultTests.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 8/29/17. 6 | // 7 | // 8 | 9 | import XCTest 10 | 11 | class PermissionResultTests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | super.tearDown() 21 | } 22 | 23 | func testExample() { 24 | // This is an example of a functional test case. 25 | // Use XCTAssert and related functions to verify your tests produce the correct results. 26 | 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /PermissionsService/Classes/Reminder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Reminder.swift 3 | // 4 | // Created by Hellen Soloviy on 6/6/17. 5 | // Copyright © 2016 LembergSolutions. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | import EventKit 10 | 11 | public final class Reminder: PermissionService { 12 | 13 | let entityType = EKEntityType.reminder 14 | 15 | public required init(with configuration: PermissionConfiguration) { } 16 | 17 | public func status() -> PermissionStatus { 18 | let statusInt = EKEventStore.authorizationStatus(for: entityType).rawValue 19 | guard let status = PermissionStatus(rawValue: statusInt), (0...3) ~= statusInt else { 20 | assertionFailure("Impossible status") 21 | return .notDetermined 22 | } 23 | return status 24 | } 25 | 26 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 27 | 28 | EKEventStore().requestAccess(to: entityType) { 29 | (accessGranted: Bool, error: Error?) in 30 | callback(accessGranted) 31 | } 32 | } 33 | 34 | } 35 | 36 | -------------------------------------------------------------------------------- /Example/Example/Resourses/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /PermissionsService/Classes/Events.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CalendarEvent.swift 3 | // 4 | // Created by Les Melnychuk on 2/19/16. 5 | // Copyright © 2016 LembergSolutions. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | import EventKit 10 | 11 | public final class Events: PermissionService { 12 | 13 | public required init(with configuration: PermissionConfiguration) { } 14 | 15 | let type = EKEntityType.event 16 | 17 | public func requestPermission(_ requestGranted: @escaping (_ successRequestResult: Bool) -> Void) { 18 | 19 | EKEventStore().requestAccess(to: type) { 20 | (accessGranted: Bool, error: Error?) in 21 | requestGranted(accessGranted) 22 | } 23 | } 24 | 25 | public func status() -> PermissionStatus { 26 | let statusInt = EKEventStore.authorizationStatus(for: type).rawValue 27 | guard let status = PermissionStatus(rawValue: statusInt), (0...3) ~= statusInt else { 28 | assertionFailure("Impossible status") 29 | return .notDetermined 30 | } 31 | return status 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /Example/Pods/PermissionsServiceTests/PermissionServiceTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PermissionServiceTests.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 8/28/17. 6 | // 7 | // 8 | 9 | import XCTest 10 | @testable import PermissionsService 11 | 12 | class PermissionServiceTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Example/Pods/PermissionsServiceTests/SiriTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SiriTests.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 8/28/17. 6 | // 7 | // 8 | 9 | import XCTest 10 | @testable import PermissionsService 11 | 12 | class SiriTests: XCTestCase { 13 | 14 | var object: Siri! 15 | 16 | override func setUp() { 17 | super.setUp() 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | testSiriInit() 20 | } 21 | 22 | override func tearDown() { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | super.tearDown() 25 | } 26 | 27 | //test if inits without problems 28 | func testSiriInit() { 29 | object = Siri(with: DefaultConfiguration()) 30 | XCTAssertNotNil(object) 31 | } 32 | 33 | func testPerformanceExample() { 34 | // This is an example of a performance test case. 35 | self.measure { 36 | // Put the code you want to measure the time of here. 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /Example/Pods/PermissionsServiceTests/GalleryTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GalleryTests.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 8/28/17. 6 | // 7 | // 8 | 9 | import XCTest 10 | @testable import PermissionsService 11 | 12 | class GalleryTests: XCTestCase { 13 | 14 | var object: Gallery! 15 | 16 | override func setUp() { 17 | super.setUp() 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | testGalleryInit() 20 | } 21 | 22 | override func tearDown() { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | super.tearDown() 25 | } 26 | 27 | //test if inits without problems 28 | func testGalleryInit() { 29 | object = Gallery(with: DefaultConfiguration()) 30 | XCTAssertNotNil(object) 31 | } 32 | 33 | 34 | func testPerformanceExample() { 35 | // This is an example of a performance test case. 36 | self.measure { 37 | // Put the code you want to measure the time of here. 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Example/Pods/PermissionsServiceTests/ContactsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContactsTests.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 8/28/17. 6 | // 7 | // 8 | import XCTest 9 | @testable import PermissionsService 10 | 11 | class ContactsTests: XCTestCase { 12 | 13 | var object: Contacts! 14 | 15 | override func setUp() { 16 | super.setUp() 17 | // Put setup code here. This method is called before the invocation of each test method in the class. 18 | testContactsInit() 19 | } 20 | 21 | override func tearDown() { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | super.tearDown() 24 | } 25 | 26 | //test if inits without problems 27 | func testContactsInit() { 28 | object = Contacts(with: DefaultConfiguration()) 29 | XCTAssertNotNil(object) 30 | } 31 | 32 | 33 | func testPerformanceExample() { 34 | // This is an example of a performance test case. 35 | self.measure { 36 | // Put the code you want to measure the time of here. 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /PermissionsService/Classes/Camera/Camera.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Camera.swift 3 | // 4 | // Created by Volodymyr Hyrka on 2/9/16. 5 | // Copyright © 2016 LembergSolutions. All rights reserved. 6 | // 7 | 8 | #if PERMISSION_CAMERA 9 | import Foundation 10 | import Photos 11 | 12 | public final class Camera: PermissionService { 13 | 14 | public required init(with configuration: PermissionConfiguration) { } 15 | 16 | let mediaType = AVMediaTypeVideo 17 | 18 | public init() {} 19 | 20 | public func status() -> PermissionStatus { 21 | let statusInt = AVCaptureDevice.authorizationStatus(forMediaType: mediaType).rawValue 22 | guard let status = PermissionStatus(rawValue: statusInt), (0...3) ~= statusInt else { 23 | assertionFailure("Impossible status") 24 | return .notDetermined 25 | } 26 | return status 27 | } 28 | 29 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 30 | 31 | AVCaptureDevice.requestAccess(forMediaType: mediaType) { (granted) -> Void in 32 | callback(granted) 33 | } 34 | } 35 | 36 | } 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /Example/Pods/PermissionsServiceTests/MediaLibraryTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MediaLibraryTests.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 8/28/17. 6 | // 7 | // 8 | 9 | import XCTest 10 | @testable import PermissionsService 11 | 12 | class MediaLibraryTests: XCTestCase { 13 | 14 | var object: MediaLibrary! 15 | 16 | override func setUp() { 17 | super.setUp() 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | testMediaLibraryInit() 20 | } 21 | 22 | override func tearDown() { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | super.tearDown() 25 | } 26 | 27 | //test if inits without problems 28 | func testMediaLibraryInit() { 29 | object = MediaLibrary(with: DefaultConfiguration()) 30 | XCTAssertNotNil(object) 31 | } 32 | 33 | func testPerformanceExample() { 34 | // This is an example of a performance test case. 35 | self.measure { 36 | // Put the code you want to measure the time of here. 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /Example/Pods/PermissionsServiceTests/SpeechRecognitionTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SpeechRecognitionTests.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 8/28/17. 6 | // 7 | // 8 | 9 | import XCTest 10 | @testable import PermissionsService 11 | 12 | class SpeechRecognitionTests: XCTestCase { 13 | 14 | var object: SpeechRecognition! 15 | 16 | override func setUp() { 17 | super.setUp() 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | testSpeechRecognitionInit() 20 | } 21 | 22 | override func tearDown() { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | super.tearDown() 25 | } 26 | 27 | //test if inits without problems 28 | func testSpeechRecognitionInit() { 29 | object = SpeechRecognition(with: DefaultConfiguration()) 30 | XCTAssertNotNil(object) 31 | } 32 | 33 | 34 | func testPerformanceExample() { 35 | // This is an example of a performance test case. 36 | self.measure { 37 | // Put the code you want to measure the time of here. 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Source/MediaLibrary/MediaLibrary.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MediaLibrary.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/25/17. 6 | // 7 | // 8 | 9 | #if PERMISSION_MEDIA_LIBRARY 10 | import Foundation 11 | import MediaPlayer 12 | 13 | 14 | @available(iOS 9.3, *) 15 | public final class MediaLibrary: PermissionService { 16 | 17 | public required init(with configuration: PermissionConfiguration) { } 18 | 19 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 20 | 21 | MPMediaLibrary.requestAuthorization { status in 22 | 23 | let status = status.rawValue.permissionStatus() 24 | var permissionGranted = false 25 | 26 | switch (status) { 27 | case .authorized: 28 | permissionGranted = true 29 | default: 30 | permissionGranted = false 31 | } 32 | 33 | callback(permissionGranted) 34 | } 35 | 36 | } 37 | 38 | public func status() -> PermissionStatus { 39 | 40 | let status = MPMediaLibrary.authorizationStatus() 41 | return status.rawValue.permissionStatus() 42 | } 43 | 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /Source/SpeechRecognition/SpeechRecognition.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SpeechRecognition.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/25/17. 6 | // 7 | // 8 | 9 | #if PERMISSION_SPEECH_RECOGNITION 10 | import Foundation 11 | import Speech 12 | 13 | @available(iOS 10.0, *) 14 | public final class SpeechRecognition: PermissionService { 15 | 16 | public required init(with configuration: PermissionConfiguration) { } 17 | 18 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 19 | 20 | SFSpeechRecognizer.requestAuthorization { status in 21 | 22 | let status = status.rawValue.permissionStatus() 23 | var permissionGranted = false 24 | 25 | switch (status) { 26 | case .authorized: 27 | permissionGranted = true 28 | default: 29 | permissionGranted = false 30 | } 31 | 32 | callback(permissionGranted) 33 | } 34 | 35 | } 36 | 37 | public func status() -> PermissionStatus { 38 | 39 | let status = SFSpeechRecognizer.authorizationStatus() 40 | return status.rawValue.permissionStatus() 41 | 42 | } 43 | 44 | } 45 | #endif 46 | -------------------------------------------------------------------------------- /PermissionsService/Classes/MediaLibrary.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MediaLibrary.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/25/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | import MediaPlayer 11 | 12 | 13 | @available(iOS 9.3, *) 14 | public final class MediaLibrary: PermissionService { 15 | 16 | public required init(with configuration: PermissionConfiguration) { } 17 | 18 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 19 | 20 | //TODO: Error handling 21 | 22 | MPMediaLibrary.requestAuthorization { status in 23 | 24 | let status = status.rawValue.permissionStatus() 25 | var permissionGranted = false 26 | 27 | switch (status) { 28 | case .authorized: 29 | permissionGranted = true 30 | break 31 | default: 32 | permissionGranted = false 33 | break 34 | } 35 | 36 | callback(permissionGranted) 37 | } 38 | 39 | } 40 | 41 | public func status() -> PermissionStatus { 42 | 43 | let status = MPMediaLibrary.authorizationStatus() 44 | return status.rawValue.permissionStatus() 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /PermissionsService/Classes/SpeechRecognition.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SpeechRecognition.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/25/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | import Speech 11 | 12 | @available(iOS 10.0, *) 13 | public final class SpeechRecognition: PermissionService { 14 | 15 | public required init(with configuration: PermissionConfiguration) { } 16 | 17 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 18 | 19 | //TODO: Error handling 20 | 21 | SFSpeechRecognizer.requestAuthorization { status in 22 | 23 | let status = status.rawValue.permissionStatus() 24 | var permissionGranted = false 25 | 26 | switch (status) { 27 | case .authorized: 28 | permissionGranted = true 29 | break 30 | default: 31 | permissionGranted = false 32 | break 33 | } 34 | 35 | callback(permissionGranted) 36 | } 37 | 38 | } 39 | 40 | public func status() -> PermissionStatus { 41 | 42 | let status = SFSpeechRecognizer.authorizationStatus() 43 | return status.rawValue.permissionStatus() 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Source/Core/Permissible.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ServiceDisplay.swift 3 | // 4 | // Created by Hellen Soloviy on 7/24/17. 5 | // 6 | // 7 | 8 | import Foundation 9 | 10 | public protocol ServiceMessages { 11 | 12 | var restrictedMessage: String { get } 13 | var restrictedTitle: String { get } 14 | var deniedMessage: String { get } 15 | var deniedTitle: String { get } 16 | } 17 | 18 | public protocol Permissible { 19 | 20 | func showAlert(vc: UIAlertController) 21 | } 22 | 23 | public extension Permissible where Self: UIViewController { 24 | 25 | func showAlert(vc: UIAlertController) { 26 | self.present(vc, animated: true, completion: nil) 27 | } 28 | 29 | } 30 | 31 | public extension ServiceMessages { 32 | 33 | func isEqual(to compareble: ServiceMessages) -> Bool { 34 | 35 | var isEqual: Bool = false 36 | 37 | if (self.deniedMessage == compareble.deniedMessage && 38 | self.deniedTitle == compareble.deniedTitle && 39 | self.restrictedMessage == compareble.restrictedMessage && 40 | self.restrictedTitle == compareble.restrictedTitle) { 41 | isEqual = true 42 | } else { 43 | isEqual = false 44 | } 45 | 46 | return isEqual 47 | 48 | } 49 | 50 | } 51 | 52 | -------------------------------------------------------------------------------- /Example/README.md: -------------------------------------------------------------------------------- 1 | # PermissionsService 2 | 3 | [![CI Status](http://img.shields.io/travis/lemberg/ios-permissions-service.svg?style=flat)](https://travis-ci.org/lemberg/ios-permissions-service.svg?branch=master) 4 | [![Version](https://img.shields.io/cocoapods/v/PermissionsService.svg?style=flat)](http://cocoapods.org/pods/PermissionsService) 5 | [![License](https://img.shields.io/cocoapods/l/PermissionsService.svg?style=flat)](http://cocoapods.org/pods/PermissionsService) 6 | [![Platform](https://img.shields.io/cocoapods/p/PermissionsService.svg?style=flat)](http://cocoapods.org/pods/PermissionsService) 7 | 8 | ## Example 9 | 10 | ```swift 11 | class ViewController: UIViewController { 12 | 13 | @IBAction func onButtonClick() { 14 | 15 | Permission.prepare(for: self, callback: { (granted) in 16 | if granted { 17 | self.performSegue(withIdentifier: "showGallery", sender: self) 18 | } 19 | }) 20 | } 21 | } 22 | ``` 23 | 24 | ## Installation 25 | 26 | ios-permissions-service is available through [CocoaPods](http://cocoapods.org). To install 27 | it, simply add the following line to your Podfile: 28 | 29 | ```ruby 30 | pod "PermissionsService" 31 | ``` 32 | 33 | ## Author 34 | 35 | Lemberg Solutions Inc 36 | 37 | ## License 38 | 39 | ios-permissions-service is available under the BSD license. See the LICENSE file for more info. 40 | -------------------------------------------------------------------------------- /Example/Pods/PermissionsServiceTests/CameraTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CameraTests.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 8/28/17. 6 | // 7 | // 8 | 9 | import XCTest 10 | import Photos 11 | @testable import PermissionsService 12 | 13 | class CameraTests: XCTestCase { 14 | 15 | var object: Camera! 16 | 17 | override func setUp() { 18 | super.setUp() 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | testCameraInit() 21 | } 22 | 23 | override func tearDown() { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | super.tearDown() 26 | } 27 | 28 | //test if inits without problems 29 | func testCameraInit() { 30 | object = Camera(with: DefaultConfiguration()) 31 | XCTAssertNotNil(object) 32 | } 33 | 34 | //this class supports not all types, so we test if type is correct 35 | func testIfPermissionTypeIsCorrect() { 36 | XCTAssertEqual(object.type, AVMediaTypeVideo) 37 | } 38 | 39 | func testPerformanceExample() { 40 | // This is an example of a performance test case. 41 | self.measure { 42 | // Put the code you want to measure the time of here. 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /Example/Pods/PermissionsServiceTests/EventsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EventsTests.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 8/28/17. 6 | // 7 | // 8 | 9 | import XCTest 10 | import EventKit 11 | @testable import PermissionsService 12 | 13 | class EventsTests: XCTestCase { 14 | 15 | var object: Events! 16 | 17 | override func setUp() { 18 | super.setUp() 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | testEventsInit() 21 | } 22 | 23 | override func tearDown() { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | super.tearDown() 26 | } 27 | 28 | //test if inits without problems 29 | func testEventsInit() { 30 | object = Events(with: DefaultConfiguration()) 31 | XCTAssertNotNil(object) 32 | } 33 | 34 | //this class supports only one type .event, so we test if type is correct 35 | func testIfPermissionTypeIsCorrect() { 36 | XCTAssertEqual(object.type, EKEntityType.event) 37 | } 38 | 39 | func testPerformanceExample() { 40 | // This is an example of a performance test case. 41 | self.measure { 42 | // Put the code you want to measure the time of here. 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /Example/Pods/PermissionsServiceTests/MicrophoneTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MicrophoneTests.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 8/28/17. 6 | // 7 | // 8 | 9 | import XCTest 10 | import Photos 11 | @testable import PermissionsService 12 | 13 | class MicrophoneTests: XCTestCase { 14 | 15 | var object: Microphone! 16 | 17 | override func setUp() { 18 | super.setUp() 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | testMicrophoneInit() 21 | } 22 | 23 | override func tearDown() { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | super.tearDown() 26 | } 27 | 28 | //test if inits without problems 29 | func testMicrophoneInit() { 30 | object = Microphone(with: DefaultConfiguration()) 31 | XCTAssertNotNil(object) 32 | } 33 | 34 | //this class supports not all types, so we test if type is correct 35 | func testIfPermissionTypeIsCorrect() { 36 | XCTAssertEqual(object.type, AVMediaTypeAudio) 37 | } 38 | 39 | func testPerformanceExample() { 40 | // This is an example of a performance test case. 41 | self.measure { 42 | // Put the code you want to measure the time of here. 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /Example/Pods/PermissionsServiceTests/ReminderTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReminderTests.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 8/28/17. 6 | // 7 | // 8 | 9 | import EventKit 10 | import XCTest 11 | @testable import PermissionsService 12 | 13 | class ReminderTests: XCTestCase { 14 | 15 | var object: Reminder! 16 | 17 | override func setUp() { 18 | super.setUp() 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | testReminderInit() 21 | } 22 | 23 | override func tearDown() { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | super.tearDown() 26 | } 27 | 28 | //test if inits without problems 29 | func testReminderInit() { 30 | object = Reminder(with: DefaultConfiguration()) 31 | XCTAssertNotNil(object) 32 | } 33 | 34 | //this class supports only one type .reminder, so we test if type is correct 35 | func testIfPermissionTypeIsCorrect() { 36 | XCTAssertEqual(object.type, EKEntityType.reminder) 37 | } 38 | 39 | func testPerformanceExample() { 40 | // This is an example of a performance test case. 41 | self.measure { 42 | // Put the code you want to measure the time of here. 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /PermissionsService/Classes/LocationConfiguration.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LocationConfiguration.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/25/17. 6 | // 7 | // 8 | 9 | #if PERMISSION_LOCATION 10 | 11 | import Foundation 12 | import CoreLocation 13 | 14 | /** 15 | Class for configuration of location permission service, where can be two types of permission. For now only iOS 10 support. In future it will support new keys for iOS 11 too. 16 | */ 17 | public final class LocationConfiguration: PermissionConfiguration { 18 | 19 | public let messages: ServiceMessages 20 | public let permissionType: LocationPermissionType 21 | 22 | /** 23 | Enum Int values based on rawValues of CoreLocation status enum - CLAuthorizationStatus. 24 | 25 | - description: For pretty print if needed 26 | */ 27 | public enum LocationPermissionType: Int, CustomStringConvertible { 28 | case always = 3 29 | case whenInUse = 4 30 | 31 | public var description: String { 32 | switch self { 33 | case .always: return "always authorization" 34 | case .whenInUse: return "whenInUse authorization" 35 | } 36 | } 37 | } 38 | 39 | public required init(_ type: LocationPermissionType = .whenInUse, with messages: ServiceMessages = DefaultMessages()) { 40 | 41 | self.messages = messages 42 | self.permissionType = type 43 | print("Configuration created for \(permissionType.description)") 44 | 45 | } 46 | 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /Source/Location/LocationConfiguration.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LocationConfiguration.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/25/17. 6 | // 7 | // 8 | 9 | #if PERMISSION_LOCATION 10 | 11 | import Foundation 12 | import CoreLocation 13 | 14 | /** 15 | Class for configuration of location permission service, where can be two types of permission. For now only iOS 10 support. In future it will support new keys for iOS 11 too. 16 | */ 17 | public final class LocationConfiguration: PermissionConfiguration { 18 | 19 | public let messages: ServiceMessages 20 | public let permissionType: LocationPermissionType 21 | 22 | /** 23 | Enum Int values based on rawValues of CoreLocation status enum - CLAuthorizationStatus. 24 | 25 | - description: For pretty print if needed 26 | */ 27 | public enum LocationPermissionType: Int, CustomStringConvertible { 28 | case always = 3 29 | case whenInUse = 4 30 | 31 | public var description: String { 32 | switch self { 33 | case .always: return "always authorization" 34 | case .whenInUse: return "whenInUse authorization" 35 | } 36 | } 37 | 38 | } 39 | 40 | public required init(_ type: LocationPermissionType = .whenInUse, with messages: ServiceMessages = DefaultMessages()) { 41 | 42 | self.messages = messages 43 | self.permissionType = type 44 | print("Configuration created for \(permissionType.description)") 45 | 46 | } 47 | 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /PermissionsService/Classes/Location/LocationConfiguration.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LocationConfiguration.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/25/17. 6 | // 7 | // 8 | 9 | #if PERMISSION_LOCATION 10 | 11 | import Foundation 12 | import CoreLocation 13 | 14 | /** 15 | Class for configuration of location permission service, where can be two types of permission. For now only iOS 10 support. In future it will support new keys for iOS 11 too. 16 | */ 17 | public final class LocationConfiguration: PermissionConfiguration { 18 | 19 | public let messages: ServiceMessages 20 | public let permissionType: LocationPermissionType 21 | 22 | /** 23 | Enum Int values based on rawValues of CoreLocation status enum - CLAuthorizationStatus. 24 | 25 | - description: For pretty print if needed 26 | */ 27 | public enum LocationPermissionType: Int, CustomStringConvertible { 28 | case always = 3 29 | case whenInUse = 4 30 | 31 | public var description: String { 32 | switch self { 33 | case .always: return "always authorization" 34 | case .whenInUse: return "whenInUse authorization" 35 | } 36 | } 37 | } 38 | 39 | public required init(_ type: LocationPermissionType = .whenInUse, with messages: ServiceMessages = DefaultMessages()) { 40 | 41 | self.messages = messages 42 | self.permissionType = type 43 | print("Configuration created for \(permissionType.description)") 44 | 45 | } 46 | 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - PermissionsService/Camera (0.9.61): 3 | - PermissionsService/Core 4 | - PermissionsService/Contacts (0.9.61): 5 | - PermissionsService/Core 6 | - PermissionsService/Core (0.9.61) 7 | - PermissionsService/Events (0.9.61): 8 | - PermissionsService/Core 9 | - PermissionsService/Gallery (0.9.61): 10 | - PermissionsService/Core 11 | - PermissionsService/Location (0.9.61): 12 | - PermissionsService/Core 13 | - PermissionsService/MediaLibrary (0.9.61): 14 | - PermissionsService/Core 15 | - PermissionsService/Microphone (0.9.61): 16 | - PermissionsService/Core 17 | - PermissionsService/Reminder (0.9.61): 18 | - PermissionsService/Core 19 | - PermissionsService/Siri (0.9.61): 20 | - PermissionsService/Core 21 | - PermissionsService/SpeechRecognition (0.9.61): 22 | - PermissionsService/Core 23 | 24 | DEPENDENCIES: 25 | - PermissionsService/Camera (from `../`) 26 | - PermissionsService/Contacts (from `../`) 27 | - PermissionsService/Events (from `../`) 28 | - PermissionsService/Gallery (from `../`) 29 | - PermissionsService/Location (from `../`) 30 | - PermissionsService/MediaLibrary (from `../`) 31 | - PermissionsService/Microphone (from `../`) 32 | - PermissionsService/Reminder (from `../`) 33 | - PermissionsService/Siri (from `../`) 34 | - PermissionsService/SpeechRecognition (from `../`) 35 | 36 | EXTERNAL SOURCES: 37 | PermissionsService: 38 | :path: "../" 39 | 40 | SPEC CHECKSUMS: 41 | PermissionsService: 9b986838c3a7cd1d14238dab7fa4fda7918435bb 42 | 43 | PODFILE CHECKSUM: 92f3ab47c41087396f2c64bca1e2b996de094b06 44 | 45 | COCOAPODS: 1.6.1 46 | -------------------------------------------------------------------------------- /Example/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - PermissionsService/Camera (0.9.61): 3 | - PermissionsService/Core 4 | - PermissionsService/Contacts (0.9.61): 5 | - PermissionsService/Core 6 | - PermissionsService/Core (0.9.61) 7 | - PermissionsService/Events (0.9.61): 8 | - PermissionsService/Core 9 | - PermissionsService/Gallery (0.9.61): 10 | - PermissionsService/Core 11 | - PermissionsService/Location (0.9.61): 12 | - PermissionsService/Core 13 | - PermissionsService/MediaLibrary (0.9.61): 14 | - PermissionsService/Core 15 | - PermissionsService/Microphone (0.9.61): 16 | - PermissionsService/Core 17 | - PermissionsService/Reminder (0.9.61): 18 | - PermissionsService/Core 19 | - PermissionsService/Siri (0.9.61): 20 | - PermissionsService/Core 21 | - PermissionsService/SpeechRecognition (0.9.61): 22 | - PermissionsService/Core 23 | 24 | DEPENDENCIES: 25 | - PermissionsService/Camera (from `../`) 26 | - PermissionsService/Contacts (from `../`) 27 | - PermissionsService/Events (from `../`) 28 | - PermissionsService/Gallery (from `../`) 29 | - PermissionsService/Location (from `../`) 30 | - PermissionsService/MediaLibrary (from `../`) 31 | - PermissionsService/Microphone (from `../`) 32 | - PermissionsService/Reminder (from `../`) 33 | - PermissionsService/Siri (from `../`) 34 | - PermissionsService/SpeechRecognition (from `../`) 35 | 36 | EXTERNAL SOURCES: 37 | PermissionsService: 38 | :path: "../" 39 | 40 | SPEC CHECKSUMS: 41 | PermissionsService: 9b986838c3a7cd1d14238dab7fa4fda7918435bb 42 | 43 | PODFILE CHECKSUM: 92f3ab47c41087396f2c64bca1e2b996de094b06 44 | 45 | COCOAPODS: 1.6.1 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Lemberg Inc 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. All advertising materials mentioning features or use of this software 12 | must display the following acknowledgement: 13 | This product includes software developed by the Lemberg Inc. 14 | 4. Neither the name of the Lemberg Inc nor the 15 | names of its contributors may be used to endorse or promote products 16 | derived from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY Lemberg Inc ''AS IS'' AND ANY 19 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL Lemberg Inc BE LIABLE FOR ANY 22 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /PermissionsService/Classes/Contacts.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Contacts.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/24/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | import Contacts 11 | import AddressBook 12 | 13 | public final class Contacts: PermissionService { 14 | 15 | public required init(with configuration: PermissionConfiguration) { } 16 | 17 | /** 18 | Request for accessing Contacts. 19 | 20 | - returns: Permission request result and error, if it exist 21 | */ 22 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 23 | //TODO: Error handling 24 | 25 | if #available(iOS 8.0, *) { 26 | ABAddressBookRequestAccessWithCompletion(nil) { grandted, error in 27 | callback(grandted) 28 | } 29 | 30 | } else { 31 | CNContactStore().requestAccess(for: .contacts, completionHandler: { 32 | grandted, error in 33 | callback(grandted) 34 | }) 35 | } 36 | 37 | } 38 | 39 | /** 40 | Returns the current permission status for accessing Contacts. 41 | 42 | - returns: Current permission status. 43 | */ 44 | public func status() -> PermissionStatus { 45 | 46 | if #available(iOS 8.0, *) { 47 | let status = ABAddressBookGetAuthorizationStatus() 48 | return status.rawValue.permissionStatus() 49 | 50 | } else { 51 | let status = CNContactStore.authorizationStatus(for: .contacts) 52 | return status.rawValue.permissionStatus() 53 | 54 | } 55 | } 56 | 57 | 58 | } 59 | -------------------------------------------------------------------------------- /Source/Contacts/Contacts.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Contacts.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/24/17. 6 | // 7 | // 8 | 9 | #if PERMISSION_CONTACTS 10 | import Foundation 11 | import Contacts 12 | import AddressBook 13 | 14 | public final class Contacts: PermissionService { 15 | 16 | public required init(with configuration: PermissionConfiguration) { } 17 | 18 | /** 19 | Request for accessing Contacts. 20 | 21 | - returns: Permission request result and error, if it exist 22 | */ 23 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 24 | 25 | if #available(iOS 8.0, *) { 26 | ABAddressBookRequestAccessWithCompletion(nil) { grandted, error in 27 | callback(grandted) 28 | } 29 | 30 | } else { 31 | CNContactStore().requestAccess(for: .contacts, completionHandler: { 32 | grandted, error in 33 | callback(grandted) 34 | }) 35 | } 36 | 37 | } 38 | 39 | /** 40 | Returns the current permission status for accessing Contacts. 41 | 42 | - returns: Current permission status. 43 | */ 44 | public func status() -> PermissionStatus { 45 | 46 | if #available(iOS 8.0, *) { 47 | let status = ABAddressBookGetAuthorizationStatus() 48 | return status.rawValue.permissionStatus() 49 | 50 | } else { 51 | let status = CNContactStore.authorizationStatus(for: .contacts) 52 | return status.rawValue.permissionStatus() 53 | 54 | } 55 | } 56 | 57 | 58 | } 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /PermissionsService/Classes/PermissionConfiguration.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PermissionConfiguration.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/25/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol PermissionConfiguration { 12 | var messages: ServiceMessages { get } 13 | 14 | } 15 | 16 | extension PermissionConfiguration { 17 | public var messages: ServiceMessages { return DefaultMessages() } 18 | 19 | } 20 | 21 | struct DefaultMessages: ServiceMessages { 22 | 23 | let deniedTitle = "Access denied" 24 | let deniedMessage = "You can enable access in Privacy Settings" 25 | let restrictedTitle = "Access restricted" 26 | let restrictedMessage = "Access to this component is restricted" 27 | } 28 | 29 | 30 | public final class DefaultConfiguration: PermissionConfiguration { 31 | //mock for unknown&default situations 32 | public let messages: ServiceMessages 33 | 34 | public required init(with messages: ServiceMessages = DefaultMessages()) { 35 | self.messages = messages 36 | 37 | } 38 | 39 | } 40 | 41 | 42 | public final class Configurator: PermissionConfiguration { 43 | 44 | var configuration: PermissionConfiguration = DefaultConfiguration() 45 | 46 | public init(for permission: PermissionService.Type) { 47 | 48 | #if PERMISSION_LOCATION 49 | switch permission { 50 | case is Location.Type: 51 | self.configuration = LocationConfiguration() 52 | break 53 | default: 54 | self.configuration = DefaultConfiguration() 55 | break 56 | } 57 | 58 | #else 59 | self.configuration = DefaultConfiguration() 60 | 61 | #endif 62 | 63 | 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /PermissionsService/Classes/Core/PermissionConfiguration.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PermissionConfiguration.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/25/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol PermissionConfiguration { 12 | var messages: ServiceMessages { get } 13 | 14 | } 15 | 16 | extension PermissionConfiguration { 17 | public var messages: ServiceMessages { return DefaultMessages() } 18 | 19 | } 20 | 21 | struct DefaultMessages: ServiceMessages { 22 | 23 | let deniedTitle = "Access denied" 24 | let deniedMessage = "You can enable access in Privacy Settings" 25 | let restrictedTitle = "Access restricted" 26 | let restrictedMessage = "Access to this component is restricted" 27 | } 28 | 29 | 30 | public final class DefaultConfiguration: PermissionConfiguration { 31 | //mock for unknown&default situations 32 | public let messages: ServiceMessages 33 | 34 | public required init(with messages: ServiceMessages = DefaultMessages()) { 35 | self.messages = messages 36 | 37 | } 38 | 39 | } 40 | 41 | 42 | public final class Configurator: PermissionConfiguration { 43 | 44 | var configuration: PermissionConfiguration = DefaultConfiguration() 45 | 46 | public init(for permission: PermissionService.Type) { 47 | 48 | #if PERMISSION_LOCATION 49 | switch permission { 50 | case is Location.Type: 51 | self.configuration = LocationConfiguration() 52 | break 53 | default: 54 | self.configuration = DefaultConfiguration() 55 | break 56 | } 57 | 58 | #else 59 | self.configuration = DefaultConfiguration() 60 | 61 | #endif 62 | 63 | 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /Source/Core/PermissionConfiguration.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PermissionConfiguration.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/25/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol PermissionConfiguration { 12 | var messages: ServiceMessages { get } 13 | 14 | } 15 | 16 | extension PermissionConfiguration { 17 | public var messages: ServiceMessages { return DefaultMessages() } 18 | 19 | } 20 | 21 | public struct DefaultMessages: ServiceMessages { 22 | 23 | public let deniedTitle = "Access denied" 24 | public let deniedMessage = "You can enable access in Privacy Settings" 25 | public let restrictedTitle = "Access restricted" 26 | public let restrictedMessage = "Access to this component is restricted" 27 | 28 | public init() {} 29 | } 30 | 31 | 32 | public final class DefaultConfiguration: PermissionConfiguration { 33 | //mock for unknown&default situations 34 | public let messages: ServiceMessages 35 | 36 | public required init(with messages: ServiceMessages = DefaultMessages()) { 37 | self.messages = messages 38 | 39 | } 40 | 41 | } 42 | 43 | 44 | public final class Configurator: PermissionConfiguration { 45 | 46 | public var configuration: PermissionConfiguration = DefaultConfiguration() 47 | 48 | public init(for permission: PermissionService.Type) { 49 | 50 | #if PERMISSION_LOCATION 51 | switch permission { 52 | case is Location.Type: 53 | self.configuration = LocationConfiguration() 54 | default: 55 | self.configuration = DefaultConfiguration() 56 | } 57 | 58 | #else 59 | self.configuration = DefaultConfiguration() 60 | 61 | #endif 62 | 63 | 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /Example/Example/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Example/Pods-Example-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## PermissionsService 5 | 6 | Copyright (c) 2016, Lemberg Inc 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | 1. Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 3. All advertising materials mentioning features or use of this software 17 | must display the following acknowledgement: 18 | This product includes software developed by the Lemberg Inc. 19 | 4. Neither the name of the Lemberg Inc nor the 20 | names of its contributors may be used to endorse or promote products 21 | derived from this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY Lemberg Inc ''AS IS'' AND ANY 24 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | DISCLAIMED. IN NO EVENT SHALL Lemberg Inc BE LIABLE FOR ANY 27 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | Generated by CocoaPods - https://cocoapods.org 34 | -------------------------------------------------------------------------------- /Source/Bluetooth/Bluetooth.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Bluetooth.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/24/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | import CoreBluetooth 11 | 12 | private final class Bluetooth: NSObject, PermissionService { 13 | 14 | internal var bluetoothManager = CBPeripheralManager( 15 | delegate: nil, 16 | queue: nil, 17 | options: [CBPeripheralManagerOptionShowPowerAlertKey: false] 18 | ) 19 | 20 | // internal var bluetoothManager = CBCentralManager(delegate: nil, queue: nil, options: [CBPeripheralManagerOptionShowPowerAlertKey: true]) 21 | 22 | public required init(with configuration: PermissionConfiguration) { 23 | super.init() 24 | 25 | bluetoothManager.delegate = self 26 | } 27 | 28 | /** 29 | */ 30 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 31 | 32 | //TODO: Error handling 33 | guard bluetoothManager.state == .poweredOn else { return } 34 | 35 | bluetoothManager.startAdvertising(nil) 36 | bluetoothManager.stopAdvertising() 37 | } 38 | 39 | /** 40 | 41 | */ 42 | public func status() -> PermissionStatus { 43 | let status = CBPeripheralManager.authorizationStatus() 44 | return status.rawValue.permissionStatus() 45 | } 46 | 47 | } 48 | 49 | extension Bluetooth: CBPeripheralManagerDelegate { 50 | 51 | public func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) { 52 | 53 | // UserDefaults.standard.stateBluetoothManagerDetermined = true 54 | // UserDefaults.standard.statusBluetooth = statusBluetooth 55 | // guard UserDefaults.standard.requestedBluetooth else { return } 56 | // callback?(statusBluetooth) 57 | // UserDefaults.standard.requestedBluetooth = false 58 | 59 | // if status != .notDetermined { 60 | // dispatchGroup.leave() 61 | // } 62 | // bluetoothManager.delegate = nil 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /PermissionsService/Classes/Bluetooth.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Bluetooth.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/24/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | import CoreBluetooth 11 | 12 | private final class Bluetooth: NSObject, PermissionService { 13 | 14 | internal var bluetoothManager = CBPeripheralManager( 15 | delegate: nil, 16 | queue: nil, 17 | options: [CBPeripheralManagerOptionShowPowerAlertKey: false] 18 | ) 19 | 20 | // internal var bluetoothManager = CBCentralManager(delegate: nil, queue: nil, options: [CBPeripheralManagerOptionShowPowerAlertKey: true]) 21 | 22 | public required init(with configuration: PermissionConfiguration) { 23 | super.init() 24 | 25 | bluetoothManager.delegate = self 26 | } 27 | 28 | /** 29 | */ 30 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 31 | 32 | //TODO: Error handling 33 | guard bluetoothManager.state == .poweredOn else { return } 34 | 35 | bluetoothManager.startAdvertising(nil) 36 | bluetoothManager.stopAdvertising() 37 | } 38 | 39 | /** 40 | 41 | */ 42 | public func status() -> PermissionStatus { 43 | let status = CBPeripheralManager.authorizationStatus() 44 | return status.rawValue.permissionStatus() 45 | } 46 | 47 | } 48 | 49 | extension Bluetooth: CBPeripheralManagerDelegate { 50 | 51 | public func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) { 52 | 53 | // UserDefaults.standard.stateBluetoothManagerDetermined = true 54 | // UserDefaults.standard.statusBluetooth = statusBluetooth 55 | // guard UserDefaults.standard.requestedBluetooth else { return } 56 | // callback?(statusBluetooth) 57 | // UserDefaults.standard.requestedBluetooth = false 58 | 59 | // if status != .notDetermined { 60 | // dispatchGroup.leave() 61 | // } 62 | // bluetoothManager.delegate = nil 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Example/Pods/PermissionsServiceTests/LocationTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LocationTests.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 8/28/17. 6 | // 7 | // 8 | 9 | import XCTest 10 | import CoreLocation 11 | @testable import PermissionsService 12 | 13 | class LocationTests: XCTestCase { 14 | 15 | var object: Location! 16 | let defaultAuthorizationType = CLAuthorizationStatus.authorizedWhenInUse 17 | 18 | 19 | override func setUp() { 20 | super.setUp() 21 | // Put setup code here. This method is called before the invocation of each test method in the class. 22 | } 23 | 24 | override func tearDown() { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | super.tearDown() 27 | } 28 | 29 | func testLocationInit_defaultConfiguration() { 30 | object = Location(with: DefaultConfiguration()) 31 | XCTAssertNotNil(object) 32 | 33 | XCTAssertEqual(object.type, defaultAuthorizationType) 34 | } 35 | 36 | func testLocationInit_defaultLocationConfiguration() { 37 | object = Location(with: LocationConfiguration()) 38 | XCTAssertNotNil(object) 39 | 40 | XCTAssertEqual(object.type, defaultAuthorizationType) 41 | } 42 | 43 | func testLocationInit_whenInUseLocationConfiguration() { 44 | object = Location(with: LocationConfiguration(.whenInUse)) 45 | XCTAssertNotNil(object) 46 | 47 | XCTAssertEqual(object.type, defaultAuthorizationType) 48 | } 49 | 50 | func testLocationInit_alwaysLocationConfiguration() { 51 | object = Location(with: LocationConfiguration(.always)) 52 | XCTAssertNotNil(object) 53 | 54 | XCTAssertEqual(object.type, CLAuthorizationStatus.authorizedAlways) 55 | } 56 | 57 | func testPerformanceExample() { 58 | // This is an example of a performance test case. 59 | self.measure { 60 | // Put the code you want to measure the time of here. 61 | } 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /Example/Example/Enter Point/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // Example 4 | // 5 | // Created by Yuriy Trach on 10/11/16. 6 | // Copyright © 2016 CocoaPods. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /Example/Pods/PermissionsServiceTests/PermissionStatusTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PermissionStatusTests.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 8/29/17. 6 | // 7 | // 8 | 9 | import XCTest 10 | @testable import PermissionsService 11 | 12 | class PermissionStatusTests: XCTestCase { 13 | 14 | var permissionStatus: PermissionStatus! 15 | 16 | override func setUp() { 17 | super.setUp() 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | } 20 | 21 | override func tearDown() { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | super.tearDown() 24 | } 25 | 26 | func testInit_unknownStatus() { 27 | permissionStatus = PermissionStatus.init(rawValue: -1) 28 | XCTAssertNotNil(permissionStatus) 29 | XCTAssertEqual(permissionStatus, .unknown) 30 | } 31 | 32 | func testInit_notDeterminedStatus() { 33 | permissionStatus = PermissionStatus.init(rawValue: 0) 34 | XCTAssertNotNil(permissionStatus) 35 | XCTAssertEqual(permissionStatus, .notDetermined) 36 | } 37 | 38 | func testInit_restrictedStatus() { 39 | permissionStatus = PermissionStatus.init(rawValue: 1) 40 | XCTAssertNotNil(permissionStatus) 41 | XCTAssertEqual(permissionStatus, .restricted) 42 | } 43 | 44 | func testInit_deniedStatus() { 45 | permissionStatus = PermissionStatus.init(rawValue: 2) 46 | XCTAssertNotNil(permissionStatus) 47 | XCTAssertEqual(permissionStatus, .denied) 48 | } 49 | 50 | func testInit_authorizedStatus() { 51 | permissionStatus = PermissionStatus.init(rawValue: 3) 52 | XCTAssertNotNil(permissionStatus) 53 | XCTAssertEqual(permissionStatus, .authorized) 54 | } 55 | 56 | func testInit_uncorrectStatus() { 57 | permissionStatus = PermissionStatus.init(rawValue: 5) 58 | XCTAssertNil(permissionStatus) 59 | } 60 | 61 | func testPerformanceExample() { 62 | // This is an example of a performance test case. 63 | self.measure { 64 | // Put the code you want to measure the time of here. 65 | } 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /Example/Pods/PermissionsServiceTests/ConfigurationTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ConfigurationTests.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 8/28/17. 6 | // 7 | // 8 | 9 | import XCTest 10 | @testable import PermissionsService 11 | 12 | class ConfigurationTests: XCTestCase { 13 | 14 | var configuration: Configurator! 15 | 16 | override func setUp() { 17 | super.setUp() 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | } 20 | 21 | override func tearDown() { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | super.tearDown() 24 | } 25 | 26 | func testConfiguratorInit_events() { 27 | configuration = Configurator(for: Events.self) 28 | XCTAssertTrue(configuration.configuration is DefaultConfiguration) 29 | } 30 | 31 | func testConfiguratorInit_mediaLibrary() { 32 | configuration = Configurator(for: MediaLibrary.self) 33 | XCTAssertTrue(configuration.configuration is DefaultConfiguration) 34 | } 35 | 36 | func testConfiguratorInit_camera() { 37 | configuration = Configurator(for: Camera.self) 38 | XCTAssertTrue(configuration.configuration is DefaultConfiguration) 39 | } 40 | 41 | func testConfiguratorInit_gallery() { 42 | configuration = Configurator(for: Gallery.self) 43 | XCTAssertTrue(configuration.configuration is DefaultConfiguration) 44 | } 45 | 46 | func testConfiguratorInit_contacts() { 47 | configuration = Configurator(for: Contacts.self) 48 | XCTAssertTrue(configuration.configuration is DefaultConfiguration) 49 | } 50 | 51 | func testConfiguratorInit_siri() { 52 | configuration = Configurator(for: Siri.self) 53 | XCTAssertTrue(configuration.configuration is DefaultConfiguration) 54 | } 55 | 56 | func testConfiguratorInit_speechRecognition() { 57 | configuration = Configurator(for: SpeechRecognition.self) 58 | XCTAssertTrue(configuration.configuration is DefaultConfiguration) 59 | } 60 | 61 | func testConfiguratorInit_location() { 62 | configuration = Configurator(for: Location.self) 63 | XCTAssertTrue(configuration.configuration is LocationConfiguration) 64 | } 65 | 66 | func testPerformanceExample() { 67 | // This is an example of a performance test case. 68 | self.measure { 69 | // Put the code you want to measure the time of here. 70 | } 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcshareddata/xcschemes/PermissionsService.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 66 | 67 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /Source/Core/PermissionResult.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Structs.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/24/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | List of permissions currently supported 13 | 14 | */ 15 | public enum PermissionType: Int, CustomStringConvertible { 16 | case contacts, locationAlways, locationInUse, notifications, microphone, camera, photos, reminders, events, bluetooth, motion, siri 17 | 18 | public var prettyDescription: String { 19 | switch self { 20 | case .locationAlways, .locationInUse: 21 | return "Location" 22 | default: 23 | return "\(self)" 24 | } 25 | } 26 | 27 | public var description: String { 28 | switch self { 29 | case .contacts: return "Contacts" 30 | case .events: return "Events" 31 | case .locationAlways: return "LocationAlways" 32 | case .locationInUse: return "LocationInUse" 33 | case .notifications: return "Notifications" 34 | case .microphone: return "Microphone" 35 | case .camera: return "Camera" 36 | case .photos: return "Photos" 37 | case .reminders: return "Reminders" 38 | case .bluetooth: return "Bluetooth" 39 | case .motion: return "Motion" 40 | case .siri: return "Siri" 41 | 42 | } 43 | } 44 | 45 | static let allValues = [contacts, locationAlways, locationInUse, notifications, microphone, camera, photos, reminders, events, bluetooth, motion] 46 | } 47 | 48 | /** 49 | Possible statuses for a permission. 50 | 51 | */ 52 | public enum PermissionStatus: Int, CustomStringConvertible { 53 | case unknown = -1 54 | case notDetermined = 0 55 | case restricted = 1 56 | case denied = 2 57 | case authorized = 3 58 | 59 | public var description: String { 60 | switch self { 61 | case .unknown: return "Unknown" 62 | case .notDetermined: return "NotDetermined" 63 | case .restricted: return "Restricted" // System-level 64 | case .denied: return "Denied" 65 | case .authorized: return "Authorized" 66 | } 67 | } 68 | } 69 | 70 | /** 71 | Result for a permission status request. 72 | */ 73 | public class PermissionResult: NSObject { 74 | public let type: PermissionType 75 | public let status: PermissionStatus 76 | 77 | internal init(type:PermissionType, status:PermissionStatus) { 78 | self.type = type 79 | self.status = status 80 | } 81 | 82 | override public var description: String { 83 | return "\(type) \(status)" 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Example/Pods-Example-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Copyright (c) 2016, Lemberg Inc 18 | All rights reserved. 19 | 20 | Redistribution and use in source and binary forms, with or without 21 | modification, are permitted provided that the following conditions are met: 22 | 1. Redistributions of source code must retain the above copyright 23 | notice, this list of conditions and the following disclaimer. 24 | 2. Redistributions in binary form must reproduce the above copyright 25 | notice, this list of conditions and the following disclaimer in the 26 | documentation and/or other materials provided with the distribution. 27 | 3. All advertising materials mentioning features or use of this software 28 | must display the following acknowledgement: 29 | This product includes software developed by the Lemberg Inc. 30 | 4. Neither the name of the Lemberg Inc nor the 31 | names of its contributors may be used to endorse or promote products 32 | derived from this software without specific prior written permission. 33 | 34 | THIS SOFTWARE IS PROVIDED BY Lemberg Inc ''AS IS'' AND ANY 35 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 36 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 37 | DISCLAIMED. IN NO EVENT SHALL Lemberg Inc BE LIABLE FOR ANY 38 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 39 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 40 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 41 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 42 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 43 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 44 | License 45 | BSD 46 | Title 47 | PermissionsService 48 | Type 49 | PSGroupSpecifier 50 | 51 | 52 | FooterText 53 | Generated by CocoaPods - https://cocoapods.org 54 | Title 55 | 56 | Type 57 | PSGroupSpecifier 58 | 59 | 60 | StringsTable 61 | Acknowledgements 62 | Title 63 | Acknowledgements 64 | 65 | 66 | -------------------------------------------------------------------------------- /Example/Example/Resourses/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSAppleMusicUsageDescription 24 | Permission for Example 25 | NSBluetoothPeripheralUsageDescription 26 | Permission for Example 27 | NSCalendarsUsageDescription 28 | Permission for Example 29 | NSCameraUsageDescription 30 | Permission for Example 31 | NSContactsUsageDescription 32 | Permissions for Example 33 | NSHealthShareUsageDescription 34 | Permission for Example 35 | NSHealthUpdateUsageDescription 36 | Permission for Example 37 | NSHomeKitUsageDescription 38 | Permission for Example 39 | NSLocationAlwaysUsageDescription 40 | Permission for Example 41 | NSLocationWhenInUseUsageDescription 42 | Permission for Example 43 | NSLocationAlwaysAndWhenInUseUsageDescription 44 | Permission for Example 45 | NSLocationUsageDescription 46 | Permission for Example 47 | NSMicrophoneUsageDescription 48 | Permission for Example 49 | NSMotionUsageDescription 50 | Permission for Example 51 | NSPhotoLibraryUsageDescription 52 | Permission for Example 53 | NSRemindersUsageDescription 54 | Permission for Example 55 | NSSiriUsageDescription 56 | Permission for Example 57 | NSSpeechRecognitionUsageDescription 58 | Permission for Example 59 | UILaunchStoryboardName 60 | LaunchScreen 61 | UIMainStoryboardFile 62 | Main 63 | UIRequiredDeviceCapabilities 64 | 65 | armv7 66 | 67 | UISupportedInterfaceOrientations 68 | 69 | UIInterfaceOrientationPortrait 70 | UIInterfaceOrientationLandscapeLeft 71 | UIInterfaceOrientationLandscapeRight 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /PermissionsService/Classes/Structs.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Structs.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/24/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | List of permissions currently supported 13 | 14 | */ 15 | public enum PermissionType: Int, CustomStringConvertible { 16 | case contacts, locationAlways, locationInUse, notifications, microphone, camera, photos, reminders, events, bluetooth, motion, siri 17 | 18 | public var prettyDescription: String { 19 | switch self { 20 | case .locationAlways, .locationInUse: 21 | return "Location" 22 | default: 23 | return "\(self)" 24 | } 25 | } 26 | 27 | public var description: String { 28 | switch self { 29 | case .contacts: return "Contacts" // 30 | case .events: return "Events" // 31 | case .locationAlways: return "LocationAlways" 32 | case .locationInUse: return "LocationInUse" 33 | case .notifications: return "Notifications" 34 | case .microphone: return "Microphone" // 35 | case .camera: return "Camera" // 36 | case .photos: return "Photos" // 37 | case .reminders: return "Reminders" // 38 | case .bluetooth: return "Bluetooth" 39 | case .motion: return "Motion" 40 | case .siri: return "Siri" // 41 | 42 | } 43 | } 44 | 45 | static let allValues = [contacts, locationAlways, locationInUse, notifications, microphone, camera, photos, reminders, events, bluetooth, motion] 46 | } 47 | 48 | /** 49 | Possible statuses for a permission. 50 | 51 | */ 52 | public enum PermissionStatus: Int, CustomStringConvertible { 53 | case unknown = -1 54 | case notDetermined = 0 55 | case restricted = 1 56 | case denied = 2 57 | case authorized = 3 58 | 59 | public var description: String { 60 | switch self { 61 | case .unknown: return "Unknown" 62 | case .notDetermined: return "NotDetermined" 63 | case .restricted: return "Restricted" // System-level 64 | case .denied: return "Denied" 65 | case .authorized: return "Authorized" 66 | } 67 | } 68 | } 69 | 70 | /** 71 | Result for a permission status request. 72 | */ 73 | public class PermissionResult: NSObject { 74 | public let type: PermissionType 75 | public let status: PermissionStatus 76 | 77 | internal init(type:PermissionType, status:PermissionStatus) { 78 | self.type = type 79 | self.status = status 80 | } 81 | 82 | override public var description: String { 83 | return "\(type) \(status)" 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /PermissionsService/Classes/Core/Structs.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Structs.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 7/24/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | List of permissions currently supported 13 | 14 | */ 15 | public enum PermissionType: Int, CustomStringConvertible { 16 | case contacts, locationAlways, locationInUse, notifications, microphone, camera, photos, reminders, events, bluetooth, motion, siri 17 | 18 | public var prettyDescription: String { 19 | switch self { 20 | case .locationAlways, .locationInUse: 21 | return "Location" 22 | default: 23 | return "\(self)" 24 | } 25 | } 26 | 27 | public var description: String { 28 | switch self { 29 | case .contacts: return "Contacts" // 30 | case .events: return "Events" // 31 | case .locationAlways: return "LocationAlways" 32 | case .locationInUse: return "LocationInUse" 33 | case .notifications: return "Notifications" 34 | case .microphone: return "Microphone" // 35 | case .camera: return "Camera" // 36 | case .photos: return "Photos" // 37 | case .reminders: return "Reminders" // 38 | case .bluetooth: return "Bluetooth" 39 | case .motion: return "Motion" 40 | case .siri: return "Siri" // 41 | 42 | } 43 | } 44 | 45 | static let allValues = [contacts, locationAlways, locationInUse, notifications, microphone, camera, photos, reminders, events, bluetooth, motion] 46 | } 47 | 48 | /** 49 | Possible statuses for a permission. 50 | 51 | */ 52 | public enum PermissionStatus: Int, CustomStringConvertible { 53 | case unknown = -1 54 | case notDetermined = 0 55 | case restricted = 1 56 | case denied = 2 57 | case authorized = 3 58 | 59 | public var description: String { 60 | switch self { 61 | case .unknown: return "Unknown" 62 | case .notDetermined: return "NotDetermined" 63 | case .restricted: return "Restricted" // System-level 64 | case .denied: return "Denied" 65 | case .authorized: return "Authorized" 66 | } 67 | } 68 | } 69 | 70 | /** 71 | Result for a permission status request. 72 | */ 73 | public class PermissionResult: NSObject { 74 | public let type: PermissionType 75 | public let status: PermissionStatus 76 | 77 | internal init(type:PermissionType, status:PermissionStatus) { 78 | self.type = type 79 | self.status = status 80 | } 81 | 82 | override public var description: String { 83 | return "\(type) \(status)" 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Source/Location/Location.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Location.swift 3 | // 4 | // Created by Orest Grabovskyi on 12/28/16. 5 | // Copyright © 2016 Lemberg Solution. All rights reserved. 6 | // 7 | 8 | #if PERMISSION_LOCATION 9 | 10 | import Foundation 11 | import CoreLocation 12 | 13 | 14 | /** 15 | Class Location working with locationManager and CLLocationManagerDelegate for returning complition block like all others permissions. Location Manager Delegate return to be nil after all for callback finished. 16 | */ 17 | public final class Location: NSObject, PermissionService { 18 | 19 | fileprivate var locationManager = CLLocationManager() 20 | fileprivate let dispatchGroup = DispatchGroup() 21 | 22 | fileprivate var _type: CLAuthorizationStatus = CLAuthorizationStatus.authorizedWhenInUse 23 | 24 | var type: CLAuthorizationStatus { 25 | return _type 26 | } 27 | 28 | public required init(with configuration: PermissionConfiguration) { 29 | 30 | guard let config = configuration as? LocationConfiguration else { 31 | print("#ERROR - 001 Not correct Configuration") 32 | return 33 | } 34 | 35 | if let type = CLAuthorizationStatus(rawValue: Int32(config.permissionType.rawValue)) { 36 | self._type = type 37 | } else { 38 | self._type = CLAuthorizationStatus.authorizedWhenInUse 39 | } 40 | 41 | } 42 | 43 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 44 | 45 | locationManager.delegate = self 46 | dispatchGroup.enter() 47 | 48 | if self.type == CLAuthorizationStatus.authorizedWhenInUse { 49 | locationManager.requestWhenInUseAuthorization() 50 | } else { 51 | locationManager.requestAlwaysAuthorization() 52 | } 53 | 54 | dispatchGroup.notify(queue: DispatchQueue.main) { 55 | 56 | var permissionGranted = false 57 | let status = CLLocationManager.authorizationStatus() 58 | self.locationManager.delegate = nil 59 | 60 | switch (status) { 61 | case .authorizedAlways, .authorizedWhenInUse: 62 | permissionGranted = true 63 | case .denied,.restricted,.notDetermined: 64 | permissionGranted = false 65 | } 66 | 67 | callback(permissionGranted) 68 | } 69 | 70 | } 71 | 72 | 73 | public func status() -> PermissionStatus { 74 | let status = Int(CLLocationManager.authorizationStatus().rawValue) 75 | return status.permissionStatus() 76 | } 77 | 78 | } 79 | 80 | extension Location: CLLocationManagerDelegate { 81 | 82 | public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { 83 | 84 | if status != .notDetermined { 85 | dispatchGroup.leave() 86 | } 87 | 88 | } 89 | } 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /Source/Core/PermissionService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SystemPermissionController.swift 3 | // 4 | // Created by Volodymyr Hyrka on 2/8/16. 5 | // Copyright © 2016 LembergSolutions. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | 10 | public protocol PermissionService { 11 | 12 | init(with configuration: PermissionConfiguration) 13 | func status() -> PermissionStatus 14 | func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) 15 | 16 | } 17 | 18 | public var closeTitle: String = "Close" 19 | public var settingsTitle: String = "Settings" 20 | 21 | open class Permission { 22 | 23 | public typealias PermissionGranted = (_ granted:Bool) -> Swift.Void 24 | 25 | public class func prepare(for handler: Permissible, with configuration: PermissionConfiguration = Configurator(for: T.self).configuration, callback: @escaping PermissionGranted) { 26 | 27 | let service = T(with: configuration) 28 | let status = service.status() 29 | 30 | switch status { 31 | case .notDetermined: 32 | service.requestPermission({ (success) in 33 | OperationQueue.main.addOperation { 34 | callback(success) 35 | } 36 | }) 37 | case .authorized: 38 | callback(true) 39 | case .restricted: 40 | showRestrictedAlert(from: handler, with: configuration.messages) 41 | callback(false) 42 | case .denied: 43 | showDeniedAlert(from: handler, with: configuration.messages) 44 | callback(false) 45 | default: fatalError() 46 | } 47 | } 48 | 49 | 50 | private class func showDeniedAlert(from sender:Permissible, with messages: ServiceMessages) { 51 | let alert = createAlert() 52 | alert.title = messages.deniedTitle 53 | alert.message = messages.deniedMessage 54 | alert.addAction(UIAlertController.openSettingsAction()) 55 | sender.showAlert(vc: alert) 56 | } 57 | 58 | private class func showRestrictedAlert(from sender:Permissible, with messages: ServiceMessages) { 59 | let alert = createAlert() 60 | alert.title = messages.restrictedTitle 61 | alert.message = messages.restrictedMessage 62 | sender.showAlert(vc: alert) 63 | } 64 | 65 | private class func createAlert() -> UIAlertController { 66 | let alert = UIAlertController(title: nil, message: nil, preferredStyle: .alert) 67 | let closeAction = UIAlertAction(title: closeTitle, style: .cancel, handler: nil) 68 | alert.addAction(closeAction) 69 | return alert 70 | } 71 | 72 | } 73 | 74 | private extension UIAlertController { 75 | 76 | class func openSettingsAction() -> UIAlertAction { 77 | 78 | let action = UIAlertAction(title: settingsTitle, style: .default) { (action) in 79 | let settingsUrl = URL(string: UIApplication.openSettingsURLString) 80 | if let url = settingsUrl, UIApplication.shared.canOpenURL(url) { 81 | if #available(iOS 10.0, *) { 82 | UIApplication.shared.open(url, completionHandler: nil) 83 | } else { 84 | UIApplication.shared.openURL(url) 85 | } 86 | } 87 | } 88 | return action 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /PermissionsService/Classes/PermissionService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SystemPermissionController.swift 3 | // 4 | // Created by Volodymyr Hyrka on 2/8/16. 5 | // Copyright © 2016 LembergSolutions. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | 10 | public protocol PermissionService { 11 | 12 | init(with configuration: PermissionConfiguration) 13 | func status() -> PermissionStatus 14 | func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) 15 | 16 | } 17 | 18 | public var closeTitle: String = "Close" 19 | public var settingsTitle: String = "Settings" 20 | 21 | open class Permission { 22 | 23 | public typealias PermissionGranted = (_ granted:Bool) -> Swift.Void 24 | 25 | public class func prepare(for handler: ServiceDisplay, with configuration: PermissionConfiguration = Configurator(for: T.self).configuration, callback: @escaping PermissionGranted) { 26 | 27 | let service = T(with: configuration) 28 | let status = service.status() 29 | 30 | //TODO: Error handling 31 | switch status { 32 | case .notDetermined: 33 | service.requestPermission({ (success) in 34 | OperationQueue.main.addOperation { 35 | callback(success) 36 | } 37 | }) 38 | break 39 | case .authorized: 40 | callback(true) 41 | break 42 | case .restricted: 43 | showRestrictedAlert(from: handler, with: configuration.messages) 44 | callback(false) 45 | break 46 | case .denied: 47 | showDeniedAlert(from: handler, with: configuration.messages) 48 | callback(false) 49 | break 50 | default: fatalError() 51 | } 52 | } 53 | 54 | 55 | private class func showDeniedAlert(from sender:ServiceDisplay, with messages: ServiceMessages) { 56 | let alert = createAlert() 57 | alert.title = messages.deniedTitle 58 | alert.message = messages.deniedMessage 59 | alert.addAction(UIAlertController.openSettingsAction()) 60 | sender.showAlert(vc: alert) 61 | } 62 | 63 | private class func showRestrictedAlert(from sender:ServiceDisplay, with messages: ServiceMessages) { 64 | let alert = createAlert() 65 | alert.title = messages.restrictedTitle 66 | alert.message = messages.restrictedMessage 67 | sender.showAlert(vc: alert) 68 | } 69 | 70 | private class func createAlert() -> UIAlertController { 71 | let alert = UIAlertController(title: nil, message: nil, preferredStyle: .alert) 72 | let closeAction = UIAlertAction(title: closeTitle, style: .cancel, handler: nil) 73 | alert.addAction(closeAction) 74 | return alert 75 | } 76 | 77 | } 78 | 79 | private extension UIAlertController { 80 | 81 | class func openSettingsAction() -> UIAlertAction { 82 | 83 | let action = UIAlertAction(title: settingsTitle, style: .default) { (action) in 84 | let settingsUrl = URL(string: UIApplicationOpenSettingsURLString) 85 | if let url = settingsUrl, UIApplication.shared.canOpenURL(url) { 86 | if #available(iOS 10.0, *) { 87 | UIApplication.shared.open(url, completionHandler: nil) 88 | } else { 89 | UIApplication.shared.openURL(url) 90 | } 91 | } 92 | } 93 | return action 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /PermissionsService/Classes/Core/PermissionService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SystemPermissionController.swift 3 | // 4 | // Created by Volodymyr Hyrka on 2/8/16. 5 | // Copyright © 2016 LembergSolutions. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | 10 | public protocol PermissionService { 11 | 12 | init(with configuration: PermissionConfiguration) 13 | func status() -> PermissionStatus 14 | func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) 15 | 16 | } 17 | 18 | public var closeTitle: String = "Close" 19 | public var settingsTitle: String = "Settings" 20 | 21 | open class Permission { 22 | 23 | public typealias PermissionGranted = (_ granted:Bool) -> Swift.Void 24 | 25 | public class func prepare(for handler: ServiceDisplay, with configuration: PermissionConfiguration = Configurator(for: T.self).configuration, callback: @escaping PermissionGranted) { 26 | 27 | let service = T(with: configuration) 28 | let status = service.status() 29 | 30 | //TODO: Error handling 31 | switch status { 32 | case .notDetermined: 33 | service.requestPermission({ (success) in 34 | OperationQueue.main.addOperation { 35 | callback(success) 36 | } 37 | }) 38 | break 39 | case .authorized: 40 | callback(true) 41 | break 42 | case .restricted: 43 | showRestrictedAlert(from: handler, with: configuration.messages) 44 | callback(false) 45 | break 46 | case .denied: 47 | showDeniedAlert(from: handler, with: configuration.messages) 48 | callback(false) 49 | break 50 | default: fatalError() 51 | } 52 | } 53 | 54 | 55 | private class func showDeniedAlert(from sender:ServiceDisplay, with messages: ServiceMessages) { 56 | let alert = createAlert() 57 | alert.title = messages.deniedTitle 58 | alert.message = messages.deniedMessage 59 | alert.addAction(UIAlertController.openSettingsAction()) 60 | sender.showAlert(vc: alert) 61 | } 62 | 63 | private class func showRestrictedAlert(from sender:ServiceDisplay, with messages: ServiceMessages) { 64 | let alert = createAlert() 65 | alert.title = messages.restrictedTitle 66 | alert.message = messages.restrictedMessage 67 | sender.showAlert(vc: alert) 68 | } 69 | 70 | private class func createAlert() -> UIAlertController { 71 | let alert = UIAlertController(title: nil, message: nil, preferredStyle: .alert) 72 | let closeAction = UIAlertAction(title: closeTitle, style: .cancel, handler: nil) 73 | alert.addAction(closeAction) 74 | return alert 75 | } 76 | 77 | } 78 | 79 | private extension UIAlertController { 80 | 81 | class func openSettingsAction() -> UIAlertAction { 82 | 83 | let action = UIAlertAction(title: settingsTitle, style: .default) { (action) in 84 | let settingsUrl = URL(string: UIApplicationOpenSettingsURLString) 85 | if let url = settingsUrl, UIApplication.shared.canOpenURL(url) { 86 | if #available(iOS 10.0, *) { 87 | UIApplication.shared.open(url, completionHandler: nil) 88 | } else { 89 | UIApplication.shared.openURL(url) 90 | } 91 | } 92 | } 93 | return action 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /PermissionsService/Classes/Location.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Location.swift 3 | // 4 | // Created by Orest Grabovskyi on 12/28/16. 5 | // Copyright © 2016 Lemberg Solution. All rights reserved. 6 | // 7 | 8 | #if PERMISSION_LOCATION 9 | 10 | import Foundation 11 | import CoreLocation 12 | 13 | 14 | /** 15 | Class Location working with locationManager and CLLocationManagerDelegate for returning complition block like all others permissions. Location Manager Delegate return to be nil after all for callback finished. 16 | */ 17 | public final class Location: NSObject, PermissionService { 18 | 19 | fileprivate var locationManager = CLLocationManager() 20 | fileprivate let dispatchGroup = DispatchGroup() 21 | 22 | fileprivate var type: CLAuthorizationStatus = CLAuthorizationStatus.authorizedWhenInUse 23 | 24 | public required init(with configuration: PermissionConfiguration) { 25 | //TODO: throw error 26 | 27 | guard let config = configuration as? LocationConfiguration else { 28 | print("#ERROR - 001 Not correct Configuration") 29 | return 30 | } 31 | 32 | if let type = CLAuthorizationStatus(rawValue: Int32(config.permissionType.rawValue)) { 33 | self.type = type 34 | } else { 35 | self.type = CLAuthorizationStatus.authorizedWhenInUse 36 | } 37 | 38 | } 39 | 40 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 41 | 42 | locationManager.delegate = self 43 | dispatchGroup.enter() 44 | 45 | if self.type == CLAuthorizationStatus.authorizedWhenInUse { 46 | locationManager.requestWhenInUseAuthorization() 47 | } else { 48 | locationManager.requestAlwaysAuthorization() 49 | } 50 | 51 | dispatchGroup.notify(queue: DispatchQueue.main) { 52 | 53 | var permissionGranted = false 54 | let status = CLLocationManager.authorizationStatus() 55 | self.locationManager.delegate = nil 56 | 57 | switch (status) { 58 | case .authorizedAlways, .authorizedWhenInUse: 59 | permissionGranted = true 60 | break 61 | case .denied,.restricted: 62 | permissionGranted = false 63 | break 64 | case .notDetermined: 65 | permissionGranted = false 66 | break 67 | } 68 | 69 | callback(permissionGranted) 70 | } 71 | 72 | } 73 | 74 | 75 | public func status() -> PermissionStatus { 76 | let statusInt = Int(CLLocationManager.authorizationStatus().rawValue) 77 | guard let status = PermissionStatus(rawValue: statusInt), (0...4) ~= statusInt else { 78 | assertionFailure("Impossible status") 79 | return .notDetermined 80 | } 81 | return status 82 | } 83 | 84 | 85 | } 86 | 87 | extension Location: CLLocationManagerDelegate { 88 | 89 | public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { 90 | 91 | if status != .notDetermined { 92 | dispatchGroup.leave() 93 | } 94 | 95 | } 96 | } 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /PermissionsService/Classes/Location/Location.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Location.swift 3 | // 4 | // Created by Orest Grabovskyi on 12/28/16. 5 | // Copyright © 2016 Lemberg Solution. All rights reserved. 6 | // 7 | 8 | #if PERMISSION_LOCATION 9 | 10 | import Foundation 11 | import CoreLocation 12 | 13 | 14 | /** 15 | Class Location working with locationManager and CLLocationManagerDelegate for returning complition block like all others permissions. Location Manager Delegate return to be nil after all for callback finished. 16 | */ 17 | public final class Location: NSObject, PermissionService { 18 | 19 | fileprivate var locationManager = CLLocationManager() 20 | fileprivate let dispatchGroup = DispatchGroup() 21 | 22 | fileprivate var type: CLAuthorizationStatus = CLAuthorizationStatus.authorizedWhenInUse 23 | 24 | public required init(with configuration: PermissionConfiguration) { 25 | //TODO: throw error 26 | 27 | guard let config = configuration as? LocationConfiguration else { 28 | print("#ERROR - 001 Not correct Configuration") 29 | return 30 | } 31 | 32 | if let type = CLAuthorizationStatus(rawValue: Int32(config.permissionType.rawValue)) { 33 | self.type = type 34 | } else { 35 | self.type = CLAuthorizationStatus.authorizedWhenInUse 36 | } 37 | 38 | } 39 | 40 | public func requestPermission(_ callback: @escaping (_ success: Bool) -> Void) { 41 | 42 | locationManager.delegate = self 43 | dispatchGroup.enter() 44 | 45 | if self.type == CLAuthorizationStatus.authorizedWhenInUse { 46 | locationManager.requestWhenInUseAuthorization() 47 | } else { 48 | locationManager.requestAlwaysAuthorization() 49 | } 50 | 51 | dispatchGroup.notify(queue: DispatchQueue.main) { 52 | 53 | var permissionGranted = false 54 | let status = CLLocationManager.authorizationStatus() 55 | self.locationManager.delegate = nil 56 | 57 | switch (status) { 58 | case .authorizedAlways, .authorizedWhenInUse: 59 | permissionGranted = true 60 | break 61 | case .denied,.restricted: 62 | permissionGranted = false 63 | break 64 | case .notDetermined: 65 | permissionGranted = false 66 | break 67 | } 68 | 69 | callback(permissionGranted) 70 | } 71 | 72 | } 73 | 74 | 75 | public func status() -> PermissionStatus { 76 | let statusInt = Int(CLLocationManager.authorizationStatus().rawValue) 77 | guard let status = PermissionStatus(rawValue: statusInt), (0...4) ~= statusInt else { 78 | assertionFailure("Impossible status") 79 | return .notDetermined 80 | } 81 | return status 82 | } 83 | 84 | 85 | } 86 | 87 | extension Location: CLLocationManagerDelegate { 88 | 89 | public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { 90 | 91 | if status != .notDetermined { 92 | dispatchGroup.leave() 93 | } 94 | 95 | } 96 | } 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /Example/Example/Sources/Controller/PermissionsController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PrmissionsController.swift 3 | // PermissionsService 4 | // 5 | // Created by Yuriy Trach on 10/11/16. 6 | // Copyright © 2016 CocoaPods. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import PermissionsService 11 | 12 | extension PermissionsController: Permissible {} 13 | 14 | struct CameraMessages: ServiceMessages { 15 | let deniedTitle = "Access denied" 16 | let deniedMessage = "You can enable access to camera in Privacy Settings" 17 | let restrictedTitle = "Access restricted" 18 | let restrictedMessage = "Access to camera is restricted" 19 | 20 | } 21 | 22 | 23 | class PermissionsController: UITableViewController { 24 | 25 | enum CellsIndexes: Int 26 | { 27 | case gallery = 0 28 | case calendar 29 | case camera 30 | case location 31 | case contacts 32 | case microphone 33 | case reminder 34 | case siri 35 | case speechRecognition 36 | case mediaLibrary 37 | } 38 | 39 | override func viewDidLoad() { 40 | super.viewDidLoad() 41 | 42 | } 43 | 44 | // MARK: - Table view data source 45 | 46 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 47 | tableView.deselectRow(at: indexPath, animated: true) 48 | guard let cellIndex = CellsIndexes(rawValue: indexPath.row) else { 49 | assertionFailure("guard in \(#file) on \(#line) line") 50 | return 51 | } 52 | 53 | var instanceName = "" 54 | 55 | let block = { [unowned self] (granted: Bool) in 56 | var title: String! 57 | var message: String! 58 | if granted { 59 | title = "Success" 60 | message = "Permision for \(instanceName) is granded" 61 | let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) 62 | alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil)) 63 | self.present(alert, animated: true, completion: nil) 64 | } 65 | } 66 | 67 | switch cellIndex { 68 | case .gallery: 69 | instanceName = "Gallery" 70 | Permission.prepare(for: self, callback: block) 71 | case .calendar: 72 | instanceName = "Events" 73 | Permission.prepare(for: self, callback: block) 74 | case .camera: 75 | instanceName = "Camera" 76 | let config = DefaultConfiguration(with: CameraMessages()) 77 | Permission.prepare(for: self, with: config, callback: block) 78 | case .location: 79 | instanceName = "Location" 80 | let config = LocationConfiguration(.always, with: CameraMessages()) 81 | Permission.prepare(for: self, with: config, callback: block) 82 | case .contacts: 83 | instanceName = "Contacts" 84 | Permission.prepare(for: self, callback: block) 85 | case .microphone: 86 | instanceName = "Microphone" 87 | Permission.prepare(for: self, callback: block) 88 | case .reminder: 89 | instanceName = "Reminder" 90 | Permission.prepare(for: self, callback: block) 91 | case .siri: 92 | instanceName = "Siri" 93 | Permission.prepare(for: self, callback: block) 94 | case .speechRecognition: 95 | instanceName = "Speech Recognition" 96 | Permission.prepare(for: self, callback: block) 97 | case .mediaLibrary: 98 | instanceName = "Media Library" 99 | Permission.prepare(for: self, callback: block) 100 | } 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /PermissionsService.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint PermissionsService.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | # Any lines starting with a # are optional, but their use is encouraged 6 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 7 | 8 | 9 | Pod::Spec.new do |s| 10 | s.name = "PermissionsService" 11 | s.version = "0.9.61" 12 | s.summary = "An easy way to do permissions requests & handling automatically" 13 | s.homepage = "https://github.com/lemberg/ios-permissions-service" 14 | s.license = { :type => 'BSD', :file => 'LICENSE' } 15 | s.author = { 'Lemberg Solutions Limited' => 'www.lemberg.co.uk' } 16 | s.source = { :git => 'https://github.com/lemberg/ios-permissions-service.git', :tag => s.version.to_s } 17 | s.social_media_url = "https://twitter.com/wearelemberg" 18 | s.requires_arc = true 19 | 20 | s.ios.deployment_target = '8.0' 21 | s.swift_version = '4.2' 22 | 23 | s.description = <<-DESC 24 | Using this code you can get permisions for Photos, Camera and other permisisons 25 | DESC 26 | 27 | s.default_subspec = 'Core' 28 | s.subspec 'Core' do |co| 29 | co.source_files = "Source/Core/*.{swift, h}" 30 | end 31 | 32 | s.subspec 'Location' do |lo| 33 | lo.dependency 'PermissionsService/Core' 34 | lo.source_files = 'Source/Location' 35 | lo.pod_target_xcconfig = { "SWIFT_ACTIVE_COMPILATION_CONDITIONS" => "PERMISSION_LOCATION" } 36 | 37 | end 38 | 39 | s.subspec 'Camera' do |ca| 40 | ca.dependency 'PermissionsService/Core' 41 | ca.source_files = 'Source/Camera' 42 | ca.pod_target_xcconfig = { "SWIFT_ACTIVE_COMPILATION_CONDITIONS" => "PERMISSION_CAMERA" } 43 | 44 | end 45 | 46 | s.subspec 'Contacts' do |co| 47 | co.dependency 'PermissionsService/Core' 48 | co.source_files = 'Source/Contacts' 49 | co.pod_target_xcconfig = { "SWIFT_ACTIVE_COMPILATION_CONDITIONS" => "PERMISSION_CONTACTS" } 50 | 51 | end 52 | 53 | s.subspec 'Events' do |ev| 54 | ev.dependency 'PermissionsService/Core' 55 | ev.source_files = 'Source/Events' 56 | ev.pod_target_xcconfig = { "SWIFT_ACTIVE_COMPILATION_CONDITIONS" => "PERMISSION_EVENTS" } 57 | 58 | end 59 | 60 | s.subspec 'MediaLibrary' do |ml| 61 | ml.dependency 'PermissionsService/Core' 62 | ml.source_files = 'Source/MediaLibrary' 63 | ml.pod_target_xcconfig = { "SWIFT_ACTIVE_COMPILATION_CONDITIONS" => "PERMISSION_MEDIA_LIBRARY" } 64 | end 65 | 66 | s.subspec 'Gallery' do |ga| 67 | ga.dependency 'PermissionsService/Core' 68 | ga.source_files = 'Source/Gallery' 69 | ga.pod_target_xcconfig = { "SWIFT_ACTIVE_COMPILATION_CONDITIONS" => "PERMISSION_GALLERY" } 70 | 71 | end 72 | 73 | s.subspec 'Microphone' do |mi| 74 | mi.dependency 'PermissionsService/Core' 75 | mi.source_files = 'Source/Microphone' 76 | mi.pod_target_xcconfig = { "SWIFT_ACTIVE_COMPILATION_CONDITIONS" => "PERMISSION_MICROPHONE" } 77 | 78 | end 79 | 80 | s.subspec 'Reminder' do |ra| 81 | ra.dependency 'PermissionsService/Core' 82 | ra.source_files = 'Source/Reminder' 83 | ra.pod_target_xcconfig = { "SWIFT_ACTIVE_COMPILATION_CONDITIONS" => "PERMISSION_REMINDER" } 84 | 85 | end 86 | 87 | s.subspec 'Siri' do |si| 88 | si.dependency 'PermissionsService/Core' 89 | si.source_files = 'Source/Siri' 90 | si.pod_target_xcconfig = { "SWIFT_ACTIVE_COMPILATION_CONDITIONS" => "PERMISSION_SIRI" } 91 | 92 | end 93 | 94 | s.subspec 'SpeechRecognition' do |sp| 95 | sp.dependency 'PermissionsService/Core' 96 | sp.source_files = 'Source/SpeechRecognition' 97 | sp.pod_target_xcconfig = { "SWIFT_ACTIVE_COMPILATION_CONDITIONS" => "PERMISSION_SPEECH_RECOGNITION" } 98 | 99 | end 100 | 101 | 102 | end 103 | -------------------------------------------------------------------------------- /Example/Pods/Local Podspecs/PermissionsService.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PermissionsService", 3 | "version": "0.9.61", 4 | "summary": "An easy way to do permissions requests & handling automatically", 5 | "homepage": "https://github.com/lemberg/ios-permissions-service", 6 | "license": { 7 | "type": "BSD", 8 | "file": "LICENSE" 9 | }, 10 | "authors": { 11 | "Lemberg Solutions Limited": "www.lemberg.co.uk" 12 | }, 13 | "source": { 14 | "git": "https://github.com/lemberg/ios-permissions-service.git", 15 | "tag": "0.9.61" 16 | }, 17 | "social_media_url": "https://twitter.com/wearelemberg", 18 | "requires_arc": true, 19 | "platforms": { 20 | "ios": "8.0" 21 | }, 22 | "swift_version": "4.2", 23 | "description": "Using this code you can get permisions for Photos, Camera and other permisisons", 24 | "default_subspecs": "Core", 25 | "subspecs": [ 26 | { 27 | "name": "Core", 28 | "source_files": "Source/Core/*.{swift, h}" 29 | }, 30 | { 31 | "name": "Location", 32 | "dependencies": { 33 | "PermissionsService/Core": [ 34 | 35 | ] 36 | }, 37 | "source_files": "Source/Location", 38 | "pod_target_xcconfig": { 39 | "SWIFT_ACTIVE_COMPILATION_CONDITIONS": "PERMISSION_LOCATION" 40 | } 41 | }, 42 | { 43 | "name": "Camera", 44 | "dependencies": { 45 | "PermissionsService/Core": [ 46 | 47 | ] 48 | }, 49 | "source_files": "Source/Camera", 50 | "pod_target_xcconfig": { 51 | "SWIFT_ACTIVE_COMPILATION_CONDITIONS": "PERMISSION_CAMERA" 52 | } 53 | }, 54 | { 55 | "name": "Contacts", 56 | "dependencies": { 57 | "PermissionsService/Core": [ 58 | 59 | ] 60 | }, 61 | "source_files": "Source/Contacts", 62 | "pod_target_xcconfig": { 63 | "SWIFT_ACTIVE_COMPILATION_CONDITIONS": "PERMISSION_CONTACTS" 64 | } 65 | }, 66 | { 67 | "name": "Events", 68 | "dependencies": { 69 | "PermissionsService/Core": [ 70 | 71 | ] 72 | }, 73 | "source_files": "Source/Events", 74 | "pod_target_xcconfig": { 75 | "SWIFT_ACTIVE_COMPILATION_CONDITIONS": "PERMISSION_EVENTS" 76 | } 77 | }, 78 | { 79 | "name": "MediaLibrary", 80 | "dependencies": { 81 | "PermissionsService/Core": [ 82 | 83 | ] 84 | }, 85 | "source_files": "Source/MediaLibrary", 86 | "pod_target_xcconfig": { 87 | "SWIFT_ACTIVE_COMPILATION_CONDITIONS": "PERMISSION_MEDIA_LIBRARY" 88 | } 89 | }, 90 | { 91 | "name": "Gallery", 92 | "dependencies": { 93 | "PermissionsService/Core": [ 94 | 95 | ] 96 | }, 97 | "source_files": "Source/Gallery", 98 | "pod_target_xcconfig": { 99 | "SWIFT_ACTIVE_COMPILATION_CONDITIONS": "PERMISSION_GALLERY" 100 | } 101 | }, 102 | { 103 | "name": "Microphone", 104 | "dependencies": { 105 | "PermissionsService/Core": [ 106 | 107 | ] 108 | }, 109 | "source_files": "Source/Microphone", 110 | "pod_target_xcconfig": { 111 | "SWIFT_ACTIVE_COMPILATION_CONDITIONS": "PERMISSION_MICROPHONE" 112 | } 113 | }, 114 | { 115 | "name": "Reminder", 116 | "dependencies": { 117 | "PermissionsService/Core": [ 118 | 119 | ] 120 | }, 121 | "source_files": "Source/Reminder", 122 | "pod_target_xcconfig": { 123 | "SWIFT_ACTIVE_COMPILATION_CONDITIONS": "PERMISSION_REMINDER" 124 | } 125 | }, 126 | { 127 | "name": "Siri", 128 | "dependencies": { 129 | "PermissionsService/Core": [ 130 | 131 | ] 132 | }, 133 | "source_files": "Source/Siri", 134 | "pod_target_xcconfig": { 135 | "SWIFT_ACTIVE_COMPILATION_CONDITIONS": "PERMISSION_SIRI" 136 | } 137 | }, 138 | { 139 | "name": "SpeechRecognition", 140 | "dependencies": { 141 | "PermissionsService/Core": [ 142 | 143 | ] 144 | }, 145 | "source_files": "Source/SpeechRecognition", 146 | "pod_target_xcconfig": { 147 | "SWIFT_ACTIVE_COMPILATION_CONDITIONS": "PERMISSION_SPEECH_RECOGNITION" 148 | } 149 | } 150 | ] 151 | } 152 | -------------------------------------------------------------------------------- /Example/Pods/PermissionsServiceTests/LocationConfigurationTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LocationConfigurationTests.swift 3 | // Pods 4 | // 5 | // Created by Hellen Soloviy on 8/28/17. 6 | // 7 | // 8 | 9 | import XCTest 10 | import CoreLocation 11 | @testable import PermissionsService 12 | 13 | class LocationConfigurationTests: XCTestCase { 14 | 15 | var object: LocationConfiguration! 16 | var permissionTypeObject: LocationConfiguration.LocationPermissionType! 17 | let defaultPermissionType: LocationConfiguration.LocationPermissionType = .whenInUse 18 | fileprivate let defaultMessages = DefaultMessages() 19 | fileprivate let customMessages = CustomMessages() 20 | 21 | 22 | fileprivate struct CustomMessages: ServiceMessages { 23 | let deniedTitle = "Custom Access denied" 24 | let deniedMessage = "Custom You can enable access to camera in Privacy Settings" 25 | let restrictedTitle = "Custom Access restricted" 26 | let restrictedMessage = "Custom Access to camera is restricted" 27 | } 28 | 29 | override func setUp() { 30 | super.setUp() 31 | // Put setup code here. This method is called before the invocation of each test method in the class. 32 | } 33 | 34 | override func tearDown() { 35 | // Put teardown code here. This method is called after the invocation of each test method in the class. 36 | super.tearDown() 37 | } 38 | 39 | //MARK: Init Test Cases 40 | func testLocationConfigurationInit_default() { 41 | object = LocationConfiguration() 42 | XCTAssertNotNil(object) 43 | 44 | XCTAssertEqual(object.permissionType, defaultPermissionType) 45 | XCTAssertTrue(object.messages.isEqual(to: defaultMessages)) 46 | } 47 | 48 | func testLocationConfigurationInit_alwaysTypeWithDefaultMessages() { 49 | object = LocationConfiguration(.always) 50 | XCTAssertNotNil(object) 51 | 52 | XCTAssertEqual(object.permissionType, .always) 53 | XCTAssertTrue(object.messages.isEqual(to: defaultMessages)) 54 | 55 | } 56 | 57 | func testLocationConfigurationInit_whenInUseTypeWithDefaultMessages() { 58 | object = LocationConfiguration(.whenInUse) 59 | XCTAssertNotNil(object) 60 | 61 | XCTAssertEqual(object.permissionType, defaultPermissionType) 62 | XCTAssertTrue(object.messages.isEqual(to: defaultMessages)) 63 | 64 | } 65 | 66 | func testLocationConfigurationInit_defaultTypeWithCustomMessages() { 67 | object = LocationConfiguration(with: customMessages) 68 | XCTAssertNotNil(object) 69 | 70 | XCTAssertEqual(object.permissionType, defaultPermissionType) 71 | XCTAssertTrue(object.messages.isEqual(to: customMessages)) 72 | XCTAssertFalse(object.messages.isEqual(to: defaultMessages)) 73 | 74 | } 75 | 76 | func testLocationConfigurationInit_alwaysTypeWithCustomMessages() { 77 | object = LocationConfiguration(.always, with: customMessages) 78 | XCTAssertNotNil(object) 79 | 80 | XCTAssertEqual(object.permissionType, .always) 81 | XCTAssertTrue(object.messages.isEqual(to: customMessages)) 82 | XCTAssertFalse(object.messages.isEqual(to: defaultMessages)) 83 | 84 | } 85 | 86 | func testLocationConfigurationInit_whenInUseTypeWithCustomMessages() { 87 | object = LocationConfiguration(.whenInUse, with: customMessages) 88 | XCTAssertNotNil(object) 89 | 90 | XCTAssertEqual(object.permissionType, defaultPermissionType) 91 | XCTAssertTrue(object.messages.isEqual(to: customMessages)) 92 | XCTAssertFalse(object.messages.isEqual(to: defaultMessages)) 93 | 94 | } 95 | 96 | //MARK: LocationPermissionType Test Cases 97 | func testLocationPermissionTypeInit_uncorrectRawValue() { 98 | permissionTypeObject = LocationConfiguration.LocationPermissionType.init(rawValue: 1) 99 | XCTAssertNil(permissionTypeObject) 100 | 101 | } 102 | 103 | func testLocationPermissionTypeInit_correctRawValueAlways() { 104 | permissionTypeObject = LocationConfiguration.LocationPermissionType.init(rawValue: 3) 105 | XCTAssertNotNil(permissionTypeObject) 106 | XCTAssertEqual(permissionTypeObject, .always) 107 | 108 | } 109 | 110 | func testLocationPermissionTypeInit_uncorrectRawValueWhenInUse() { 111 | permissionTypeObject = LocationConfiguration.LocationPermissionType.init(rawValue: 4) 112 | XCTAssertNotNil(permissionTypeObject) 113 | XCTAssertEqual(permissionTypeObject, defaultPermissionType) 114 | 115 | } 116 | 117 | func testPerformanceExample() { 118 | // This is an example of a performance test case. 119 | self.measure { 120 | // Put the code you want to measure the time of here. 121 | } 122 | } 123 | 124 | } 125 | 126 | -------------------------------------------------------------------------------- /Example/PermissionsService.xcodeproj/xcshareddata/xcschemes/PermissionsService-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 80 | 86 | 87 | 88 | 89 | 90 | 91 | 97 | 99 | 105 | 106 | 107 | 108 | 110 | 111 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Example/Pods-Example-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then 7 | # If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy 8 | # resources to, so exit 0 (signalling the script phase was successful). 9 | exit 0 10 | fi 11 | 12 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 13 | 14 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 15 | > "$RESOURCES_TO_COPY" 16 | 17 | XCASSET_FILES=() 18 | 19 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 20 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 21 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 22 | 23 | case "${TARGETED_DEVICE_FAMILY:-}" in 24 | 1,2) 25 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 26 | ;; 27 | 1) 28 | TARGET_DEVICE_ARGS="--target-device iphone" 29 | ;; 30 | 2) 31 | TARGET_DEVICE_ARGS="--target-device ipad" 32 | ;; 33 | 3) 34 | TARGET_DEVICE_ARGS="--target-device tv" 35 | ;; 36 | 4) 37 | TARGET_DEVICE_ARGS="--target-device watch" 38 | ;; 39 | *) 40 | TARGET_DEVICE_ARGS="--target-device mac" 41 | ;; 42 | esac 43 | 44 | install_resource() 45 | { 46 | if [[ "$1" = /* ]] ; then 47 | RESOURCE_PATH="$1" 48 | else 49 | RESOURCE_PATH="${PODS_ROOT}/$1" 50 | fi 51 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 52 | cat << EOM 53 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 54 | EOM 55 | exit 1 56 | fi 57 | case $RESOURCE_PATH in 58 | *.storyboard) 59 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 60 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 61 | ;; 62 | *.xib) 63 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 64 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 65 | ;; 66 | *.framework) 67 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 68 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 69 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 70 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 71 | ;; 72 | *.xcdatamodel) 73 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true 74 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 75 | ;; 76 | *.xcdatamodeld) 77 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true 78 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 79 | ;; 80 | *.xcmappingmodel) 81 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true 82 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 83 | ;; 84 | *.xcassets) 85 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 86 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 87 | ;; 88 | *) 89 | echo "$RESOURCE_PATH" || true 90 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 91 | ;; 92 | esac 93 | } 94 | 95 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 96 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 97 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 98 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 99 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 100 | fi 101 | rm -f "$RESOURCES_TO_COPY" 102 | 103 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ] 104 | then 105 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 106 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 107 | while read line; do 108 | if [[ $line != "${PODS_ROOT}*" ]]; then 109 | XCASSET_FILES+=("$line") 110 | fi 111 | done <<<"$OTHER_XCASSETS" 112 | 113 | if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then 114 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 115 | else 116 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist" 117 | fi 118 | fi 119 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Example/Pods-Example-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | function on_error { 7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" 8 | } 9 | trap 'on_error $LINENO' ERR 10 | 11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then 12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy 13 | # frameworks to, so exit 0 (signalling the script phase was successful). 14 | exit 0 15 | fi 16 | 17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 19 | 20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" 21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 22 | 23 | # Used as a return value for each invocation of `strip_invalid_archs` function. 24 | STRIP_BINARY_RETVAL=0 25 | 26 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 27 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 28 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 29 | 30 | # Copies and strips a vendored framework 31 | install_framework() 32 | { 33 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 34 | local source="${BUILT_PRODUCTS_DIR}/$1" 35 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 36 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 37 | elif [ -r "$1" ]; then 38 | local source="$1" 39 | fi 40 | 41 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 42 | 43 | if [ -L "${source}" ]; then 44 | echo "Symlinked..." 45 | source="$(readlink "${source}")" 46 | fi 47 | 48 | # Use filter instead of exclude so missing patterns don't throw errors. 49 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 50 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 51 | 52 | local basename 53 | basename="$(basename -s .framework "$1")" 54 | binary="${destination}/${basename}.framework/${basename}" 55 | 56 | if ! [ -r "$binary" ]; then 57 | binary="${destination}/${basename}" 58 | elif [ -L "${binary}" ]; then 59 | echo "Destination binary is symlinked..." 60 | dirname="$(dirname "${binary}")" 61 | binary="${dirname}/$(readlink "${binary}")" 62 | fi 63 | 64 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 65 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 66 | strip_invalid_archs "$binary" 67 | fi 68 | 69 | # Resign the code if required by the build settings to avoid unstable apps 70 | code_sign_if_enabled "${destination}/$(basename "$1")" 71 | 72 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 73 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 74 | local swift_runtime_libs 75 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) 76 | for lib in $swift_runtime_libs; do 77 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 78 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 79 | code_sign_if_enabled "${destination}/${lib}" 80 | done 81 | fi 82 | } 83 | 84 | # Copies and strips a vendored dSYM 85 | install_dsym() { 86 | local source="$1" 87 | if [ -r "$source" ]; then 88 | # Copy the dSYM into a the targets temp dir. 89 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" 90 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" 91 | 92 | local basename 93 | basename="$(basename -s .framework.dSYM "$source")" 94 | binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}" 95 | 96 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 97 | if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then 98 | strip_invalid_archs "$binary" 99 | fi 100 | 101 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then 102 | # Move the stripped file into its final destination. 103 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" 104 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}" 105 | else 106 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. 107 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM" 108 | fi 109 | fi 110 | } 111 | 112 | # Signs a framework with the provided identity 113 | code_sign_if_enabled() { 114 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 115 | # Use the current code_sign_identity 116 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 117 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" 118 | 119 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 120 | code_sign_cmd="$code_sign_cmd &" 121 | fi 122 | echo "$code_sign_cmd" 123 | eval "$code_sign_cmd" 124 | fi 125 | } 126 | 127 | # Strip invalid architectures 128 | strip_invalid_archs() { 129 | binary="$1" 130 | # Get architectures for current target binary 131 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" 132 | # Intersect them with the architectures we are building for 133 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" 134 | # If there are no archs supported by this binary then warn the user 135 | if [[ -z "$intersected_archs" ]]; then 136 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." 137 | STRIP_BINARY_RETVAL=0 138 | return 139 | fi 140 | stripped="" 141 | for arch in $binary_archs; do 142 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 143 | # Strip non-valid architectures in-place 144 | lipo -remove "$arch" -output "$binary" "$binary" 145 | stripped="$stripped $arch" 146 | fi 147 | done 148 | if [[ "$stripped" ]]; then 149 | echo "Stripped $binary of architectures:$stripped" 150 | fi 151 | STRIP_BINARY_RETVAL=1 152 | } 153 | 154 | 155 | if [[ "$CONFIGURATION" == "Debug" ]]; then 156 | install_framework "${BUILT_PRODUCTS_DIR}/PermissionsService/PermissionsService.framework" 157 | fi 158 | if [[ "$CONFIGURATION" == "Release" ]]; then 159 | install_framework "${BUILT_PRODUCTS_DIR}/PermissionsService/PermissionsService.framework" 160 | fi 161 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 162 | wait 163 | fi 164 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 |

5 | 6 | [![License](https://img.shields.io/cocoapods/l/PermissionsService.svg?style=flat)](http://cocoapods.org/pods/PermissionsService) 7 | [![Version](https://img.shields.io/badge/pod-v0.3.0-blue.svg?style=flat)](http://cocoapods.org/pods/PermissionsService) 8 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 9 | [![Swift Version](https://img.shields.io/badge/Swift-3.1%2B-orange.svg?style=flat)](http://cocoapods.org/pods/PermissionsService) 10 | [![iOS Platform](https://img.shields.io/badge/iOS-8.0%2B-blue.svg?style=flat)](http://cocoapods.org/pods/PermissionsService) 11 | [![By](https://img.shields.io/badge/By-Lemberg%20Solutions%20Limited-blue.svg?style=flat)](http://cocoapods.org/pods/PermissionsService) 12 | 13 | An easy way to do permissions requests & handling automatically. 14 | 15 | 1. [Why do you need it?](https://github.com/lemberg/ios-permissions-service#why-you-need-it) 16 | 1. [Features](https://github.com/lemberg/ios-permissions-service#features) 17 | 1. [Supported Permission Types](https://github.com/lemberg/ios-permissions-service#supported-permission-types) 18 | 1. [Installation](https://github.com/lemberg/ios-permissions-service#installation) 19 | 1. [CocoaPods](https://github.com/lemberg/ios-permissions-service#cocoapods) 20 | 1. [Carthage](https://github.com/lemberg/ios-permissions-service#carthage) 21 | 1. [How To Use](https://github.com/lemberg/ios-permissions-service#how-to-use) 22 | 1. [Configurations](https://github.com/lemberg/ios-permissions-service#configurations) 23 | 1. [Custom alert messages](https://github.com/lemberg/ios-permissions-service#configurate-messages) 24 | 1. [Location permission](https://github.com/lemberg/ios-permissions-service#location-permission-types) 25 | 1. [Requirements](https://github.com/lemberg/ios-permissions-service#requirements) 26 | 1. [Author](https://github.com/lemberg/ios-permissions-service#author) 27 | 1. [License](https://github.com/lemberg/ios-permissions-service#license) 28 | 29 | ## Why do you need it? 30 | 31 | This library is an easy way to handle `notDetermined`, `authorised`, `restricted` and `denied` cases without doing it by yourself. No more need to do error handling for `restricted` and `denied` cases, create and present to user specific alerts. 32 | Of cause, it is not a silver bullet, but a good tool for your project! 33 | 34 | ## Features 35 | 36 | - [x] Customise or localise alerts messages via `Configuration` 37 | - [x] Automatic alert creating and presenting 38 | - [x] Opportunity for users to easily change permissions in Settings 39 | - [x] CoreLocation permission returns you completion block with user's decision 40 | - [x] Example project for easy understanding of framework 41 | 42 | ## Supported Permission Types 43 | 44 | * `Camera` 45 | * `Contacts` 46 | * `Events` 47 | * `Gallery` 48 | * `Location` 49 | * `MediaLibrary` 50 | * `Microphone` 51 | * `Reminder` 52 | * `Siri` 53 | * `SpeechRecognition` 54 | 55 | ## Installation with CocoaPods 56 | 57 | ios-permissions-service is available through [CocoaPods](http://cocoapods.org) and [Carthage](https://github.com/Carthage/Carthage) 58 | 59 | ### CocoaPods 60 | 61 | To install it, simply add one or several lines to your Podfile like this: 62 | 63 | ```swift 64 | pod "PermissionsService/Location" 65 | pod "PermissionsService/Camera" 66 | ``` 67 | 68 | Full list of available permissions you can found [here](https://github.com/lemberg/ios-permissions-service#supported-permission-types). 69 | 70 | > If you'll need, there is still a versions written on **Swift 3/4** which you can find in separate branches 71 | 72 | Now you need to run `pod update` command from you project folder and that's it! 73 | 74 | ### Carthage 75 | 76 | 1. Add the following line to your Cartfile: 77 | 78 | ```swift 79 | github "lemberg/ios-permissions-service" 80 | ``` 81 | 82 | If you want to use a specific branch with another Swift version you can add branch name: 83 | 84 | ```swift 85 | github "lemberg/ios-permissions-service" "swift4" 86 | ``` 87 | 88 | 2. Run `carthage update --platform iOS` command from you project folder. 89 | 90 | 3. Find the *Carthage/Build* folder, which is in your project folder. Drag and drop `PermissionsService.framework` file, to the *Linked Frameworks and Libraries* section in *General* settings tab of your project. 91 | 92 | 4. Do to *Build Phases* settings tab. Click the “+” icon and choose *New Run Script Phase* if not exist. Add the following line to your script 93 | 94 | ```swift 95 | /usr/local/bin/carthage copy-frameworks 96 | ``` 97 | 98 | 5. Add the framework's paths under *Input Files*: 99 | 100 | ```swift 101 | $(SRCROOT)/Carthage/Build/iOS/PermissionsService.framework 102 | ``` 103 | 104 | 6. Add the framework's paths to the *Output Files*: 105 | 106 | ```swift 107 | $(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/PermissionsService.framework 108 | ``` 109 | 110 | > More info about using and configuring Carthage you can find [here](https://github.com/Carthage/Carthage#getting-started). 111 | 112 | #### Note! 113 | 114 | There is an important note about installing, because of Apple's policy. Due to this policy regarding permission access, binaries may be rejected due to a perceived attempt to access privacy-sensitive data without a usage key, and then further rejected for not actually requesting permissions. This error will be when you'll try uploading to itunesconnect. 115 | 116 | But there is a **solutuion**. You need to provide custom build flags *before building the dynamic framework* to only compile with permissions you request. 117 | 118 | 1. Go to your project root directory and add `xcconfig` file named `PermissionConfiguration.xcconfig`. 119 | [Example of such file you can find here.](https://github.com/lemberg/ios-permissions-service/blob/master/Example/Pods/PermissionConfiguration.xcconfig) 120 | 121 | 2. Comment lines which you don't want to use like this: 122 | 123 | ```swift 124 | 125 | PERMISSION_CAMERA = PERMISSION_CAMERA 126 | PERMISSION_CONTACTS = // PERMISSION_CONTACTS 127 | 128 | ``` 129 | 130 | Here you can see an example of using only `Camera` permission. `Contacts` permission will be unavailable. 131 | 132 | 3. Now you can run `carthage update --platform iOS` to compile framework. 133 | 134 | > If you'll need to change available permissions, go to `PermissionConfiguration.xcconfig` file and modify it. Then update the framework again. 135 | 136 | 137 | ## How To Use 138 | 139 | 1. Configure your project in all ways needed for chosen permission type. For example, in a case of a gallery, add a specific key to your .plist file. 140 | 141 | 2. Implement `Permissible` protocol in your class. If it's not a `UIVIewController` class you should implement `showAlert(_:)` method, but if it is - there is a default implementation and you can leave it empty. 142 | 143 | 3. Add `Permission` object with a type you needed and use `prepare(_:) ` method for request permission and presenting alert to the user. 144 | 145 | ```swift 146 | 147 | Permission.prepare(for: self, callback: { (granted) in 148 | if granted { 149 | //present library 150 | } else { 151 | //perform specific functions 152 | } 153 | }) 154 | 155 | ``` 156 | 157 | This case if show a simple variant of use with default permission settings. 158 | 159 | > Be aware that **Calendar** permission service named **Events**. 160 | 161 | 4. Enjoy! 162 | 163 | ## Configurations 164 | 165 | This library gives you an opportunity to do some customising or configurations if you need it. 166 | 167 | ### Configurate messages 168 | 169 | You can add custom alerts messages for `denied` and `restricted` cases by creating new `struct` which conform to `ServiceMessages` protocol. 170 | 171 | ```swift 172 | 173 | struct CameraMessages: ServiceMessages { 174 | 175 | let deniedTitle = "Access denied" 176 | let deniedMessage = "You can enable access to camera in Privacy Settings" 177 | let restrictedTitle = "Access restricted" 178 | let restrictedMessage = "Access to camera is restricted" 179 | 180 | } 181 | ``` 182 | 183 | To use your custom messages you need to use `DefaultConfiguration` class. Let's init it! 184 | 185 | ```swift 186 | let config = DefaultConfiguration(with: CameraMessages()) 187 | ``` 188 | 189 | And now put it in `prepare(_:) ` method, like this: 190 | 191 | ```swift 192 | Permission.prepare(for: self, with: config) { (granted) in 193 | if granted { 194 | print("Granted") 195 | } else { 196 | print("Error") 197 | } 198 | 199 | } 200 | 201 | ``` 202 | 203 | ### Location permission types 204 | 205 | As you can know, you can request two types of user location permission: `WhenInUse` and `Always`. 206 | For choosing it you need to use configurations too. Class `LocationConfiguration` is a subclass of `DefaultConfiguration` and have the same way to use. 207 | 208 | You can init it only with type 209 | 210 | ```swift 211 | let config = LocationConfiguration(.always) 212 | ``` 213 | 214 | Or you can use it with your messages 215 | 216 | ```swift 217 | let config = LocationConfiguration(.always, with: CustomLocationMessages()) 218 | ``` 219 | 220 | And then simply put it in your `prepare(_:) ` method as you already did with `DefaultConfiguration`. 221 | 222 | ```swift 223 | Permission.prepare(for: self, with: config) { (granted) in 224 | if granted { 225 | print("Granted") 226 | } else { 227 | print("Error") 228 | } 229 | 230 | } 231 | 232 | ``` 233 | 234 | > If you still have some questions or issues (maybe even improvements!) feel free to open new issue or PR. 235 | 236 | 237 | ## Requirements 238 | 239 | - [![Swift Version](https://img.shields.io/badge/Swift-3.1%2B-orange.svg?style=flat)](http://cocoapods.org/pods/PermissionsService) 240 | - [![iOS Platform](https://img.shields.io/badge/iOS-8.0%2B-blue.svg?style=flat)](http://cocoapods.org/pods/PermissionsService) 241 | - [![Xcode Version](https://img.shields.io/badge/Xcode-8.1%2B-blue.svg?style=flat)](http://cocoapods.org/pods/PermissionsService) 242 | 243 | ## Author 244 | 245 | ### [Lemberg Solutions](http://lemberg.co.uk) 246 | 247 | [![iOS Platform](http://lemberg.co.uk/sites/all/themes/lemberg/images/logo.png)](https://github.com/lemberg) 248 | 249 | ## License 250 | 251 | ios-permissions-service is available under the [BSD license](https://directory.fsf.org/wiki/License:BSD_4Clause). See the LICENSE file for more info. 252 | -------------------------------------------------------------------------------- /Example/Example/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | -------------------------------------------------------------------------------- /Example/PermissionsService.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4F8521A22C836E3345E2DF2D /* Pods_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9F446DF0721F3104C2FFC11 /* Pods_Example.framework */; }; 11 | DBBDE1B41DACEB3F00E4151F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DBBDE1B21DACEB3F00E4151F /* Main.storyboard */; }; 12 | DBBDE1B91DACEB3F00E4151F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DBBDE1B71DACEB3F00E4151F /* LaunchScreen.storyboard */; }; 13 | DBBDE1C11DACEC2000E4151F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DBBDE1BF1DACEC2000E4151F /* Assets.xcassets */; }; 14 | DBBDE1CF1DACF46E00E4151F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DBBDE1CD1DACF46E00E4151F /* AppDelegate.m */; }; 15 | DBBDE1D01DACF46E00E4151F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DBBDE1CE1DACF46E00E4151F /* main.m */; }; 16 | DBBDE1D31DACF50C00E4151F /* PermissionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBDE1D21DACF50C00E4151F /* PermissionsController.swift */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXFileReference section */ 20 | 115DFF34E5A239BE4C0940D4 /* Pods-PermissionsService_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PermissionsService_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PermissionsService_Tests/Pods-PermissionsService_Tests.debug.xcconfig"; sourceTree = ""; }; 21 | 7ADD5F211D4FBE2FE6881EFF /* PermissionsService.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = PermissionsService.podspec; path = ../PermissionsService.podspec; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 22 | 9B01A92F1F2884690056279D /* Example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Example.entitlements; sourceTree = ""; }; 23 | BA644CC018C9CCC2FA10C489 /* Pods-PermissionsService_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PermissionsService_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-PermissionsService_Tests/Pods-PermissionsService_Tests.release.xcconfig"; sourceTree = ""; }; 24 | C9F446DF0721F3104C2FFC11 /* Pods_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 25 | D1E7F4FA7E8AFE8CA9CBD36C /* Pods-Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.debug.xcconfig"; sourceTree = ""; }; 26 | D59FADF8389DD5C55FB59402 /* Pods_PermissionsService_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PermissionsService_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | DBBDE1A71DACEB3F00E4151F /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | DBBDE1B31DACEB3F00E4151F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 29 | DBBDE1B81DACEB3F00E4151F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 30 | DBBDE1BF1DACEC2000E4151F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Resourses/Assets.xcassets; sourceTree = ""; }; 31 | DBBDE1C01DACEC2000E4151F /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Resourses/Info.plist; sourceTree = ""; }; 32 | DBBDE1CC1DACF46E00E4151F /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 33 | DBBDE1CD1DACF46E00E4151F /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 34 | DBBDE1CE1DACF46E00E4151F /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 35 | DBBDE1D21DACF50C00E4151F /* PermissionsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PermissionsController.swift; sourceTree = ""; }; 36 | DBCE10161D26AE1800F97B8E /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 37 | E2020FAF9E463C2A412E99DA /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; 38 | ED0308B2A9D83383EBEE8B2A /* Pods-Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.release.xcconfig"; sourceTree = ""; }; 39 | /* End PBXFileReference section */ 40 | 41 | /* Begin PBXFrameworksBuildPhase section */ 42 | DBBDE1A41DACEB3F00E4151F /* Frameworks */ = { 43 | isa = PBXFrameworksBuildPhase; 44 | buildActionMask = 2147483647; 45 | files = ( 46 | 4F8521A22C836E3345E2DF2D /* Pods_Example.framework in Frameworks */, 47 | ); 48 | runOnlyForDeploymentPostprocessing = 0; 49 | }; 50 | /* End PBXFrameworksBuildPhase section */ 51 | 52 | /* Begin PBXGroup section */ 53 | 256066CC91454B15DB474C36 /* Frameworks */ = { 54 | isa = PBXGroup; 55 | children = ( 56 | D59FADF8389DD5C55FB59402 /* Pods_PermissionsService_Tests.framework */, 57 | C9F446DF0721F3104C2FFC11 /* Pods_Example.framework */, 58 | ); 59 | name = Frameworks; 60 | sourceTree = ""; 61 | }; 62 | 607FACC71AFB9204008FA782 = { 63 | isa = PBXGroup; 64 | children = ( 65 | DBBDE1A81DACEB3F00E4151F /* Example */, 66 | 607FACF51AFB993E008FA782 /* Podspec Metadata */, 67 | 607FACD11AFB9204008FA782 /* Products */, 68 | 9A1B671DDEEAFA471C50559A /* Pods */, 69 | 256066CC91454B15DB474C36 /* Frameworks */, 70 | ); 71 | indentWidth = 2; 72 | sourceTree = ""; 73 | tabWidth = 2; 74 | }; 75 | 607FACD11AFB9204008FA782 /* Products */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | DBBDE1A71DACEB3F00E4151F /* Example.app */, 79 | ); 80 | name = Products; 81 | sourceTree = ""; 82 | }; 83 | 607FACF51AFB993E008FA782 /* Podspec Metadata */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | 7ADD5F211D4FBE2FE6881EFF /* PermissionsService.podspec */, 87 | DBCE10161D26AE1800F97B8E /* README.md */, 88 | E2020FAF9E463C2A412E99DA /* LICENSE */, 89 | ); 90 | name = "Podspec Metadata"; 91 | sourceTree = ""; 92 | }; 93 | 9A1B671DDEEAFA471C50559A /* Pods */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 115DFF34E5A239BE4C0940D4 /* Pods-PermissionsService_Tests.debug.xcconfig */, 97 | BA644CC018C9CCC2FA10C489 /* Pods-PermissionsService_Tests.release.xcconfig */, 98 | D1E7F4FA7E8AFE8CA9CBD36C /* Pods-Example.debug.xcconfig */, 99 | ED0308B2A9D83383EBEE8B2A /* Pods-Example.release.xcconfig */, 100 | ); 101 | name = Pods; 102 | sourceTree = ""; 103 | }; 104 | DBBDE1A81DACEB3F00E4151F /* Example */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | 9B01A92F1F2884690056279D /* Example.entitlements */, 108 | DBBDE1C31DACF05C00E4151F /* Sources */, 109 | DBBDE1CA1DACF19800E4151F /* Storyboards */, 110 | DBBDE1BE1DACEBA500E4151F /* Resources */, 111 | DBBDE1CB1DACF46E00E4151F /* Enter Point */, 112 | DBBDE1A91DACEB3F00E4151F /* Supporting Files */, 113 | ); 114 | path = Example; 115 | sourceTree = ""; 116 | }; 117 | DBBDE1A91DACEB3F00E4151F /* Supporting Files */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | ); 121 | name = "Supporting Files"; 122 | sourceTree = ""; 123 | }; 124 | DBBDE1BE1DACEBA500E4151F /* Resources */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | DBBDE1BF1DACEC2000E4151F /* Assets.xcassets */, 128 | DBBDE1C01DACEC2000E4151F /* Info.plist */, 129 | ); 130 | name = Resources; 131 | sourceTree = ""; 132 | }; 133 | DBBDE1C31DACF05C00E4151F /* Sources */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | DBBDE1D11DACF49700E4151F /* Controllers */, 137 | ); 138 | path = Sources; 139 | sourceTree = ""; 140 | }; 141 | DBBDE1CA1DACF19800E4151F /* Storyboards */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | DBBDE1B21DACEB3F00E4151F /* Main.storyboard */, 145 | DBBDE1B71DACEB3F00E4151F /* LaunchScreen.storyboard */, 146 | ); 147 | name = Storyboards; 148 | sourceTree = ""; 149 | }; 150 | DBBDE1CB1DACF46E00E4151F /* Enter Point */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | DBBDE1CC1DACF46E00E4151F /* AppDelegate.h */, 154 | DBBDE1CD1DACF46E00E4151F /* AppDelegate.m */, 155 | DBBDE1CE1DACF46E00E4151F /* main.m */, 156 | ); 157 | path = "Enter Point"; 158 | sourceTree = ""; 159 | }; 160 | DBBDE1D11DACF49700E4151F /* Controllers */ = { 161 | isa = PBXGroup; 162 | children = ( 163 | DBBDE1D21DACF50C00E4151F /* PermissionsController.swift */, 164 | ); 165 | name = Controllers; 166 | path = Controller; 167 | sourceTree = ""; 168 | }; 169 | /* End PBXGroup section */ 170 | 171 | /* Begin PBXNativeTarget section */ 172 | DBBDE1A61DACEB3F00E4151F /* Example */ = { 173 | isa = PBXNativeTarget; 174 | buildConfigurationList = DBBDE1BB1DACEB3F00E4151F /* Build configuration list for PBXNativeTarget "Example" */; 175 | buildPhases = ( 176 | 502A51AE0245E2AA775B630C /* [CP] Check Pods Manifest.lock */, 177 | DBBDE1A31DACEB3F00E4151F /* Sources */, 178 | DBBDE1A41DACEB3F00E4151F /* Frameworks */, 179 | DBBDE1A51DACEB3F00E4151F /* Resources */, 180 | 30BD0FC9C444F23BD511F7F2 /* [CP] Embed Pods Frameworks */, 181 | ); 182 | buildRules = ( 183 | ); 184 | dependencies = ( 185 | ); 186 | name = Example; 187 | productName = Example; 188 | productReference = DBBDE1A71DACEB3F00E4151F /* Example.app */; 189 | productType = "com.apple.product-type.application"; 190 | }; 191 | /* End PBXNativeTarget section */ 192 | 193 | /* Begin PBXProject section */ 194 | 607FACC81AFB9204008FA782 /* Project object */ = { 195 | isa = PBXProject; 196 | attributes = { 197 | LastSwiftUpdateCheck = 0720; 198 | LastUpgradeCheck = 1020; 199 | ORGANIZATIONNAME = CocoaPods; 200 | TargetAttributes = { 201 | DBBDE1A61DACEB3F00E4151F = { 202 | CreatedOnToolsVersion = 8.0; 203 | DevelopmentTeam = J7LBYY3B34; 204 | LastSwiftMigration = 0800; 205 | ProvisioningStyle = Automatic; 206 | SystemCapabilities = { 207 | com.apple.Siri = { 208 | enabled = 1; 209 | }; 210 | }; 211 | }; 212 | }; 213 | }; 214 | buildConfigurationList = 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "PermissionsService" */; 215 | compatibilityVersion = "Xcode 3.2"; 216 | developmentRegion = en; 217 | hasScannedForEncodings = 0; 218 | knownRegions = ( 219 | en, 220 | Base, 221 | ); 222 | mainGroup = 607FACC71AFB9204008FA782; 223 | productRefGroup = 607FACD11AFB9204008FA782 /* Products */; 224 | projectDirPath = ""; 225 | projectRoot = ""; 226 | targets = ( 227 | DBBDE1A61DACEB3F00E4151F /* Example */, 228 | ); 229 | }; 230 | /* End PBXProject section */ 231 | 232 | /* Begin PBXResourcesBuildPhase section */ 233 | DBBDE1A51DACEB3F00E4151F /* Resources */ = { 234 | isa = PBXResourcesBuildPhase; 235 | buildActionMask = 2147483647; 236 | files = ( 237 | DBBDE1B91DACEB3F00E4151F /* LaunchScreen.storyboard in Resources */, 238 | DBBDE1C11DACEC2000E4151F /* Assets.xcassets in Resources */, 239 | DBBDE1B41DACEB3F00E4151F /* Main.storyboard in Resources */, 240 | ); 241 | runOnlyForDeploymentPostprocessing = 0; 242 | }; 243 | /* End PBXResourcesBuildPhase section */ 244 | 245 | /* Begin PBXShellScriptBuildPhase section */ 246 | 30BD0FC9C444F23BD511F7F2 /* [CP] Embed Pods Frameworks */ = { 247 | isa = PBXShellScriptBuildPhase; 248 | buildActionMask = 2147483647; 249 | files = ( 250 | ); 251 | inputPaths = ( 252 | "${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-frameworks.sh", 253 | "${BUILT_PRODUCTS_DIR}/PermissionsService/PermissionsService.framework", 254 | ); 255 | name = "[CP] Embed Pods Frameworks"; 256 | outputPaths = ( 257 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PermissionsService.framework", 258 | ); 259 | runOnlyForDeploymentPostprocessing = 0; 260 | shellPath = /bin/sh; 261 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-frameworks.sh\"\n"; 262 | showEnvVarsInLog = 0; 263 | }; 264 | 502A51AE0245E2AA775B630C /* [CP] Check Pods Manifest.lock */ = { 265 | isa = PBXShellScriptBuildPhase; 266 | buildActionMask = 2147483647; 267 | files = ( 268 | ); 269 | inputPaths = ( 270 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 271 | "${PODS_ROOT}/Manifest.lock", 272 | ); 273 | name = "[CP] Check Pods Manifest.lock"; 274 | outputPaths = ( 275 | "$(DERIVED_FILE_DIR)/Pods-Example-checkManifestLockResult.txt", 276 | ); 277 | runOnlyForDeploymentPostprocessing = 0; 278 | shellPath = /bin/sh; 279 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 280 | showEnvVarsInLog = 0; 281 | }; 282 | /* End PBXShellScriptBuildPhase section */ 283 | 284 | /* Begin PBXSourcesBuildPhase section */ 285 | DBBDE1A31DACEB3F00E4151F /* Sources */ = { 286 | isa = PBXSourcesBuildPhase; 287 | buildActionMask = 2147483647; 288 | files = ( 289 | DBBDE1D31DACF50C00E4151F /* PermissionsController.swift in Sources */, 290 | DBBDE1CF1DACF46E00E4151F /* AppDelegate.m in Sources */, 291 | DBBDE1D01DACF46E00E4151F /* main.m in Sources */, 292 | ); 293 | runOnlyForDeploymentPostprocessing = 0; 294 | }; 295 | /* End PBXSourcesBuildPhase section */ 296 | 297 | /* Begin PBXVariantGroup section */ 298 | DBBDE1B21DACEB3F00E4151F /* Main.storyboard */ = { 299 | isa = PBXVariantGroup; 300 | children = ( 301 | DBBDE1B31DACEB3F00E4151F /* Base */, 302 | ); 303 | name = Main.storyboard; 304 | sourceTree = ""; 305 | }; 306 | DBBDE1B71DACEB3F00E4151F /* LaunchScreen.storyboard */ = { 307 | isa = PBXVariantGroup; 308 | children = ( 309 | DBBDE1B81DACEB3F00E4151F /* Base */, 310 | ); 311 | name = LaunchScreen.storyboard; 312 | sourceTree = ""; 313 | }; 314 | /* End PBXVariantGroup section */ 315 | 316 | /* Begin XCBuildConfiguration section */ 317 | 607FACED1AFB9204008FA782 /* Debug */ = { 318 | isa = XCBuildConfiguration; 319 | buildSettings = { 320 | ALWAYS_SEARCH_USER_PATHS = NO; 321 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 322 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 323 | CLANG_CXX_LIBRARY = "libc++"; 324 | CLANG_ENABLE_MODULES = YES; 325 | CLANG_ENABLE_OBJC_ARC = YES; 326 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 327 | CLANG_WARN_BOOL_CONVERSION = YES; 328 | CLANG_WARN_COMMA = YES; 329 | CLANG_WARN_CONSTANT_CONVERSION = YES; 330 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 331 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 332 | CLANG_WARN_EMPTY_BODY = YES; 333 | CLANG_WARN_ENUM_CONVERSION = YES; 334 | CLANG_WARN_INFINITE_RECURSION = YES; 335 | CLANG_WARN_INT_CONVERSION = YES; 336 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 337 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 338 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 339 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 340 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 341 | CLANG_WARN_STRICT_PROTOTYPES = YES; 342 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 343 | CLANG_WARN_UNREACHABLE_CODE = YES; 344 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 345 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 346 | COPY_PHASE_STRIP = NO; 347 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 348 | ENABLE_STRICT_OBJC_MSGSEND = YES; 349 | ENABLE_TESTABILITY = YES; 350 | GCC_C_LANGUAGE_STANDARD = gnu99; 351 | GCC_DYNAMIC_NO_PIC = NO; 352 | GCC_NO_COMMON_BLOCKS = YES; 353 | GCC_OPTIMIZATION_LEVEL = 0; 354 | GCC_PREPROCESSOR_DEFINITIONS = ( 355 | "DEBUG=1", 356 | "$(inherited)", 357 | ); 358 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 359 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 360 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 361 | GCC_WARN_UNDECLARED_SELECTOR = YES; 362 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 363 | GCC_WARN_UNUSED_FUNCTION = YES; 364 | GCC_WARN_UNUSED_VARIABLE = YES; 365 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 366 | MTL_ENABLE_DEBUG_INFO = YES; 367 | ONLY_ACTIVE_ARCH = YES; 368 | SDKROOT = iphoneos; 369 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 370 | SWIFT_VERSION = 3.0; 371 | }; 372 | name = Debug; 373 | }; 374 | 607FACEE1AFB9204008FA782 /* Release */ = { 375 | isa = XCBuildConfiguration; 376 | buildSettings = { 377 | ALWAYS_SEARCH_USER_PATHS = NO; 378 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 379 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 380 | CLANG_CXX_LIBRARY = "libc++"; 381 | CLANG_ENABLE_MODULES = YES; 382 | CLANG_ENABLE_OBJC_ARC = YES; 383 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 384 | CLANG_WARN_BOOL_CONVERSION = YES; 385 | CLANG_WARN_COMMA = YES; 386 | CLANG_WARN_CONSTANT_CONVERSION = YES; 387 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 388 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 389 | CLANG_WARN_EMPTY_BODY = YES; 390 | CLANG_WARN_ENUM_CONVERSION = YES; 391 | CLANG_WARN_INFINITE_RECURSION = YES; 392 | CLANG_WARN_INT_CONVERSION = YES; 393 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 394 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 395 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 396 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 397 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 398 | CLANG_WARN_STRICT_PROTOTYPES = YES; 399 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 400 | CLANG_WARN_UNREACHABLE_CODE = YES; 401 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 402 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 403 | COPY_PHASE_STRIP = NO; 404 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 405 | ENABLE_NS_ASSERTIONS = NO; 406 | ENABLE_STRICT_OBJC_MSGSEND = YES; 407 | GCC_C_LANGUAGE_STANDARD = gnu99; 408 | GCC_NO_COMMON_BLOCKS = YES; 409 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 410 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 411 | GCC_WARN_UNDECLARED_SELECTOR = YES; 412 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 413 | GCC_WARN_UNUSED_FUNCTION = YES; 414 | GCC_WARN_UNUSED_VARIABLE = YES; 415 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 416 | MTL_ENABLE_DEBUG_INFO = NO; 417 | SDKROOT = iphoneos; 418 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 419 | SWIFT_VERSION = 3.0; 420 | VALIDATE_PRODUCT = YES; 421 | }; 422 | name = Release; 423 | }; 424 | DBBDE1BC1DACEB3F00E4151F /* Debug */ = { 425 | isa = XCBuildConfiguration; 426 | baseConfigurationReference = D1E7F4FA7E8AFE8CA9CBD36C /* Pods-Example.debug.xcconfig */; 427 | buildSettings = { 428 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 429 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 430 | CLANG_ANALYZER_NONNULL = YES; 431 | CLANG_ENABLE_MODULES = YES; 432 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 433 | CLANG_WARN_INFINITE_RECURSION = YES; 434 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 435 | CODE_SIGN_ENTITLEMENTS = Example/Example.entitlements; 436 | DEBUG_INFORMATION_FORMAT = dwarf; 437 | DEVELOPMENT_TEAM = J7LBYY3B34; 438 | INFOPLIST_FILE = "$(SRCROOT)/Example/Resourses/Info.plist"; 439 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 440 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 441 | PRODUCT_BUNDLE_IDENTIFIER = permissionsservice.example; 442 | PRODUCT_NAME = "$(TARGET_NAME)"; 443 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 444 | SWIFT_VERSION = 4.2; 445 | }; 446 | name = Debug; 447 | }; 448 | DBBDE1BD1DACEB3F00E4151F /* Release */ = { 449 | isa = XCBuildConfiguration; 450 | baseConfigurationReference = ED0308B2A9D83383EBEE8B2A /* Pods-Example.release.xcconfig */; 451 | buildSettings = { 452 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 453 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 454 | CLANG_ANALYZER_NONNULL = YES; 455 | CLANG_ENABLE_MODULES = YES; 456 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 457 | CLANG_WARN_INFINITE_RECURSION = YES; 458 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 459 | CODE_SIGN_ENTITLEMENTS = Example/Example.entitlements; 460 | DEVELOPMENT_TEAM = J7LBYY3B34; 461 | INFOPLIST_FILE = "$(SRCROOT)/Example/Resourses/Info.plist"; 462 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 463 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 464 | PRODUCT_BUNDLE_IDENTIFIER = permissionsservice.example; 465 | PRODUCT_NAME = "$(TARGET_NAME)"; 466 | SWIFT_VERSION = 4.2; 467 | }; 468 | name = Release; 469 | }; 470 | /* End XCBuildConfiguration section */ 471 | 472 | /* Begin XCConfigurationList section */ 473 | 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "PermissionsService" */ = { 474 | isa = XCConfigurationList; 475 | buildConfigurations = ( 476 | 607FACED1AFB9204008FA782 /* Debug */, 477 | 607FACEE1AFB9204008FA782 /* Release */, 478 | ); 479 | defaultConfigurationIsVisible = 0; 480 | defaultConfigurationName = Release; 481 | }; 482 | DBBDE1BB1DACEB3F00E4151F /* Build configuration list for PBXNativeTarget "Example" */ = { 483 | isa = XCConfigurationList; 484 | buildConfigurations = ( 485 | DBBDE1BC1DACEB3F00E4151F /* Debug */, 486 | DBBDE1BD1DACEB3F00E4151F /* Release */, 487 | ); 488 | defaultConfigurationIsVisible = 0; 489 | defaultConfigurationName = Release; 490 | }; 491 | /* End XCConfigurationList section */ 492 | }; 493 | rootObject = 607FACC81AFB9204008FA782 /* Project object */; 494 | } 495 | --------------------------------------------------------------------------------