From 8b4f3271b666d6ec0a4420a475ccc6a35bb0defd Mon Sep 17 00:00:00 2001 From: Ennio Masi Date: Wed, 18 Oct 2017 13:29:13 +0100 Subject: [PATCH 1/2] Fix core motion --- .../arek_example.xcodeproj/project.pbxproj | 21 +++-- Example/arek_example/AppDelegate.swift | 26 ------ Example/arek_example/ArekCell.swift | 2 - .../ArekCellVMServiceProgrammatically.swift | 15 ++- .../AppIcon.appiconset/Contents.json | 5 + Example/arek_example/Info.plist | 37 ++++---- .../arek_example/arek_example.entitlements | 8 -- .../Core/Utilities/ArekPermissionStatus.swift | 2 +- code/Classes/Permissions/ArekMotion.swift | 93 +++++++++++-------- 9 files changed, 102 insertions(+), 107 deletions(-) delete mode 100644 Example/arek_example/arek_example.entitlements diff --git a/Example/arek_example.xcodeproj/project.pbxproj b/Example/arek_example.xcodeproj/project.pbxproj index fca8cb0..8c057e4 100644 --- a/Example/arek_example.xcodeproj/project.pbxproj +++ b/Example/arek_example.xcodeproj/project.pbxproj @@ -44,7 +44,6 @@ 6B3633611F0D8CEE00F3B300 /* ArekCellVMServiceLocalizable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArekCellVMServiceLocalizable.swift; sourceTree = ""; }; 6B6654171F0CF3D80093A15E /* ArekCellVM.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArekCellVM.swift; sourceTree = ""; }; 6BAB53341F0D1ACE00E02E1D /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; - 752A54701E77416E006F9B3E /* arek_example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = arek_example.entitlements; sourceTree = ""; }; 7569AF8D1E7447F300E81C95 /* arek_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = arek_example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 7569AF901E7447F300E81C95 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7569AF921E7447F300E81C95 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; @@ -137,7 +136,6 @@ children = ( 6B6654161F0CF3CA0093A15E /* ArekCell */, 7569AF901E7447F300E81C95 /* AppDelegate.swift */, - 752A54701E77416E006F9B3E /* arek_example.entitlements */, 7569AF971E7447F300E81C95 /* Assets.xcassets */, 7569AF9C1E7447F300E81C95 /* Info.plist */, 7569AF991E7447F300E81C95 /* LaunchScreen.storyboard */, @@ -245,6 +243,7 @@ TargetAttributes = { 7569AF8C1E7447F300E81C95 = { CreatedOnToolsVersion = 8.2.1; + DevelopmentTeam = MQ7M5YR8SU; ProvisioningStyle = Automatic; SystemCapabilities = { com.apple.Siri = { @@ -538,12 +537,15 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = arek_example/arek_example.entitlements; - DEVELOPMENT_TEAM = ""; + CODE_SIGN_ENTITLEMENTS = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = MQ7M5YR8SU; INFOPLIST_FILE = arek_example/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = ennioma.arek; + PRODUCT_BUNDLE_IDENTIFIER = com.ennioma.arek; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 3.0; }; name = Debug; @@ -554,12 +556,15 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = arek_example/arek_example.entitlements; - DEVELOPMENT_TEAM = ""; + CODE_SIGN_ENTITLEMENTS = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = MQ7M5YR8SU; INFOPLIST_FILE = arek_example/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = ennioma.arek; + PRODUCT_BUNDLE_IDENTIFIER = com.ennioma.arek; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 3.0; }; name = Release; diff --git a/Example/arek_example/AppDelegate.swift b/Example/arek_example/AppDelegate.swift index bf0667a..43657e0 100644 --- a/Example/arek_example/AppDelegate.swift +++ b/Example/arek_example/AppDelegate.swift @@ -30,34 +30,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. return true } - func applicationWillResignActive(_ application: UIApplication) { - // 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. - // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. - } - - func applicationDidEnterBackground(_ application: UIApplication) { - // 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. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - } - - func applicationWillEnterForeground(_ application: UIApplication) { - // 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. - } - - func applicationDidBecomeActive(_ application: UIApplication) { - // 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. - } - - func applicationWillTerminate(_ application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - } - - } - diff --git a/Example/arek_example/ArekCell.swift b/Example/arek_example/ArekCell.swift index a24799f..8228807 100644 --- a/Example/arek_example/ArekCell.swift +++ b/Example/arek_example/ArekCell.swift @@ -50,7 +50,6 @@ class ArekCell: UITableViewCell { if clicked, (viewModel?.permission != nil) { self.managePermission() - } } } @@ -59,7 +58,6 @@ class ArekCell: UITableViewCell { viewModel?.permission.manage(completion: { (status) in self.updateUI(status) - }) } diff --git a/Example/arek_example/ArekCellVMServiceProgrammatically.swift b/Example/arek_example/ArekCellVMServiceProgrammatically.swift index 980c60c..5a23f40 100644 --- a/Example/arek_example/ArekCellVMServiceProgrammatically.swift +++ b/Example/arek_example/ArekCellVMServiceProgrammatically.swift @@ -30,7 +30,8 @@ class ArekCellVMServiceProgrammatically { static private var permissions = [ ["popupDataTitle": "Media Library Access - native", "allowButtonTitle": "Allow 👍🏼", "denyButtonTitle": "No! 👎🏼", "enableTitle": "Please!", "reEnableTitle": "Re-enable please!"], ["popupDataTitle": "Camera Access - PMAlertController", "allowButtonTitle": "Allow 👍🏼", "denyButtonTitle": "No! 👎🏼", "enableTitle": "Please!", "reEnableTitle": "Re-enable please!"], - ["popupDataTitle": "Location Always Access - native", "allowButtonTitle": "Allow 👍🏼", "denyButtonTitle": "No! 👎🏼", "enableTitle": "Please!", "reEnableTitle": "Re-enable please!"] + ["popupDataTitle": "Location Always Access - native", "allowButtonTitle": "Allow 👍🏼", "denyButtonTitle": "No! 👎🏼", "enableTitle": "Please!", "reEnableTitle": "Re-enable please!"], + ["popupDataTitle": "Motion - PMAlertController", "allowButtonTitle": "Allow 👍🏼", "denyButtonTitle": "No! 👎🏼", "enableTitle": "Please!", "reEnableTitle": "Re-enable please!"] ] static func numberOfVMs() -> Int { @@ -40,15 +41,15 @@ class ArekCellVMServiceProgrammatically { static func buildVM(index: Int) -> ArekCellVM { let data = permissions[index] - let configuration = ArekConfiguration(frequency: .OnceADay, presentInitialPopup: true, presentReEnablePopup: true) - let initialPopupData = ArekPopupData(title: data["popupDataTitle"]!, message: data["enableTitle"]!, image: "", allowButtonTitle: data["allowButtonTitle"]!, denyButtonTitle: data["denyButtonTitle"]!, type: getPopuptType(index: index)) - let reenablePopupData = ArekPopupData(title: data["popupDataTitle"]!, message: data["reEnableTitle"]!, image: "", allowButtonTitle: data["allowButtonTitle"]!, denyButtonTitle: data["denyButtonTitle"]!, type: getPopuptType(index: index)) + let configuration = ArekConfiguration(frequency: .Always, presentInitialPopup: true, presentReEnablePopup: true) + let initialPopupData = ArekPopupData(title: data["popupDataTitle"]!, message: data["enableTitle"]!, image: "", allowButtonTitle: data["allowButtonTitle"]!, denyButtonTitle: data["denyButtonTitle"]!, type: getPopupType(index: index)) + let reenablePopupData = ArekPopupData(title: data["popupDataTitle"]!, message: data["reEnableTitle"]!, image: "", allowButtonTitle: data["allowButtonTitle"]!, denyButtonTitle: data["denyButtonTitle"]!, type: getPopupType(index: index)) let permission = getPermissionType(index: index, configuration: configuration, initialPopupData: initialPopupData, reEnablePopupData: reenablePopupData) return ArekCellVM(permission: permission!, title: data["popupDataTitle"]!) } - static private func getPopuptType(index: Int) -> ArekPopupType { + static private func getPopupType(index: Int) -> ArekPopupType { switch index { case 0: return .native @@ -56,6 +57,8 @@ class ArekCellVMServiceProgrammatically { return .codeido case 2: return .native + case 3: + return .codeido default: return .native } @@ -70,6 +73,8 @@ class ArekCellVMServiceProgrammatically { return ArekCamera(configuration: configuration, initialPopupData: initialPopupData, reEnablePopupData: reEnablePopupData) case 2: return ArekLocationAlways(configuration: configuration, initialPopupData: initialPopupData, reEnablePopupData: reEnablePopupData) + case 3: + return ArekMotion(configuration: configuration, initialPopupData: initialPopupData, reEnablePopupData: reEnablePopupData) default: return nil } diff --git a/Example/arek_example/Assets.xcassets/AppIcon.appiconset/Contents.json b/Example/arek_example/Assets.xcassets/AppIcon.appiconset/Contents.json index b8236c6..19882d5 100644 --- a/Example/arek_example/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Example/arek_example/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -39,6 +39,11 @@ "idiom" : "iphone", "size" : "60x60", "scale" : "3x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" } ], "info" : { diff --git a/Example/arek_example/Info.plist b/Example/arek_example/Info.plist index af55295..24450a0 100644 --- a/Example/arek_example/Info.plist +++ b/Example/arek_example/Info.plist @@ -20,10 +20,24 @@ 1 LSRequiresIPhoneOS - NSCalendarsUsageDescription - asd lol - NSSiriUsageDescription - usa siri + NSAppleMusicUsageDescription + Oh oh get me your Media! + NSCameraUsageDescription + I want to access your Camera! + NSContactsUsageDescription + Let me read your contacts! + NSLocationAlwaysUsageDescription + Get me the Location Dude! + NSPhotoLibraryUsageDescription + Want to access your photos! + NSRemindersUsageDescription + Let's go to your reminders! + NSMotionUsageDescription + Want your motion dataaaa + NSLocationAlwaysAndWhenInUseUsageDescription + Get me the Location Dude! + NSLocationWhenInUseUsageDescription + Get me the Location Dude! UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -35,20 +49,7 @@ UISupportedInterfaceOrientations UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown - NSAppleMusicUsageDescription - Oh oh get me your Media! - NSCameraUsageDescription - I want to access your Camera! - NSLocationAlwaysUsageDescription - Get me the Location Dude! - NSContactsUsageDescription - Let me read your contacts! - NSPhotoLibraryUsageDescription - Want to access your photos! - NSRemindersUsageDescription - Let's go to your reminders! diff --git a/Example/arek_example/arek_example.entitlements b/Example/arek_example/arek_example.entitlements deleted file mode 100644 index 21d95c4..0000000 --- a/Example/arek_example/arek_example.entitlements +++ /dev/null @@ -1,8 +0,0 @@ - - - - - com.apple.developer.siri - - - diff --git a/code/Classes/Core/Utilities/ArekPermissionStatus.swift b/code/Classes/Core/Utilities/ArekPermissionStatus.swift index 4daa041..9e61a93 100644 --- a/code/Classes/Core/Utilities/ArekPermissionStatus.swift +++ b/code/Classes/Core/Utilities/ArekPermissionStatus.swift @@ -25,7 +25,7 @@ import Foundation -public enum ArekPermissionStatus { +public enum ArekPermissionStatus: String { case authorized case denied case notDetermined diff --git a/code/Classes/Permissions/ArekMotion.swift b/code/Classes/Permissions/ArekMotion.swift index 8e47259..46dd6fe 100644 --- a/code/Classes/Permissions/ArekMotion.swift +++ b/code/Classes/Permissions/ArekMotion.swift @@ -29,13 +29,25 @@ import CoreMotion open class ArekMotion: ArekBasePermission, ArekPermissionProtocol { open var identifier: String = "ArekMotion" + private let userKey = "ennioma.arek.motion.requested" private let motionManager = CMMotionActivityManager() - private lazy var motionHandlerQueue: OperationQueue = { - var queue = OperationQueue() - queue.name = "arek.MotionHandlerQueue" - queue.maxConcurrentOperationCount = 1 - return queue - }() + + private var motionRequested: ArekPermissionStatus { + get { + if let data = UserDefaults.standard.value(forKey: userKey) as? Data, + let value = NSKeyedUnarchiver.unarchiveObject(with: data) as? String, + let permission = ArekPermissionStatus(rawValue: value) { + + return permission + } + + return .notDetermined + } + set { + UserDefaults.standard.set(NSKeyedArchiver.archivedData(withRootObject: newValue.rawValue), forKey: userKey) + UserDefaults.standard.synchronize() + } + } public init() { super.init(identifier: self.identifier) @@ -46,57 +58,60 @@ open class ArekMotion: ArekBasePermission, ArekPermissionProtocol { } open func status(completion: @escaping ArekPermissionResponse) { - if CMMotionActivityManager.isActivityAvailable() == false { - return completion(.notAvailable) + if CMMotionActivityManager.isActivityAvailable() == false { return completion(.notAvailable) } + + switch self.motionRequested { + case .notDetermined: + return completion(.notDetermined) + //case .denied: + //return completion(.denied) + default: + self.requestMotion(completion: completion) } + } + + open func askForPermission(completion: @escaping ArekPermissionResponse) { + if CMMotionActivityManager.isActivityAvailable() == false { return completion(.notAvailable) } - self.motionManager.queryActivityStarting(from: Date(), to: Date(), to: motionHandlerQueue) { _, error in - self.motionManager.stopActivityUpdates() - + motionManager.queryActivityStarting(from: Date(), to: Date(), to: .main) { _, error in if let error = error as NSError? { if error.code == Int(CMErrorMotionActivityNotAuthorized.rawValue) || error.code == Int(CMErrorNotAuthorized.rawValue) { - - DispatchQueue.main.async { - return completion(.denied) - } + print("[🚨 Arek 🚨] 🏃🏻 permission denied by user ⛔️") + + self.motionRequested = .denied + DispatchQueue.main.async { return completion(.denied) } } else { - DispatchQueue.main.async { - return completion(.notDetermined) - } + print("[🚨 Arek 🚨] 🏃🏻 permission not determined 🤔") + + self.motionRequested = .notDetermined + DispatchQueue.main.async { return completion(.notDetermined) } } } else { - return completion(.authorized) + print("[🚨 Arek 🚨] 🏃🏻 permission authorized by user ✅") + + self.motionRequested = .authorized + DispatchQueue.main.async { return completion(.authorized) } } + self.motionManager.stopActivityUpdates() } } - open func askForPermission(completion: @escaping ArekPermissionResponse) { - if CMMotionActivityManager.isActivityAvailable() == false { - return completion(.notAvailable) - } - - motionManager.queryActivityStarting(from: Date(), to: Date(), to: motionHandlerQueue) { _, error in + private func requestMotion(completion: @escaping ArekPermissionResponse) { + self.motionManager.queryActivityStarting(from: Date(), to: Date(), to: .main) { _, error in + self.motionManager.stopActivityUpdates() + if let error = error as NSError? { if error.code == Int(CMErrorMotionActivityNotAuthorized.rawValue) || - error.code == Int(CMErrorNotAuthorized.rawValue) { - print("[🚨 Arek 🚨] 🏃🏻 permission denied by user ⛔️") - DispatchQueue.main.async { - return completion(.denied) - } + error.code == Int(CMErrorNotAuthorized.rawValue) { + + DispatchQueue.main.async { return completion(.denied) } } else { - print("[🚨 Arek 🚨] 🏃🏻 permission not determined 🤔") - DispatchQueue.main.async { - return completion(.notDetermined) - } + DispatchQueue.main.async { return completion(.notDetermined) } } } else { - print("[🚨 Arek 🚨] 🏃🏻 permission authorized by user ✅") - DispatchQueue.main.async { - return completion(.authorized) - } + return completion(.authorized) } - self.motionManager.stopActivityUpdates() } } } From cb47c6c439ca88bbb384a32d41fcc687ee77c643 Mon Sep 17 00:00:00 2001 From: Ennio Masi Date: Fri, 20 Oct 2017 13:45:36 +0100 Subject: [PATCH 2/2] Reference to version updated to 1.6.0 --- README.md | 6 +++--- arek.podspec | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c38261b..fa366a1 100644 --- a/README.md +++ b/README.md @@ -192,7 +192,7 @@ Add AREK to your Podfile ```ruby use_frameworks! target 'MyTarget' do - pod 'arek', '~> 1.5.0' + pod 'arek', '~> 1.6.0' end ``` @@ -200,7 +200,7 @@ If you want to install just a specific permission, let's say `Bluetooth`, you ha ```ruby use_frameworks! target 'MyTarget' do - pod 'arek/Bluetooth', '~> 1.5.0' + pod 'arek/Bluetooth', '~> 1.6.0' end ``` @@ -210,7 +210,7 @@ $ pod install ## Carthage ```ruby -github "ennioma/arek" ~> "1.5.0" +github "ennioma/arek" ~> "1.6.0" ``` Then on your application target *Build Phases* settings tab, add a "New Run Script Phase". Create a Run Script with the following content: diff --git a/arek.podspec b/arek.podspec index cb7838f..bbca2fa 100644 --- a/arek.podspec +++ b/arek.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'arek' - s.version = '1.5.0' + s.version = '1.6.0' s.summary = 'AREK is a clean and easy to use wrapper over any kind of iOS permission.' s.homepage = 'https://github.com/ennioma/arek' s.license = { :type => 'MIT', :file => 'LICENSE'}