diff --git a/.swift-version b/.swift-version index 9f55b2c..5186d07 100644 --- a/.swift-version +++ b/.swift-version @@ -1 +1 @@ -3.0 +4.0 diff --git a/Armchair.podspec b/Armchair.podspec index d4d6402..e0c0f1e 100644 --- a/Armchair.podspec +++ b/Armchair.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "Armchair" - s.version = "0.3.0" + s.version = "0.3.5" s.summary = "A simple yet powerful App Review Manager for iOS and OSX in Swift" s.description = <<-DESC A simple yet powerful App Review Manager for iOS and OSX in Swift. diff --git a/Armchair.xcodeproj/project.pbxproj b/Armchair.xcodeproj/project.pbxproj index 97bbe9b..84f160c 100644 --- a/Armchair.xcodeproj/project.pbxproj +++ b/Armchair.xcodeproj/project.pbxproj @@ -318,13 +318,16 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = Armchair; TargetAttributes = { E6A0AF6419C9CFF400C3A7DC = { CreatedOnToolsVersion = 6.0; ProvisioningStyle = Manual; }; + E6D8B8EF19C756A4001AD043 = { + LastSwiftMigration = 0900; + }; F8111E3219A95C8B0040E7D1 = { CreatedOnToolsVersion = 6.0; LastSwiftMigration = 0800; @@ -541,7 +544,8 @@ SKIP_INSTALL = YES; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -566,7 +570,8 @@ SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_OBJC_BRIDGING_HEADER = ""; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; + SWIFT_VERSION = 4.0; }; name = Release; }; @@ -617,14 +622,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -655,6 +666,7 @@ OTHER_SWIFT_FLAGS = "-DDebug"; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -669,14 +681,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -698,6 +716,7 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -724,7 +743,7 @@ SKIP_INSTALL = YES; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -746,7 +765,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OBJC_BRIDGING_HEADER = ""; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; }; name = Release; }; diff --git a/Armchair.xcodeproj/xcshareddata/xcschemes/Armchair.xcscheme b/Armchair.xcodeproj/xcshareddata/xcschemes/Armchair.xcscheme index 53b90e2..a138fe9 100644 --- a/Armchair.xcodeproj/xcshareddata/xcschemes/Armchair.xcscheme +++ b/Armchair.xcodeproj/xcshareddata/xcschemes/Armchair.xcscheme @@ -1,6 +1,6 @@ @@ -36,6 +37,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Example/AppDelegate.swift b/Example/AppDelegate.swift index 435f5a2..c03e5a8 100644 --- a/Example/AppDelegate.swift +++ b/Example/AppDelegate.swift @@ -28,12 +28,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool { + AppDelegate.setupArmchair() return true } } - let Pages = "361309726" // Pages iOS + let appID = "361309726" // Pages iOS #elseif os(OSX) @@ -43,9 +44,12 @@ class AppDelegate: NSObject, NSApplicationDelegate { @IBOutlet weak var window: NSWindow! + override init() { + AppDelegate.setupArmchair() + } } - let Pages = "409201541" // Pages Mac + let appID = "409201541" // Pages Mac #else #endif @@ -54,10 +58,6 @@ import Armchair extension AppDelegate { - override class func initialize() { - AppDelegate.setupArmchair() - } - class func setupArmchair() { // Normally, all the setup would be here. // But, because we are presenting a few different setups in the example, @@ -68,7 +68,7 @@ extension AppDelegate { // because it needs to receive application life-cycle notifications // // NOTE: The appID call always has to go before any other Armchair calls - Armchair.appID(Pages) + Armchair.appID(appID) Armchair.debugEnabled(true) } } diff --git a/Example/ViewController.swift b/Example/ViewController.swift index 7d5703f..4a33272 100644 --- a/Example/ViewController.swift +++ b/Example/ViewController.swift @@ -55,12 +55,12 @@ extension ViewController { // Only set it if we are using Armchair localizations if !Armchair.useMainAppBundleForLocalizations() { - let currentLocalization: NSString = NSBundle.mainBundle().preferredLocalizations[0] as NSString + let currentLocalization: NSString = Bundle.main.preferredLocalizations[0] as NSString // Only set it if we are using a different language than this apps development language - if let developmentLocalization = NSBundle.mainBundle().developmentLocalization { - if currentLocalization != developmentLocalization { + if let developmentLocalization = Bundle.main.developmentLocalization { + if currentLocalization as String != developmentLocalization { languageLabelText = currentLocalization as String - if let displayName = NSLocale(localeIdentifier: currentLocalization as String).displayNameForKey(NSLocaleIdentifier, value:currentLocalization) { + if let displayName = (Locale(identifier: currentLocalization as String) as NSLocale).displayName(forKey: NSLocale.Key.identifier, value:currentLocalization) { languageLabelText = "\(displayName): \(currentLocalization)" } } @@ -78,7 +78,7 @@ extension ViewController { resetAppReviewManager() // The AppID is the only required setup - Armchair.appID(Pages) + Armchair.appID(appID) // Debug means that it will popup on the next available change Armchair.debugEnabled(true) @@ -96,7 +96,7 @@ extension ViewController { resetAppReviewManager() // The AppID is the only required setup - Armchair.appID(Pages) + Armchair.appID(appID) // Debug means that it will popup on the next available change Armchair.debugEnabled(true) @@ -143,7 +143,7 @@ extension ViewController { Armchair.opensInStoreKit(false) // This sets a custom tint color (applies only to UIAlertController). - Armchair.tintColor(UIColor.brownColor()) + Armchair.tintColor(tintColor: UIColor.brown) #endif // This sets the Affiliate code you want to use, but is not required. @@ -193,7 +193,7 @@ extension ViewController { resetAppReviewManager() // The AppID is the only required setup - Armchair.appID(Pages) + Armchair.appID(appID) // Debug means that it will popup on the next available change Armchair.debugEnabled(true) @@ -216,11 +216,11 @@ extension ViewController { } @IBAction func openUrbanApps(_: AnyObject) { - if let url = NSURL(string: "http://urbanapps.com") { + if let url = URL(string: "http://urbanapps.com") { #if os(iOS) - UIApplication.sharedApplication().openURL(url) + UIApplication.shared.openURL(url) #elseif os(OSX) - NSWorkspace.sharedWorkspace().openURL(url) + NSWorkspace.shared.open(url) #else #endif } diff --git a/Mac Example.xcodeproj/project.pbxproj b/Mac Example.xcodeproj/project.pbxproj index db29f24..c70f4c0 100644 --- a/Mac Example.xcodeproj/project.pbxproj +++ b/Mac Example.xcodeproj/project.pbxproj @@ -33,13 +33,6 @@ remoteGlobalIDString = E6D8B8F919C756A4001AD043; remoteInfo = ArmchairMac; }; - E60FA80119C90D3500179D70 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E60FA7F719C90D3500179D70 /* Armchair.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = E6D8B92819C880A9001AD043; - remoteInfo = ArmchairTests; - }; E60FA80319C90D7100179D70 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = E60FA7F719C90D3500179D70 /* Armchair.xcodeproj */; @@ -135,7 +128,6 @@ E60FA80019C90D3500179D70 /* Armchair.framework */, E6F6156919C9FE8900C0B51C /* Armchair.bundle */, E6F6159819CA003600C0B51C /* Armchair.bundle */, - E60FA80219C90D3500179D70 /* ArmchairTests.xctest */, ); name = Products; sourceTree = ""; @@ -169,7 +161,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0700; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = Armchair; TargetAttributes = { E60FA7B919C908FE00179D70 = { @@ -216,13 +208,6 @@ remoteRef = E60FA7FF19C90D3500179D70 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - E60FA80219C90D3500179D70 /* ArmchairTests.xctest */ = { - isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = ArmchairTests.xctest; - remoteRef = E60FA80119C90D3500179D70 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; E6F6156919C9FE8900C0B51C /* Armchair.bundle */ = { isa = PBXReferenceProxy; fileType = wrapper.cfbundle; @@ -300,13 +285,21 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -315,6 +308,7 @@ ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -332,6 +326,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -343,13 +338,21 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -358,6 +361,7 @@ ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -367,6 +371,8 @@ MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.0; }; name = Release; }; diff --git a/README.md b/README.md index abbf2a4..6547c8e 100644 --- a/README.md +++ b/README.md @@ -284,6 +284,14 @@ Armchair.shouldPromptIfRated() -> Bool Armchair.shouldPromptIfRated(shouldPromptIfRated: Bool) ``` +The `useStoreKitReviewPrompt` configuration determines wether or not to try showing the SKStoreReviewController's requestReview() prompt instead of the default prompt. This setting has some effects only on iOS version >= 10.3. It's default value is `false`. +```swift +// GETTER +Armchair.useStoreKitReviewPrompt() -> Bool +// SETTER +Armchair.useStoreKitReviewPrompt(useStoreKitReviewPrompt: Bool) +``` + The `useMainAppBundleForLocalizations` configuration is a way to tell Armchair that you are providing your own translations for the review prompt popup strings. This may be because you are just customizing them, or that you have set your own text for the popup. If set to `true`, the main bundle will always be used to load localized strings. You have to include the translations either in a file called `ArmchairLocalizable.strings` or the standard `Localizable.strings`. If set to `false` Armchair will look in its own translation bundle for the translating strings. It's default value is `false`. ```swift diff --git a/Source/Armchair.swift b/Source/Armchair.swift index 0144014..e6820d4 100644 --- a/Source/Armchair.swift +++ b/Source/Armchair.swift @@ -69,18 +69,6 @@ public func reviewTitle(_ reviewTitle: String) { Manager.defaultManager.reviewTitle = reviewTitle } -/* - * If set to true, use SKStoreReviewController's requestReview() prompt instead of the default prompt. - * If not on iOS 10.3+, reort to the default prompt. - * Default => false. - */ -public func useStoreKitReviewPrompt() -> Bool { - return Manager.defaultManager.useStoreKitReviewPrompt -} -public func useStoreKitReviewPrompt(_ useStoreKitReviewPrompt: Bool) { - Manager.defaultManager.useStoreKitReviewPrompt = useStoreKitReviewPrompt -} - /* * Get/Set the message to use on the review prompt. * Default value is a localized @@ -255,7 +243,6 @@ public func shouldPromptIfRated(_ shouldPromptIfRated: Bool) { Manager.defaultManager.shouldPromptIfRated = shouldPromptIfRated } - /* * Return whether Armchair will try and present the Storekit review prompt (useful for custom dialog modification) */ @@ -300,6 +287,20 @@ public func affiliateCampaignCode(_ affiliateCampaignCode: String) { Manager.defaultManager.affiliateCampaignCode = affiliateCampaignCode } +#if os(iOS) + /* + * If set to true, use SKStoreReviewController's requestReview() prompt instead of the default prompt. + * If not on iOS 10.3+, reort to the default prompt. + * Default => false. + */ + public func useStoreKitReviewPrompt() -> Bool { + return Manager.defaultManager.useStoreKitReviewPrompt + } + public func useStoreKitReviewPrompt(_ useStoreKitReviewPrompt: Bool) { + Manager.defaultManager.useStoreKitReviewPrompt = useStoreKitReviewPrompt + } +#endif + /* * 'true' will show the Armchair alert everytime. Useful for testing * how your message looks and making sure the link to your app's review page works. @@ -768,7 +769,9 @@ open class Manager : ArmchairManager { // MARK: Review Alert & Properties #if os(iOS) - fileprivate let reviewURLTemplate = "itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&onlyLatestVersion=true&pageNumber=0&sortOrdering=1&id=APP_ID&at=AFFILIATE_CODE&ct=AFFILIATE_CAMPAIGN_CODE&action=write-review" + fileprivate var ratingAlert: UIAlertView? = nil + fileprivate let reviewURLTemplate = "itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&onlyLatestVersion=true&pageNumber=0&sortOrdering=1&id=APP_ID&at=AFFILIATE_CODE&ct=AFFILIATE_CAMPAIGN_CODE&action=write-review" + fileprivate let reviewURLTemplateiOS11 = "https://itunes.apple.com/us/app/idAPP_ID?ls=1&mt=8&at=AFFILIATE_CODE&ct=AFFILIATE_CAMPAIGN_CODE&action=write-review" #elseif os(OSX) private var ratingAlert: NSAlert? = nil private let reviewURLTemplate = "macappstore://itunes.apple.com/us/app/idAPP_ID?ls=1&mt=12&at=AFFILIATE_CODE&ct=AFFILIATE_CAMPAIGN_CODE" @@ -1252,7 +1255,7 @@ open class Manager : ArmchairManager { } else { /// Didn't show storekit prompt, present app store manually let alertView : UIAlertController = UIAlertController(title: reviewTitle, message: reviewMessage, preferredStyle: UIAlertControllerStyle.alert) - alertView.addAction(UIAlertAction(title: cancelButtonTitle, style:UIAlertActionStyle.cancel, handler: { + alertView.addAction(UIAlertAction(title: cancelButtonTitle, style:UIAlertActionStyle.default, handler: { (alert: UIAlertAction!) in self.dontRate() })) @@ -1262,15 +1265,15 @@ open class Manager : ArmchairManager { self.remindMeLater() })) } - alertView.addAction(UIAlertAction(title: rateButtonTitle, style:UIAlertActionStyle.default, handler: { + alertView.addAction(UIAlertAction(title: rateButtonTitle, style:UIAlertActionStyle.cancel, handler: { (alert: UIAlertAction!) in self._rateApp() })) // get the top most controller (= the StoreKit Controller) and dismiss it if let presentingController = UIApplication.shared.keyWindow?.rootViewController { - if let topController = topMostViewController(presentingController) { - topController.present(alertView, animated: usesAnimation) { [weak self] _ in + if let topController = Manager.topMostViewController(presentingController) { + topController.present(alertView, animated: usesAnimation) { [weak self] in if let closure = self?.didDisplayAlertClosure { closure() } @@ -1282,9 +1285,6 @@ open class Manager : ArmchairManager { } } - - - #elseif os(OSX) let alert: NSAlert = NSAlert() @@ -1297,14 +1297,14 @@ open class Manager : ArmchairManager { alert.addButton(withTitle: cancelButtonTitle) ratingAlert = alert - if let window = NSApplication.shared().keyWindow { + if let window = NSApplication.shared.keyWindow { alert.beginSheetModal(for: window) { - (response: NSModalResponse) in - self.handleNSAlert(returnCode: response) + (response: NSApplication.ModalResponse) in + self.handleNSAlertResponse(response) } } else { - let returnCode = alert.runModal() - handleNSAlert(returnCode:returnCode) + let response = alert.runModal() + handleNSAlertResponse(response) } if let closure = self.didDisplayAlertClosure { @@ -1336,7 +1336,7 @@ open class Manager : ArmchairManager { // get the top most controller (= the StoreKit Controller) and dismiss it if let presentingController = UIApplication.shared.keyWindow?.rootViewController { - if let topController = topMostViewController(presentingController) { + if let topController = Manager.topMostViewController(presentingController) { topController.dismiss(animated: usesAnimation) {} currentStatusBarStyle = UIStatusBarStyle.default } @@ -1349,24 +1349,24 @@ open class Manager : ArmchairManager { #elseif os(OSX) - private func handleNSAlert(returnCode: NSInteger) { - switch (returnCode) { - case NSAlertFirstButtonReturn: - // they want to rate it - _rateApp() - case NSAlertSecondButtonReturn: - // remind them later or cancel - if showsRemindButton() { - remindMeLater() - } else { - dontRate() - } - case NSAlertThirdButtonReturn: - // they don't want to rate it - dontRate() + private func handleNSAlertResponse(_ response: NSApplication.ModalResponse) { + switch (response) { + case .alertFirstButtonReturn: + // they want to rate it + _rateApp() + case .alertSecondButtonReturn: + // remind them later or cancel + if showsRemindButton() { + remindMeLater() + } else { + dontRate() + } + case .alertThirdButtonReturn: + // they don't want to rate it + dontRate() default: - return - } + return + } } #else @@ -1422,7 +1422,7 @@ open class Manager : ArmchairManager { } - if let rootController = getRootViewController() { + if let rootController = Manager.getRootViewController() { rootController.present(storeViewController, animated: usesAnimation) { self.modalPanelOpen = true @@ -1449,7 +1449,7 @@ open class Manager : ArmchairManager { #elseif os(OSX) if let url = URL(string: reviewURLString()) { - let opened = NSWorkspace.shared().open(url) + let opened = NSWorkspace.shared.open(url) if !opened { debugLog("Failed to open \(url)") } @@ -1460,7 +1460,12 @@ open class Manager : ArmchairManager { } fileprivate func reviewURLString() -> String { - let template = reviewURLTemplate + #if os(iOS) + let template = operatingSystemVersion >= 11 ? reviewURLTemplateiOS11 : reviewURLTemplate + #elseif os(OSX) + let template = reviewURLTemplate + #else + #endif var reviewURL = template.replacingOccurrences(of: "APP_ID", with: "\(appID)") reviewURL = reviewURL.replacingOccurrences(of: "AFFILIATE_CODE", with: "\(affiliateCode)") reviewURL = reviewURL.replacingOccurrences(of: "AFFILIATE_CAMPAIGN_CODE", with: "\(affiliateCampaignCode)") @@ -1689,7 +1694,7 @@ open class Manager : ArmchairManager { } #if os(iOS) - private func topMostViewController(_ controller: UIViewController?) -> UIViewController? { + private static func topMostViewController(_ controller: UIViewController?) -> UIViewController? { var isPresenting: Bool = false var topController: UIViewController? = controller repeat { @@ -1707,7 +1712,7 @@ open class Manager : ArmchairManager { return topController } - private func getRootViewController() -> UIViewController? { + private static func getRootViewController() -> UIViewController? { if var window = UIApplication.shared.keyWindow { if window.windowLevel != UIWindowLevelNormal { @@ -1722,32 +1727,40 @@ open class Manager : ArmchairManager { } } - for subView in window.subviews { - if let responder = subView.next { - if responder.isKind(of: UIViewController.self) { - return topMostViewController(responder as? UIViewController) - } - - } - } + return iterateSubViewsForViewController(window) } return nil } + + private static func iterateSubViewsForViewController(_ parentView: UIView) -> UIViewController? { + for subView in parentView.subviews { + if let responder = subView.next { + if responder.isKind(of: UIViewController.self) { + return topMostViewController(responder as? UIViewController) + } + } + + if let found = iterateSubViewsForViewController(subView) { + return found + } + } + + return nil + } + #endif - + private func hideRatingAlert() { #if os(OSX) if let alert = ratingAlert { debugLog("Hiding Alert") - if let window = NSApplication.shared().keyWindow { - if let parent = window.sheetParent { - parent.endSheet(window) - } + if let window = NSApplication.shared().keyWindow { + if let parent = window.sheetParent { + parent.endSheet(window) } + } ratingAlert = nil - - } #endif } @@ -1763,12 +1776,12 @@ open class Manager : ArmchairManager { // MARK: - // MARK: Notification Handlers - public func appWillResignActive(_ notification: Notification) { + @objc public func appWillResignActive(_ notification: Notification) { debugLog("appWillResignActive:") hideRatingAlert() } - public func applicationDidFinishLaunching(_ notification: Notification) { + @objc public func applicationDidFinishLaunching(_ notification: Notification) { DispatchQueue.global(qos: .background).async { self.debugLog("applicationDidFinishLaunching:") self.migrateKeysIfNecessary() @@ -1776,7 +1789,7 @@ open class Manager : ArmchairManager { } } - public func applicationWillEnterForeground(_ notification: Notification) { + @objc public func applicationWillEnterForeground(_ notification: Notification) { DispatchQueue.global(qos: .background).async { self.debugLog("applicationWillEnterForeground:") self.migrateKeysIfNecessary() @@ -1804,12 +1817,12 @@ open class Manager : ArmchairManager { fileprivate func setupNotifications() { #if os(iOS) NotificationCenter.default.addObserver(self, selector: #selector(Manager.appWillResignActive(_:)), name: NSNotification.Name.UIApplicationWillResignActive, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(UIApplicationDelegate.applicationDidFinishLaunching(_:)), name: NSNotification.Name.UIApplicationDidFinishLaunching, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(UIApplicationDelegate.applicationWillEnterForeground(_:)), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(Manager.applicationDidFinishLaunching(_:)), name: NSNotification.Name.UIApplicationDidFinishLaunching, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(Manager.applicationWillEnterForeground(_:)), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil) #elseif os(OSX) - NotificationCenter.default.addObserver(self, selector: #selector(Manager.appWillResignActive(_:)), name: NSNotification.Name.NSApplicationWillResignActive, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(NSApplicationDelegate.applicationDidFinishLaunching(_:)), name: NSNotification.Name.NSApplicationDidFinishLaunching, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(Manager.applicationWillEnterForeground(_:)), name: NSNotification.Name.NSApplicationWillBecomeActive, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(Manager.appWillResignActive(_:)), name: NSApplication.willResignActiveNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(Manager.applicationDidFinishLaunching(_:)), name: NSApplication.didFinishLaunchingNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(Manager.applicationWillEnterForeground(_:)), name: NSApplication.willBecomeActiveNotification, object: nil) #else #endif diff --git a/iOS Example.xcodeproj/project.pbxproj b/iOS Example.xcodeproj/project.pbxproj index c8cf15d..1d4c1c7 100644 --- a/iOS Example.xcodeproj/project.pbxproj +++ b/iOS Example.xcodeproj/project.pbxproj @@ -188,13 +188,13 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = Armchair; TargetAttributes = { F8111E0419A951050040E7D1 = { CreatedOnToolsVersion = 6.0; DevelopmentTeam = 9H3S97RP4K; - LastSwiftMigration = 0800; + LastSwiftMigration = 0830; }; }; }; @@ -327,14 +327,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -362,6 +368,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -374,14 +381,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -401,6 +414,7 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -422,7 +436,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.armchair.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "iOS Example"; PROVISIONING_PROFILE = ""; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -440,7 +454,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.armchair.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "iOS Example"; PROVISIONING_PROFILE = ""; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 4.0; }; name = Release; };