|  |  | //
 | 
						
						
						
							|  |  | //  iRate.m
 | 
						
						
						
							|  |  | //
 | 
						
						
						
							|  |  | //  Version 1.11.4
 | 
						
						
						
							|  |  | //
 | 
						
						
						
							|  |  | //  Created by Nick Lockwood on 26/01/2011.
 | 
						
						
						
							|  |  | //  Copyright 2011 Charcoal Design
 | 
						
						
						
							|  |  | //
 | 
						
						
						
							|  |  | //  Distributed under the permissive zlib license
 | 
						
						
						
							|  |  | //  Get the latest version from here:
 | 
						
						
						
							|  |  | //
 | 
						
						
						
							|  |  | //  https://github.com/nicklockwood/iRate
 | 
						
						
						
							|  |  | //
 | 
						
						
						
							|  |  | //  This software is provided 'as-is', without any express or implied
 | 
						
						
						
							|  |  | //  warranty.  In no event will the authors be held liable for any damages
 | 
						
						
						
							|  |  | //  arising from the use of this software.
 | 
						
						
						
							|  |  | //
 | 
						
						
						
							|  |  | //  Permission is granted to anyone to use this software for any purpose,
 | 
						
						
						
							|  |  | //  including commercial applications, and to alter it and redistribute it
 | 
						
						
						
							|  |  | //  freely, subject to the following restrictions:
 | 
						
						
						
							|  |  | //
 | 
						
						
						
							|  |  | //  1. The origin of this software must not be misrepresented; you must not
 | 
						
						
						
							|  |  | //  claim that you wrote the original software. If you use this software
 | 
						
						
						
							|  |  | //  in a product, an acknowledgment in the product documentation would be
 | 
						
						
						
							|  |  | //  appreciated but is not required.
 | 
						
						
						
							|  |  | //
 | 
						
						
						
							|  |  | //  2. Altered source versions must be plainly marked as such, and must not be
 | 
						
						
						
							|  |  | //  misrepresented as being the original software.
 | 
						
						
						
							|  |  | //
 | 
						
						
						
							|  |  | //  3. This notice may not be removed or altered from any source distribution.
 | 
						
						
						
							|  |  | //
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #import "iRate.h"
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #import <Availability.h>
 | 
						
						
						
							|  |  | #if !__has_feature(objc_arc)
 | 
						
						
						
							|  |  | #error This class requires automatic reference counting
 | 
						
						
						
							|  |  | #endif
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | // Unknown diagnostic
 | 
						
						
						
							|  |  | // #pragma clang diagnostic ignored "-Wreceiver-is-weak"
 | 
						
						
						
							|  |  | #pragma clang diagnostic ignored "-Warc-repeated-use-of-weak"
 | 
						
						
						
							|  |  | #pragma clang diagnostic ignored "-Wobjc-missing-property-synthesis"
 | 
						
						
						
							|  |  | #pragma clang diagnostic ignored "-Wdirect-ivar-access"
 | 
						
						
						
							|  |  | #pragma clang diagnostic ignored "-Wunused-macros"
 | 
						
						
						
							|  |  | #pragma clang diagnostic ignored "-Wconversion"
 | 
						
						
						
							|  |  | #pragma clang diagnostic ignored "-Wformat-nonliteral"
 | 
						
						
						
							|  |  | #pragma clang diagnostic ignored "-Wselector"
 | 
						
						
						
							|  |  | #pragma clang diagnostic ignored "-Wgnu"
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | NSUInteger const iRateAppStoreGameGenreID = 6014;
 | 
						
						
						
							|  |  | NSString *const iRateErrorDomain          = @"iRateErrorDomain";
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | NSString *const iRateMessageTitleKey  = @"iRateMessageTitle";
 | 
						
						
						
							|  |  | NSString *const iRateAppMessageKey    = @"iRateAppMessage";
 | 
						
						
						
							|  |  | NSString *const iRateGameMessageKey   = @"iRateGameMessage";
 | 
						
						
						
							|  |  | NSString *const iRateUpdateMessageKey = @"iRateUpdateMessage";
 | 
						
						
						
							|  |  | NSString *const iRateCancelButtonKey  = @"iRateCancelButton";
 | 
						
						
						
							|  |  | NSString *const iRateRemindButtonKey  = @"iRateRemindButton";
 | 
						
						
						
							|  |  | NSString *const iRateRateButtonKey    = @"iRateRateButton";
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | NSString *const iRateCouldNotConnectToAppStore       = @"iRateCouldNotConnectToAppStore";
 | 
						
						
						
							|  |  | NSString *const iRateDidDetectAppUpdate              = @"iRateDidDetectAppUpdate";
 | 
						
						
						
							|  |  | NSString *const iRateDidPromptForRating              = @"iRateDidPromptForRating";
 | 
						
						
						
							|  |  | NSString *const iRateUserDidAttemptToRateApp         = @"iRateUserDidAttemptToRateApp";
 | 
						
						
						
							|  |  | NSString *const iRateUserDidDeclineToRateApp         = @"iRateUserDidDeclineToRateApp";
 | 
						
						
						
							|  |  | NSString *const iRateUserDidRequestReminderToRateApp = @"iRateUserDidRequestReminderToRateApp";
 | 
						
						
						
							|  |  | NSString *const iRateDidOpenAppStore                 = @"iRateDidOpenAppStore";
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | static NSString *const iRateAppStoreIDKey      = @"iRateAppStoreID";
 | 
						
						
						
							|  |  | static NSString *const iRateRatedVersionKey    = @"iRateRatedVersionChecked";
 | 
						
						
						
							|  |  | static NSString *const iRateDeclinedVersionKey = @"iRateDeclinedVersion";
 | 
						
						
						
							|  |  | static NSString *const iRateLastRemindedKey    = @"iRateLastReminded";
 | 
						
						
						
							|  |  | static NSString *const iRateLastVersionUsedKey = @"iRateLastVersionUsed";
 | 
						
						
						
							|  |  | static NSString *const iRateFirstUsedKey       = @"iRateFirstUsed";
 | 
						
						
						
							|  |  | static NSString *const iRateUseCountKey        = @"iRateUseCount";
 | 
						
						
						
							|  |  | static NSString *const iRateEventCountKey      = @"iRateEventCount";
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | static NSString *const iRateMacAppStoreBundleID = @"com.apple.appstore";
 | 
						
						
						
							|  |  | static NSString *const iRateAppLookupURLFormat  = @"https://itunes.apple.com/%@/lookup";
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | static NSString *const iRateiOSAppStoreURLScheme = @"itms-apps";
 | 
						
						
						
							|  |  | static NSString *const iRateiOSAppStoreURLFormat = @"itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/"
 | 
						
						
						
							|  |  |                                                    @"viewContentsUserReviews?type=Purple+Software&id=%@&pageNumber=0&"
 | 
						
						
						
							|  |  |                                                    @"sortOrdering=2&mt=8";
 | 
						
						
						
							|  |  | static NSString *const iRateiOS7AppStoreURLFormat = @"itms-apps://itunes.apple.com/app/id%@";
 | 
						
						
						
							|  |  | static NSString *const iRateMacAppStoreURLFormat  = @"macappstore://itunes.apple.com/app/id%@";
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #define SECONDS_IN_A_DAY 86400.0
 | 
						
						
						
							|  |  | #define SECONDS_IN_A_WEEK 604800.0
 | 
						
						
						
							|  |  | #define MAC_APP_STORE_REFRESH_DELAY 5.0
 | 
						
						
						
							|  |  | #define REQUEST_TIMEOUT 60.0
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | @implementation NSObject (iRate)
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)iRateCouldNotConnectToAppStore:(__unused NSError *)error {
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | - (void)iRateDidDetectAppUpdate {
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | - (BOOL)iRateShouldPromptForRating {
 | 
						
						
						
							|  |  |     return YES;
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | - (void)iRateDidPromptForRating {
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | - (void)iRateUserDidAttemptToRateApp {
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | - (void)iRateUserDidDeclineToRateApp {
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | - (void)iRateUserDidRequestReminderToRateApp {
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | - (BOOL)iRateShouldOpenAppStore {
 | 
						
						
						
							|  |  |     return YES;
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | - (void)iRateDidOpenAppStore {
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | @end
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | @interface iRate ()
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | @property (nonatomic, strong) id visibleAlert;
 | 
						
						
						
							|  |  | @property (nonatomic, assign) BOOL checkingForPrompt;
 | 
						
						
						
							|  |  | @property (nonatomic, assign) BOOL checkingForAppStoreID;
 | 
						
						
						
							|  |  | @property (nonatomic, assign) BOOL shouldPreventPromptAtNextTest;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | @end
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | @implementation iRate
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | // SIGNAL HACK
 | 
						
						
						
							|  |  | // Disabled in Signal. We don't want to prompt users who haven't registered, even if it has been
 | 
						
						
						
							|  |  | // a while since they installed. ~mjk
 | 
						
						
						
							|  |  | //+ (void)load {
 | 
						
						
						
							|  |  | //    [self performSelectorOnMainThread:@selector(sharedInstance) withObject:nil waitUntilDone:NO];
 | 
						
						
						
							|  |  | //}
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | + (instancetype)sharedInstance {
 | 
						
						
						
							|  |  |     static iRate *sharedInstance = nil;
 | 
						
						
						
							|  |  |     if (sharedInstance == nil) {
 | 
						
						
						
							|  |  |         sharedInstance = [(iRate *)[self alloc] init];
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  |     return sharedInstance;
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (NSString *)localizedStringForKey:(NSString *)key withDefault:(NSString *)defaultString {
 | 
						
						
						
							|  |  |     static NSBundle *bundle = nil;
 | 
						
						
						
							|  |  |     if (bundle == nil) {
 | 
						
						
						
							|  |  |         NSString *bundlePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"iRate" ofType:@"bundle"];
 | 
						
						
						
							|  |  |         if (self.useAllAvailableLanguages) {
 | 
						
						
						
							|  |  |             bundle             = [NSBundle bundleWithPath:bundlePath];
 | 
						
						
						
							|  |  |             NSString *language = [[NSLocale preferredLanguages] count] ? [NSLocale preferredLanguages][0] : @"en";
 | 
						
						
						
							|  |  |             if (![[bundle localizations] containsObject:language]) {
 | 
						
						
						
							|  |  |                 language = [language componentsSeparatedByString:@"-"][0];
 | 
						
						
						
							|  |  |             }
 | 
						
						
						
							|  |  |             if ([[bundle localizations] containsObject:language]) {
 | 
						
						
						
							|  |  |                 bundlePath = [bundle pathForResource:language ofType:@"lproj"];
 | 
						
						
						
							|  |  |             }
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  |         bundle = [NSBundle bundleWithPath:bundlePath] ?: [NSBundle mainBundle];
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  |     defaultString = [bundle localizedStringForKey:key value:defaultString table:nil];
 | 
						
						
						
							|  |  |     return [[NSBundle mainBundle] localizedStringForKey:key value:defaultString table:nil];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (iRate *)init {
 | 
						
						
						
							|  |  |     if ((self = [super init])) {
 | 
						
						
						
							|  |  | #if TARGET_OS_IPHONE
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         // register for iphone application events
 | 
						
						
						
							|  |  |         if (&UIApplicationWillEnterForegroundNotification) {
 | 
						
						
						
							|  |  |             [[NSNotificationCenter defaultCenter] addObserver:self
 | 
						
						
						
							|  |  |                                                      selector:@selector(applicationWillEnterForeground)
 | 
						
						
						
							|  |  |                                                          name:UIApplicationWillEnterForegroundNotification
 | 
						
						
						
							|  |  |                                                        object:nil];
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #endif
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         // get country
 | 
						
						
						
							|  |  |         self.appStoreCountry = [(NSLocale *)[NSLocale currentLocale] objectForKey:NSLocaleCountryCode];
 | 
						
						
						
							|  |  |         if ([self.appStoreCountry isEqualToString:@"150"]) {
 | 
						
						
						
							|  |  |             self.appStoreCountry = @"eu";
 | 
						
						
						
							|  |  |         } else if (!self.appStoreCountry ||
 | 
						
						
						
							|  |  |                    [[self.appStoreCountry stringByReplacingOccurrencesOfString:@"[A-Za-z]{2}"
 | 
						
						
						
							|  |  |                                                                     withString:@""
 | 
						
						
						
							|  |  |                                                                        options:NSRegularExpressionSearch
 | 
						
						
						
							|  |  |                                                                          range:NSMakeRange(0, 2)] length]) {
 | 
						
						
						
							|  |  |             self.appStoreCountry = @"us";
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         // application version (use short version preferentially)
 | 
						
						
						
							|  |  |         self.applicationVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
 | 
						
						
						
							|  |  |         if ([self.applicationVersion length] == 0) {
 | 
						
						
						
							|  |  |             self.applicationVersion =
 | 
						
						
						
							|  |  |                 [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         // localised application name
 | 
						
						
						
							|  |  |         self.applicationName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
 | 
						
						
						
							|  |  |         if ([self.applicationName length] == 0) {
 | 
						
						
						
							|  |  |             self.applicationName = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleNameKey];
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         // bundle id
 | 
						
						
						
							|  |  |         self.applicationBundleID = [[NSBundle mainBundle] bundleIdentifier];
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         // default settings
 | 
						
						
						
							|  |  |         self.useAllAvailableLanguages          = YES;
 | 
						
						
						
							|  |  |         self.promptForNewVersionIfUserRated    = NO;
 | 
						
						
						
							|  |  |         self.onlyPromptIfLatestVersion         = YES;
 | 
						
						
						
							|  |  |         self.onlyPromptIfMainWindowIsAvailable = YES;
 | 
						
						
						
							|  |  |         self.promptAtLaunch                    = YES;
 | 
						
						
						
							|  |  |         self.usesUntilPrompt                   = 10;
 | 
						
						
						
							|  |  |         self.eventsUntilPrompt                 = 10;
 | 
						
						
						
							|  |  |         self.daysUntilPrompt                   = 10.0f;
 | 
						
						
						
							|  |  |         self.usesPerWeekForPrompt              = 0.0f;
 | 
						
						
						
							|  |  |         self.remindPeriod                      = 1.0f;
 | 
						
						
						
							|  |  |         self.verboseLogging                    = NO;
 | 
						
						
						
							|  |  |         self.previewMode                       = NO;
 | 
						
						
						
							|  |  |         self.shouldPreventPromptAtNextTest     = NO;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #if DEBUG
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         // enable verbose logging in debug mode
 | 
						
						
						
							|  |  |         self.verboseLogging = YES;
 | 
						
						
						
							|  |  |         NSLog(@"iRate verbose logging enabled.");
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #endif
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         // app launched
 | 
						
						
						
							|  |  |         [self performSelectorOnMainThread:@selector(applicationLaunched) withObject:nil waitUntilDone:NO];
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  |     return self;
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (id<iRateDelegate>)delegate {
 | 
						
						
						
							|  |  |     if (_delegate == nil) {
 | 
						
						
						
							|  |  | #if TARGET_OS_IPHONE
 | 
						
						
						
							|  |  | #define APP_CLASS UIApplication
 | 
						
						
						
							|  |  | #else
 | 
						
						
						
							|  |  | #define APP_CLASS NSApplication
 | 
						
						
						
							|  |  | #endif
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         _delegate = (id<iRateDelegate>)[[APP_CLASS sharedApplication] delegate];
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  |     return _delegate;
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (NSString *)messageTitle {
 | 
						
						
						
							|  |  |     return [_messageTitle ?: [self localizedStringForKey:iRateMessageTitleKey withDefault:@"Rate %@"]
 | 
						
						
						
							|  |  |         stringByReplacingOccurrencesOfString:@"%@"
 | 
						
						
						
							|  |  |                                   withString:self.applicationName];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (NSString *)message {
 | 
						
						
						
							|  |  |     NSString *message = _message;
 | 
						
						
						
							|  |  |     if (!message) {
 | 
						
						
						
							|  |  |         message = (self.appStoreGenreID == iRateAppStoreGameGenreID)
 | 
						
						
						
							|  |  |                       ? [self localizedStringForKey:iRateGameMessageKey
 | 
						
						
						
							|  |  |                                         withDefault:@"If you enjoy playing %@, would you mind taking a moment to rate "
 | 
						
						
						
							|  |  |                                                     @"it? It won’t take more than a minute. Thanks for your support!"]
 | 
						
						
						
							|  |  |                       : [self localizedStringForKey:iRateAppMessageKey
 | 
						
						
						
							|  |  |                                         withDefault:@"If you enjoy using %@, would you mind taking a moment to rate "
 | 
						
						
						
							|  |  |                                                     @"it? It won’t take more than a minute. Thanks for your support!"];
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  |     return [message stringByReplacingOccurrencesOfString:@"%@" withString:self.applicationName];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (NSString *)updateMessage {
 | 
						
						
						
							|  |  |     NSString *updateMessage = _updateMessage;
 | 
						
						
						
							|  |  |     if (!updateMessage) {
 | 
						
						
						
							|  |  |         updateMessage = [self localizedStringForKey:iRateUpdateMessageKey withDefault:self.message];
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  |     return [updateMessage stringByReplacingOccurrencesOfString:@"%@" withString:self.applicationName];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (NSString *)cancelButtonLabel {
 | 
						
						
						
							|  |  |     return _cancelButtonLabel ?: [self localizedStringForKey:iRateCancelButtonKey withDefault:@"No, Thanks"];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (NSString *)rateButtonLabel {
 | 
						
						
						
							|  |  |     return _rateButtonLabel ?: [self localizedStringForKey:iRateRateButtonKey withDefault:@"Rate It Now"];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (NSString *)remindButtonLabel {
 | 
						
						
						
							|  |  |     return _remindButtonLabel ?: [self localizedStringForKey:iRateRemindButtonKey withDefault:@"Remind Me Later"];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (NSURL *)ratingsURL {
 | 
						
						
						
							|  |  |     if (_ratingsURL) {
 | 
						
						
						
							|  |  |         return _ratingsURL;
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     if (!self.appStoreID && self.verboseLogging) {
 | 
						
						
						
							|  |  |         NSLog(@"iRate could not find the App Store ID for this application. If the application is not intended for App "
 | 
						
						
						
							|  |  |               @"Store release then you must specify a custom ratingsURL.");
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     NSString *URLString;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #if TARGET_OS_IPHONE
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     float iOSVersion = [[UIDevice currentDevice].systemVersion floatValue];
 | 
						
						
						
							|  |  |     if (iOSVersion >= 7.0f && iOSVersion < 7.1f) {
 | 
						
						
						
							|  |  |         URLString = iRateiOS7AppStoreURLFormat;
 | 
						
						
						
							|  |  |     } else {
 | 
						
						
						
							|  |  |         URLString = iRateiOSAppStoreURLFormat;
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #else
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     URLString = iRateMacAppStoreURLFormat;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #endif
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     return [NSURL URLWithString:[NSString stringWithFormat:URLString, @(self.appStoreID)]];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (NSUInteger)appStoreID {
 | 
						
						
						
							|  |  |     return _appStoreID
 | 
						
						
						
							|  |  |                ?: [[[NSUserDefaults standardUserDefaults] objectForKey:iRateAppStoreIDKey] unsignedIntegerValue];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (NSDate *)firstUsed {
 | 
						
						
						
							|  |  |     return [[NSUserDefaults standardUserDefaults] objectForKey:iRateFirstUsedKey];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)setFirstUsed:(NSDate *)date {
 | 
						
						
						
							|  |  |     [[NSUserDefaults standardUserDefaults] setObject:date forKey:iRateFirstUsedKey];
 | 
						
						
						
							|  |  |     [[NSUserDefaults standardUserDefaults] synchronize];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (NSDate *)lastReminded {
 | 
						
						
						
							|  |  |     return [[NSUserDefaults standardUserDefaults] objectForKey:iRateLastRemindedKey];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)setLastReminded:(NSDate *)date {
 | 
						
						
						
							|  |  |     [[NSUserDefaults standardUserDefaults] setObject:date forKey:iRateLastRemindedKey];
 | 
						
						
						
							|  |  |     [[NSUserDefaults standardUserDefaults] synchronize];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (NSUInteger)usesCount {
 | 
						
						
						
							|  |  |     return [[NSUserDefaults standardUserDefaults] integerForKey:iRateUseCountKey];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)setUsesCount:(NSUInteger)count {
 | 
						
						
						
							|  |  |     [[NSUserDefaults standardUserDefaults] setInteger:(NSInteger)count forKey:iRateUseCountKey];
 | 
						
						
						
							|  |  |     [[NSUserDefaults standardUserDefaults] synchronize];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (NSUInteger)eventCount {
 | 
						
						
						
							|  |  |     return [[NSUserDefaults standardUserDefaults] integerForKey:iRateEventCountKey];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)setEventCount:(NSUInteger)count {
 | 
						
						
						
							|  |  |     [[NSUserDefaults standardUserDefaults] setInteger:(NSInteger)count forKey:iRateEventCountKey];
 | 
						
						
						
							|  |  |     [[NSUserDefaults standardUserDefaults] synchronize];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (float)usesPerWeek {
 | 
						
						
						
							|  |  |     return (float)self.usesCount / ([[NSDate date] timeIntervalSinceDate:self.firstUsed] / SECONDS_IN_A_WEEK);
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (BOOL)declinedThisVersion {
 | 
						
						
						
							|  |  |     return [[[NSUserDefaults standardUserDefaults] objectForKey:iRateDeclinedVersionKey]
 | 
						
						
						
							|  |  |         isEqualToString:self.applicationVersion];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)setDeclinedThisVersion:(BOOL)declined {
 | 
						
						
						
							|  |  |     [[NSUserDefaults standardUserDefaults] setObject:(declined ? self.applicationVersion : nil)
 | 
						
						
						
							|  |  |                                               forKey:iRateDeclinedVersionKey];
 | 
						
						
						
							|  |  |     [[NSUserDefaults standardUserDefaults] synchronize];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (BOOL)declinedAnyVersion {
 | 
						
						
						
							|  |  |     return [(NSString *)[[NSUserDefaults standardUserDefaults] objectForKey:iRateDeclinedVersionKey] length] != 0;
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (BOOL)ratedVersion:(NSString *)version {
 | 
						
						
						
							|  |  |     return [[[NSUserDefaults standardUserDefaults] objectForKey:iRateRatedVersionKey] isEqualToString:version];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (BOOL)ratedThisVersion {
 | 
						
						
						
							|  |  |     return [self ratedVersion:self.applicationVersion];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)setRatedThisVersion:(BOOL)rated {
 | 
						
						
						
							|  |  |     [[NSUserDefaults standardUserDefaults] setObject:(rated ? self.applicationVersion : nil)
 | 
						
						
						
							|  |  |                                               forKey:iRateRatedVersionKey];
 | 
						
						
						
							|  |  |     [[NSUserDefaults standardUserDefaults] synchronize];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (BOOL)ratedAnyVersion {
 | 
						
						
						
							|  |  |     return [(NSString *)[[NSUserDefaults standardUserDefaults] objectForKey:iRateRatedVersionKey] length] != 0;
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)dealloc {
 | 
						
						
						
							|  |  |     [[NSNotificationCenter defaultCenter] removeObserver:self];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)preventPromptAtNextTest {
 | 
						
						
						
							|  |  |     self.shouldPreventPromptAtNextTest = YES;
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)incrementUseCount {
 | 
						
						
						
							|  |  |     self.usesCount++;
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)incrementEventCount {
 | 
						
						
						
							|  |  |     self.eventCount++;
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (BOOL)shouldPromptForRating {
 | 
						
						
						
							|  |  |     // Avoid potentially inconvenient prompt
 | 
						
						
						
							|  |  |     if (self.shouldPreventPromptAtNextTest)
 | 
						
						
						
							|  |  |     {
 | 
						
						
						
							|  |  |         NSLog(@"iRate did not prompt for rating because it is potentially inconvenient");
 | 
						
						
						
							|  |  |         self.shouldPreventPromptAtNextTest = NO;
 | 
						
						
						
							|  |  |         return NO;
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     // preview mode?
 | 
						
						
						
							|  |  |     if (self.previewMode) {
 | 
						
						
						
							|  |  |         NSLog(@"iRate preview mode is enabled - make sure you disable this for release");
 | 
						
						
						
							|  |  |         return YES;
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     // check if we've rated this version
 | 
						
						
						
							|  |  |     else if (self.ratedThisVersion) {
 | 
						
						
						
							|  |  |         if (self.verboseLogging) {
 | 
						
						
						
							|  |  |             NSLog(@"iRate did not prompt for rating because the user has already rated this version");
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  |         return NO;
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     // check if we've rated any version
 | 
						
						
						
							|  |  |     else if (self.ratedAnyVersion && !self.promptForNewVersionIfUserRated) {
 | 
						
						
						
							|  |  |         if (self.verboseLogging) {
 | 
						
						
						
							|  |  |             NSLog(@"iRate did not prompt for rating because the user has already rated this app, and "
 | 
						
						
						
							|  |  |                   @"promptForNewVersionIfUserRated is disabled");
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  |         return NO;
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     // check if we've declined to rate the app
 | 
						
						
						
							|  |  |     else if (self.declinedAnyVersion) {
 | 
						
						
						
							|  |  |         if (self.verboseLogging) {
 | 
						
						
						
							|  |  |             NSLog(@"iRate did not prompt for rating because the user has declined to rate the app");
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  |         return NO;
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     // check how long we've been using this version
 | 
						
						
						
							|  |  |     else if ([[NSDate date] timeIntervalSinceDate:self.firstUsed] < self.daysUntilPrompt * SECONDS_IN_A_DAY) {
 | 
						
						
						
							|  |  |         if (self.verboseLogging) {
 | 
						
						
						
							|  |  |             NSLog(@"iRate did not prompt for rating because the app was first used less than %g days ago",
 | 
						
						
						
							|  |  |                   self.daysUntilPrompt);
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  |         return NO;
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     // check how many times we've used it and the number of significant events
 | 
						
						
						
							|  |  |     else if (self.usesCount < self.usesUntilPrompt && self.eventCount < self.eventsUntilPrompt) {
 | 
						
						
						
							|  |  |         if (self.verboseLogging) {
 | 
						
						
						
							|  |  |             NSLog(@"iRate did not prompt for rating because the app has only been used %@ times and only %@ events "
 | 
						
						
						
							|  |  |                   @"have been logged",
 | 
						
						
						
							|  |  |                   @(self.usesCount),
 | 
						
						
						
							|  |  |                   @(self.eventCount));
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  |         return NO;
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     // check if usage frequency is high enough
 | 
						
						
						
							|  |  |     else if (self.usesPerWeek < self.usesPerWeekForPrompt) {
 | 
						
						
						
							|  |  |         if (self.verboseLogging) {
 | 
						
						
						
							|  |  |             NSLog(@"iRate did not prompt for rating because the app has only been used %g times per week on average "
 | 
						
						
						
							|  |  |                   @"since it was installed",
 | 
						
						
						
							|  |  |                   self.usesPerWeek);
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  |         return NO;
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     // check if within the reminder period
 | 
						
						
						
							|  |  |     else if (self.lastReminded != nil &&
 | 
						
						
						
							|  |  |              [[NSDate date] timeIntervalSinceDate:self.lastReminded] < self.remindPeriod * SECONDS_IN_A_DAY) {
 | 
						
						
						
							|  |  |         if (self.verboseLogging) {
 | 
						
						
						
							|  |  |             NSLog(@"iRate did not prompt for rating because the user last asked to be reminded less than %g days ago",
 | 
						
						
						
							|  |  |                   self.remindPeriod);
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  |         return NO;
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     // lets prompt!
 | 
						
						
						
							|  |  |     return YES;
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (NSString *)valueForKey:(NSString *)key inJSON:(id)json {
 | 
						
						
						
							|  |  |     if ([json isKindOfClass:[NSString class]]) {
 | 
						
						
						
							|  |  |         // use legacy parser
 | 
						
						
						
							|  |  |         NSRange keyRange = [json rangeOfString:[NSString stringWithFormat:@"\"%@\"", key]];
 | 
						
						
						
							|  |  |         if (keyRange.location != NSNotFound) {
 | 
						
						
						
							|  |  |             NSInteger start    = keyRange.location + keyRange.length;
 | 
						
						
						
							|  |  |             NSRange valueStart = [json rangeOfString:@":"
 | 
						
						
						
							|  |  |                                              options:(NSStringCompareOptions)0
 | 
						
						
						
							|  |  |                                                range:NSMakeRange(start, [(NSString *)json length] - start)];
 | 
						
						
						
							|  |  |             if (valueStart.location != NSNotFound) {
 | 
						
						
						
							|  |  |                 start            = valueStart.location + 1;
 | 
						
						
						
							|  |  |                 NSRange valueEnd = [json rangeOfString:@","
 | 
						
						
						
							|  |  |                                                options:(NSStringCompareOptions)0
 | 
						
						
						
							|  |  |                                                  range:NSMakeRange(start, [(NSString *)json length] - start)];
 | 
						
						
						
							|  |  |                 if (valueEnd.location != NSNotFound) {
 | 
						
						
						
							|  |  |                     NSString *value = [json substringWithRange:NSMakeRange(start, valueEnd.location - start)];
 | 
						
						
						
							|  |  |                     value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
 | 
						
						
						
							|  |  |                     while ([value hasPrefix:@"\""] && ![value hasSuffix:@"\""]) {
 | 
						
						
						
							|  |  |                         if (valueEnd.location == NSNotFound) {
 | 
						
						
						
							|  |  |                             break;
 | 
						
						
						
							|  |  |                         }
 | 
						
						
						
							|  |  |                         NSInteger newStart = valueEnd.location + 1;
 | 
						
						
						
							|  |  |                         valueEnd           = [json rangeOfString:@","
 | 
						
						
						
							|  |  |                                                options:(NSStringCompareOptions)0
 | 
						
						
						
							|  |  |                                                  range:NSMakeRange(newStart, [(NSString *)json length] - newStart)];
 | 
						
						
						
							|  |  |                         value = [json substringWithRange:NSMakeRange(start, valueEnd.location - start)];
 | 
						
						
						
							|  |  |                         value =
 | 
						
						
						
							|  |  |                             [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
 | 
						
						
						
							|  |  |                     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |                     value = [value
 | 
						
						
						
							|  |  |                         stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"\""]];
 | 
						
						
						
							|  |  |                     value = [value stringByReplacingOccurrencesOfString:@"\\\\" withString:@"\\"];
 | 
						
						
						
							|  |  |                     value = [value stringByReplacingOccurrencesOfString:@"\\/" withString:@"/"];
 | 
						
						
						
							|  |  |                     value = [value stringByReplacingOccurrencesOfString:@"\\\"" withString:@"\""];
 | 
						
						
						
							|  |  |                     value = [value stringByReplacingOccurrencesOfString:@"\\n" withString:@"\n"];
 | 
						
						
						
							|  |  |                     value = [value stringByReplacingOccurrencesOfString:@"\\r" withString:@"\r"];
 | 
						
						
						
							|  |  |                     value = [value stringByReplacingOccurrencesOfString:@"\\t" withString:@"\t"];
 | 
						
						
						
							|  |  |                     value = [value stringByReplacingOccurrencesOfString:@"\\f" withString:@"\f"];
 | 
						
						
						
							|  |  |                     value = [value stringByReplacingOccurrencesOfString:@"\\b" withString:@"\f"];
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |                     while (YES) {
 | 
						
						
						
							|  |  |                         NSRange unicode = [value rangeOfString:@"\\u"];
 | 
						
						
						
							|  |  |                         if (unicode.location == NSNotFound || unicode.location + unicode.length == 0) {
 | 
						
						
						
							|  |  |                             break;
 | 
						
						
						
							|  |  |                         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |                         uint32_t c         = 0;
 | 
						
						
						
							|  |  |                         NSString *hex      = [value substringWithRange:NSMakeRange(unicode.location + 2, 4)];
 | 
						
						
						
							|  |  |                         NSScanner *scanner = [NSScanner scannerWithString:hex];
 | 
						
						
						
							|  |  |                         [scanner scanHexInt:&c];
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |                         if (c <= 0xffff) {
 | 
						
						
						
							|  |  |                             value = [value
 | 
						
						
						
							|  |  |                                 stringByReplacingCharactersInRange:NSMakeRange(unicode.location, 6)
 | 
						
						
						
							|  |  |                                                         withString:[NSString stringWithFormat:@"%C", (unichar)c]];
 | 
						
						
						
							|  |  |                         } else {
 | 
						
						
						
							|  |  |                             // convert character to surrogate pair
 | 
						
						
						
							|  |  |                             uint16_t x   = (uint16_t)c;
 | 
						
						
						
							|  |  |                             uint16_t u   = (c >> 16) & ((1 << 5) - 1);
 | 
						
						
						
							|  |  |                             uint16_t w   = (uint16_t)u - 1;
 | 
						
						
						
							|  |  |                             unichar high = 0xd800 | (w << 6) | x >> 10;
 | 
						
						
						
							|  |  |                             unichar low  = (uint16_t)(0xdc00 | (x & ((1 << 10) - 1)));
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |                             value = [value
 | 
						
						
						
							|  |  |                                 stringByReplacingCharactersInRange:NSMakeRange(unicode.location, 6)
 | 
						
						
						
							|  |  |                                                         withString:[NSString stringWithFormat:@"%C%C", high, low]];
 | 
						
						
						
							|  |  |                         }
 | 
						
						
						
							|  |  |                     }
 | 
						
						
						
							|  |  |                     return value;
 | 
						
						
						
							|  |  |                 }
 | 
						
						
						
							|  |  |             }
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  |     } else {
 | 
						
						
						
							|  |  |         return json[key];
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  |     return nil;
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)setAppStoreIDOnMainThread:(NSString *)appStoreIDString {
 | 
						
						
						
							|  |  |     _appStoreID = [appStoreIDString integerValue];
 | 
						
						
						
							|  |  |     [[NSUserDefaults standardUserDefaults] setInteger:_appStoreID forKey:iRateAppStoreIDKey];
 | 
						
						
						
							|  |  |     [[NSUserDefaults standardUserDefaults] synchronize];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)connectionSucceeded {
 | 
						
						
						
							|  |  |     if (self.checkingForAppStoreID) {
 | 
						
						
						
							|  |  |         // no longer checking
 | 
						
						
						
							|  |  |         self.checkingForPrompt     = NO;
 | 
						
						
						
							|  |  |         self.checkingForAppStoreID = NO;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         // open app store
 | 
						
						
						
							|  |  |         [self openRatingsPageInAppStore];
 | 
						
						
						
							|  |  |     } else if (self.checkingForPrompt) {
 | 
						
						
						
							|  |  |         // no longer checking
 | 
						
						
						
							|  |  |         self.checkingForPrompt = NO;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         // confirm with delegate
 | 
						
						
						
							|  |  |         if (![self.delegate iRateShouldPromptForRating]) {
 | 
						
						
						
							|  |  |             if (self.verboseLogging) {
 | 
						
						
						
							|  |  |                 NSLog(@"iRate did not display the rating prompt because the iRateShouldPromptForRating delegate method "
 | 
						
						
						
							|  |  |                       @"returned NO");
 | 
						
						
						
							|  |  |             }
 | 
						
						
						
							|  |  |             return;
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         // prompt user
 | 
						
						
						
							|  |  |         [self promptForRating];
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)connectionError:(NSError *)error {
 | 
						
						
						
							|  |  |     if (self.checkingForPrompt || self.checkingForAppStoreID) {
 | 
						
						
						
							|  |  |         // no longer checking
 | 
						
						
						
							|  |  |         self.checkingForPrompt     = NO;
 | 
						
						
						
							|  |  |         self.checkingForAppStoreID = NO;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         // log the error
 | 
						
						
						
							|  |  |         if (error) {
 | 
						
						
						
							|  |  |             NSLog(@"iRate rating process failed because: %@", [error localizedDescription]);
 | 
						
						
						
							|  |  |         } else {
 | 
						
						
						
							|  |  |             NSLog(@"iRate rating process failed because an unknown error occured");
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         // could not connect
 | 
						
						
						
							|  |  |         [self.delegate iRateCouldNotConnectToAppStore:error];
 | 
						
						
						
							|  |  |         [[NSNotificationCenter defaultCenter] postNotificationName:iRateCouldNotConnectToAppStore object:error];
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)checkForConnectivityInBackground {
 | 
						
						
						
							|  |  |     if ([NSThread isMainThread]) {
 | 
						
						
						
							|  |  |         [self performSelectorInBackground:@selector(checkForConnectivityInBackground) withObject:nil];
 | 
						
						
						
							|  |  |         return;
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     @autoreleasepool {
 | 
						
						
						
							|  |  |         // prevent concurrent checks
 | 
						
						
						
							|  |  |         static BOOL checking = NO;
 | 
						
						
						
							|  |  |         if (checking)
 | 
						
						
						
							|  |  |             return;
 | 
						
						
						
							|  |  |         checking = YES;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         // first check iTunes
 | 
						
						
						
							|  |  |         NSString *iTunesServiceURL = [NSString stringWithFormat:iRateAppLookupURLFormat, self.appStoreCountry];
 | 
						
						
						
							|  |  |         if (_appStoreID) // important that we check ivar and not getter in case it has changed
 | 
						
						
						
							|  |  |         {
 | 
						
						
						
							|  |  |             iTunesServiceURL = [iTunesServiceURL stringByAppendingFormat:@"?id=%@", @(_appStoreID)];
 | 
						
						
						
							|  |  |         } else {
 | 
						
						
						
							|  |  |             iTunesServiceURL = [iTunesServiceURL stringByAppendingFormat:@"?bundleId=%@", self.applicationBundleID];
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         if (self.verboseLogging) {
 | 
						
						
						
							|  |  |             NSLog(@"iRate is checking %@ to retrieve the App Store details...", iTunesServiceURL);
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         NSError *error          = nil;
 | 
						
						
						
							|  |  |         NSURLResponse *response = nil;
 | 
						
						
						
							|  |  |         NSURLRequest *request   = [NSURLRequest requestWithURL:[NSURL URLWithString:iTunesServiceURL]
 | 
						
						
						
							|  |  |                                                  cachePolicy:NSURLRequestUseProtocolCachePolicy
 | 
						
						
						
							|  |  |                                              timeoutInterval:REQUEST_TIMEOUT];
 | 
						
						
						
							|  |  |         NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
 | 
						
						
						
							|  |  |         NSInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;
 | 
						
						
						
							|  |  |         if (data && statusCode == 200) {
 | 
						
						
						
							|  |  |             // in case error is garbage...
 | 
						
						
						
							|  |  |             error = nil;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |             id json = nil;
 | 
						
						
						
							|  |  |             if ([NSJSONSerialization class]) {
 | 
						
						
						
							|  |  |                 json = [[NSJSONSerialization JSONObjectWithData:data options:(NSJSONReadingOptions)0
 | 
						
						
						
							|  |  |                                                           error:&error][@"results"] lastObject];
 | 
						
						
						
							|  |  |             } else {
 | 
						
						
						
							|  |  |                 // convert to string
 | 
						
						
						
							|  |  |                 json = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
 | 
						
						
						
							|  |  |             }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |             if (!error) {
 | 
						
						
						
							|  |  |                 NSLog(@"JSON: %@", json);
 | 
						
						
						
							|  |  |                 // check bundle ID matches
 | 
						
						
						
							|  |  |                 NSString *bundleID = [self valueForKey:@"bundleId" inJSON:json];
 | 
						
						
						
							|  |  |                 if (bundleID) {
 | 
						
						
						
							|  |  |                     if ([bundleID isEqualToString:self.applicationBundleID]) {
 | 
						
						
						
							|  |  |                         // get genre
 | 
						
						
						
							|  |  |                         if (self.appStoreGenreID == 0) {
 | 
						
						
						
							|  |  |                             self.appStoreGenreID = [[self valueForKey:@"primaryGenreId" inJSON:json] integerValue];
 | 
						
						
						
							|  |  |                         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |                         // get app id
 | 
						
						
						
							|  |  |                         if (!_appStoreID) {
 | 
						
						
						
							|  |  |                             NSString *appStoreIDString = [self valueForKey:@"trackId" inJSON:json];
 | 
						
						
						
							|  |  |                             [self performSelectorOnMainThread:@selector(setAppStoreIDOnMainThread:)
 | 
						
						
						
							|  |  |                                                    withObject:appStoreIDString
 | 
						
						
						
							|  |  |                                                 waitUntilDone:YES];
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |                             if (self.verboseLogging) {
 | 
						
						
						
							|  |  |                                 NSLog(@"iRate found the app on iTunes. The App Store ID is %@", appStoreIDString);
 | 
						
						
						
							|  |  |                             }
 | 
						
						
						
							|  |  |                         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |                         // check version
 | 
						
						
						
							|  |  |                         if (self.onlyPromptIfLatestVersion && !self.previewMode) {
 | 
						
						
						
							|  |  |                             NSString *latestVersion = [self valueForKey:@"version" inJSON:json];
 | 
						
						
						
							|  |  |                             if ([latestVersion compare:self.applicationVersion options:NSNumericSearch] ==
 | 
						
						
						
							|  |  |                                 NSOrderedDescending) {
 | 
						
						
						
							|  |  |                                 if (self.verboseLogging) {
 | 
						
						
						
							|  |  |                                     NSLog(@"iRate found that the installed application version (%@) is not the latest "
 | 
						
						
						
							|  |  |                                           @"version on the App Store, which is %@",
 | 
						
						
						
							|  |  |                                           self.applicationVersion,
 | 
						
						
						
							|  |  |                                           latestVersion);
 | 
						
						
						
							|  |  |                                 }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |                                 error = [NSError errorWithDomain:iRateErrorDomain
 | 
						
						
						
							|  |  |                                                             code:iRateErrorApplicationIsNotLatestVersion
 | 
						
						
						
							|  |  |                                                         userInfo:@{
 | 
						
						
						
							|  |  |                                                             NSLocalizedDescriptionKey :
 | 
						
						
						
							|  |  |                                                                 @"Installed app is not the latest version available"
 | 
						
						
						
							|  |  |                                                         }];
 | 
						
						
						
							|  |  |                             }
 | 
						
						
						
							|  |  |                         }
 | 
						
						
						
							|  |  |                     } else {
 | 
						
						
						
							|  |  |                         if (self.verboseLogging) {
 | 
						
						
						
							|  |  |                             NSLog(@"iRate found that the application bundle ID (%@) does not match the bundle ID of "
 | 
						
						
						
							|  |  |                                   @"the app found on iTunes (%@) with the specified App Store ID (%@)",
 | 
						
						
						
							|  |  |                                   self.applicationBundleID,
 | 
						
						
						
							|  |  |                                   bundleID,
 | 
						
						
						
							|  |  |                                   @(self.appStoreID));
 | 
						
						
						
							|  |  |                         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |                         error = [NSError
 | 
						
						
						
							|  |  |                             errorWithDomain:iRateErrorDomain
 | 
						
						
						
							|  |  |                                        code:iRateErrorBundleIdDoesNotMatchAppStore
 | 
						
						
						
							|  |  |                                    userInfo:@{
 | 
						
						
						
							|  |  |                                        NSLocalizedDescriptionKey : [NSString
 | 
						
						
						
							|  |  |                                            stringWithFormat:
 | 
						
						
						
							|  |  |                                                @"Application bundle ID does not match expected value of %@", bundleID]
 | 
						
						
						
							|  |  |                                    }];
 | 
						
						
						
							|  |  |                     }
 | 
						
						
						
							|  |  |                 } else if (_appStoreID || !self.ratingsURL) {
 | 
						
						
						
							|  |  |                     if (self.verboseLogging) {
 | 
						
						
						
							|  |  |                         NSLog(@"iRate could not find this application on iTunes. If your app is not intended for App "
 | 
						
						
						
							|  |  |                               @"Store release then you must specify a custom ratingsURL. If this is the first release "
 | 
						
						
						
							|  |  |                               @"of your application then it's not a problem that it cannot be found on the store yet");
 | 
						
						
						
							|  |  |                     }
 | 
						
						
						
							|  |  |                     if (!self.previewMode) {
 | 
						
						
						
							|  |  |                         error = [NSError errorWithDomain:iRateErrorDomain
 | 
						
						
						
							|  |  |                                                     code:iRateErrorApplicationNotFoundOnAppStore
 | 
						
						
						
							|  |  |                                                 userInfo:@{
 | 
						
						
						
							|  |  |                                                     NSLocalizedDescriptionKey :
 | 
						
						
						
							|  |  |                                                         @"The application could not be found on the App Store."
 | 
						
						
						
							|  |  |                                                 }];
 | 
						
						
						
							|  |  |                     }
 | 
						
						
						
							|  |  |                 } else if (!_appStoreID && self.verboseLogging) {
 | 
						
						
						
							|  |  |                     NSLog(@"iRate could not find your app on iTunes. If your app is not yet on the store or is not "
 | 
						
						
						
							|  |  |                           @"intended for App Store release then don't worry about this");
 | 
						
						
						
							|  |  |                 }
 | 
						
						
						
							|  |  |             }
 | 
						
						
						
							|  |  |         } else if (statusCode >= 400) {
 | 
						
						
						
							|  |  |             // http error
 | 
						
						
						
							|  |  |             NSString *message = [NSString stringWithFormat:@"The server returned a %@ error", @(statusCode)];
 | 
						
						
						
							|  |  |             error             = [NSError errorWithDomain:@"HTTPResponseErrorDomain"
 | 
						
						
						
							|  |  |                                         code:statusCode
 | 
						
						
						
							|  |  |                                     userInfo:@{NSLocalizedDescriptionKey : message}];
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         // handle errors (ignoring sandbox issues)
 | 
						
						
						
							|  |  |         if (error && !(error.code == EPERM && [error.domain isEqualToString:NSPOSIXErrorDomain] && _appStoreID)) {
 | 
						
						
						
							|  |  |             [self performSelectorOnMainThread:@selector(connectionError:) withObject:error waitUntilDone:YES];
 | 
						
						
						
							|  |  |         } else if (self.appStoreID || self.previewMode) {
 | 
						
						
						
							|  |  |             // show prompt
 | 
						
						
						
							|  |  |             [self performSelectorOnMainThread:@selector(connectionSucceeded) withObject:nil waitUntilDone:YES];
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         // finished
 | 
						
						
						
							|  |  |         checking = NO;
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)promptIfNetworkAvailable {
 | 
						
						
						
							|  |  |     if (!self.checkingForPrompt && !self.checkingForAppStoreID) {
 | 
						
						
						
							|  |  |         self.checkingForPrompt = YES;
 | 
						
						
						
							|  |  |         [self checkForConnectivityInBackground];
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)promptIfAllCriteriaMet {
 | 
						
						
						
							|  |  |     if ([self shouldPromptForRating]) {
 | 
						
						
						
							|  |  |         [self promptIfNetworkAvailable];
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (BOOL)showRemindButton {
 | 
						
						
						
							|  |  |     return [self.remindButtonLabel length];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (BOOL)showCancelButton {
 | 
						
						
						
							|  |  |     return [self.cancelButtonLabel length];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)promptForRating {
 | 
						
						
						
							|  |  |     if (!self.visibleAlert) {
 | 
						
						
						
							|  |  |         NSString *message = self.ratedAnyVersion ? self.updateMessage : self.message;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #if TARGET_OS_IPHONE
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         UIViewController *topController = [UIApplication sharedApplication].delegate.window.rootViewController;
 | 
						
						
						
							|  |  |         while (topController.presentedViewController) {
 | 
						
						
						
							|  |  |             topController = topController.presentedViewController;
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         if ([UIAlertController class] && topController && self.useUIAlertControllerIfAvailable) {
 | 
						
						
						
							|  |  |             UIAlertController *alert = [UIAlertController alertControllerWithTitle:self.messageTitle
 | 
						
						
						
							|  |  |                                                                            message:message
 | 
						
						
						
							|  |  |                                                                     preferredStyle:UIAlertControllerStyleAlert];
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |             // rate action
 | 
						
						
						
							|  |  |             [alert addAction:[UIAlertAction actionWithTitle:self.rateButtonLabel
 | 
						
						
						
							|  |  |                                                       style:UIAlertActionStyleDefault
 | 
						
						
						
							|  |  |                                                     handler:^(__unused UIAlertAction *action) {
 | 
						
						
						
							|  |  |                                                       [self didDismissAlert:alert withButtonAtIndex:0];
 | 
						
						
						
							|  |  |                                                     }]];
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |             // cancel action
 | 
						
						
						
							|  |  |             if ([self showCancelButton]) {
 | 
						
						
						
							|  |  |                 [alert addAction:[UIAlertAction actionWithTitle:self.cancelButtonLabel
 | 
						
						
						
							|  |  |                                                           style:UIAlertActionStyleCancel
 | 
						
						
						
							|  |  |                                                         handler:^(__unused UIAlertAction *action) {
 | 
						
						
						
							|  |  |                                                           [self didDismissAlert:alert withButtonAtIndex:1];
 | 
						
						
						
							|  |  |                                                         }]];
 | 
						
						
						
							|  |  |             }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |             // remind action
 | 
						
						
						
							|  |  |             if ([self showRemindButton]) {
 | 
						
						
						
							|  |  |                 [alert addAction:[UIAlertAction actionWithTitle:self.remindButtonLabel
 | 
						
						
						
							|  |  |                                                           style:UIAlertActionStyleDefault
 | 
						
						
						
							|  |  |                                                         handler:^(__unused UIAlertAction *action) {
 | 
						
						
						
							|  |  |                                                           [self didDismissAlert:alert
 | 
						
						
						
							|  |  |                                                               withButtonAtIndex:[self showCancelButton] ? 2 : 1];
 | 
						
						
						
							|  |  |                                                         }]];
 | 
						
						
						
							|  |  |             }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |             self.visibleAlert = alert;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |             // get current view controller and present alert
 | 
						
						
						
							|  |  |             [topController presentViewController:alert animated:YES completion:NULL];
 | 
						
						
						
							|  |  |         } else {
 | 
						
						
						
							|  |  |             UIAlertView *alert = [[UIAlertView alloc] initWithTitle:self.messageTitle
 | 
						
						
						
							|  |  |                                                             message:message
 | 
						
						
						
							|  |  |                                                            delegate:(id<UIAlertViewDelegate>)self
 | 
						
						
						
							|  |  |                                                   cancelButtonTitle:nil
 | 
						
						
						
							|  |  |                                                   otherButtonTitles:self.rateButtonLabel, nil];
 | 
						
						
						
							|  |  |             if ([self showCancelButton]) {
 | 
						
						
						
							|  |  |                 [alert addButtonWithTitle:self.cancelButtonLabel];
 | 
						
						
						
							|  |  |                 alert.cancelButtonIndex = 1;
 | 
						
						
						
							|  |  |             }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |             if ([self showRemindButton]) {
 | 
						
						
						
							|  |  |                 [alert addButtonWithTitle:self.remindButtonLabel];
 | 
						
						
						
							|  |  |             }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |             self.visibleAlert = alert;
 | 
						
						
						
							|  |  |             [self.visibleAlert show];
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #else
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         // only show when main window is available
 | 
						
						
						
							|  |  |         if (self.onlyPromptIfMainWindowIsAvailable && ![[NSApplication sharedApplication] mainWindow]) {
 | 
						
						
						
							|  |  |             [self performSelector:@selector(promptForRating) withObject:nil afterDelay:0.5];
 | 
						
						
						
							|  |  |             return;
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         NSAlert *alert        = [[NSAlert alloc] init];
 | 
						
						
						
							|  |  |         alert.messageText     = self.messageTitle;
 | 
						
						
						
							|  |  |         alert.informativeText = message;
 | 
						
						
						
							|  |  |         [alert addButtonWithTitle:self.rateButtonLabel];
 | 
						
						
						
							|  |  |         if ([self showCancelButton]) {
 | 
						
						
						
							|  |  |             [alert addButtonWithTitle:self.cancelButtonLabel];
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  |         if ([self showRemindButton]) {
 | 
						
						
						
							|  |  |             [alert addButtonWithTitle:self.remindButtonLabel];
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         self.visibleAlert = alert;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #if __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_9
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         if (![alert respondsToSelector:@selector(beginSheetModalForWindow:completionHandler:)]) {
 | 
						
						
						
							|  |  |             [alert beginSheetModalForWindow:[NSApplication sharedApplication].mainWindow
 | 
						
						
						
							|  |  |                               modalDelegate:self
 | 
						
						
						
							|  |  |                              didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
 | 
						
						
						
							|  |  |                                 contextInfo:nil];
 | 
						
						
						
							|  |  |         } else
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #endif
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         {
 | 
						
						
						
							|  |  |             [alert beginSheetModalForWindow:[NSApplication sharedApplication].mainWindow
 | 
						
						
						
							|  |  |                           completionHandler:^(NSModalResponse returnCode) {
 | 
						
						
						
							|  |  |                             [self didDismissAlert:alert withButtonAtIndex:returnCode - NSAlertFirstButtonReturn];
 | 
						
						
						
							|  |  |                           }];
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #endif
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         // inform about prompt
 | 
						
						
						
							|  |  |         [self.delegate iRateDidPromptForRating];
 | 
						
						
						
							|  |  |         [[NSNotificationCenter defaultCenter] postNotificationName:iRateDidPromptForRating object:nil];
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)applicationLaunched {
 | 
						
						
						
							|  |  |     // check if this is a new version
 | 
						
						
						
							|  |  |     NSUserDefaults *defaults  = [NSUserDefaults standardUserDefaults];
 | 
						
						
						
							|  |  |     NSString *lastUsedVersion = [defaults objectForKey:iRateLastVersionUsedKey];
 | 
						
						
						
							|  |  |     if (!self.firstUsed || ![lastUsedVersion isEqualToString:self.applicationVersion]) {
 | 
						
						
						
							|  |  |         [defaults setObject:self.applicationVersion forKey:iRateLastVersionUsedKey];
 | 
						
						
						
							|  |  |         if (!self.firstUsed || [self ratedAnyVersion]) {
 | 
						
						
						
							|  |  |             // reset defaults
 | 
						
						
						
							|  |  |             [defaults setObject:[NSDate date] forKey:iRateFirstUsedKey];
 | 
						
						
						
							|  |  |             [defaults setInteger:0 forKey:iRateUseCountKey];
 | 
						
						
						
							|  |  |             [defaults setInteger:0 forKey:iRateEventCountKey];
 | 
						
						
						
							|  |  |             [defaults setObject:nil forKey:iRateLastRemindedKey];
 | 
						
						
						
							|  |  |             [defaults synchronize];
 | 
						
						
						
							|  |  |         } else if ([[NSDate date] timeIntervalSinceDate:self.firstUsed] >
 | 
						
						
						
							|  |  |                    (self.daysUntilPrompt - 1) * SECONDS_IN_A_DAY) {
 | 
						
						
						
							|  |  |             // if was previously installed, but we haven't yet prompted for a rating
 | 
						
						
						
							|  |  |             // don't reset, but make sure it won't rate for a day at least
 | 
						
						
						
							|  |  |             self.firstUsed = [[NSDate date] dateByAddingTimeInterval:(self.daysUntilPrompt - 1) * -SECONDS_IN_A_DAY];
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         // inform about app update
 | 
						
						
						
							|  |  |         [self.delegate iRateDidDetectAppUpdate];
 | 
						
						
						
							|  |  |         [[NSNotificationCenter defaultCenter] postNotificationName:iRateDidDetectAppUpdate object:nil];
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     [self incrementUseCount];
 | 
						
						
						
							|  |  |     if (self.shouldPromptForRating) {
 | 
						
						
						
							|  |  |         [self promptForRating];
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)didDismissAlert:(__unused id)alertView withButtonAtIndex:(NSInteger)buttonIndex {
 | 
						
						
						
							|  |  |     // get button indices
 | 
						
						
						
							|  |  |     NSInteger rateButtonIndex   = 0;
 | 
						
						
						
							|  |  |     NSInteger cancelButtonIndex = [self showCancelButton] ? 1 : 0;
 | 
						
						
						
							|  |  |     NSInteger remindButtonIndex = [self showRemindButton] ? cancelButtonIndex + 1 : 0;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     if (buttonIndex == rateButtonIndex) {
 | 
						
						
						
							|  |  |         [self rate];
 | 
						
						
						
							|  |  |     } else if (buttonIndex == cancelButtonIndex) {
 | 
						
						
						
							|  |  |         [self declineThisVersion];
 | 
						
						
						
							|  |  |     } else if (buttonIndex == remindButtonIndex) {
 | 
						
						
						
							|  |  |         [self remindLater];
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     // release alert
 | 
						
						
						
							|  |  |     self.visibleAlert = nil;
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #if TARGET_OS_IPHONE
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)applicationWillEnterForeground {
 | 
						
						
						
							|  |  |     if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
 | 
						
						
						
							|  |  |         [self incrementUseCount];
 | 
						
						
						
							|  |  |         if (self.promptAtLaunch) {
 | 
						
						
						
							|  |  |             [self promptIfAllCriteriaMet];
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)openRatingsPageInAppStore {
 | 
						
						
						
							|  |  |     if (!_ratingsURL && !self.appStoreID) {
 | 
						
						
						
							|  |  |         self.checkingForAppStoreID = YES;
 | 
						
						
						
							|  |  |         if (!self.checkingForPrompt) {
 | 
						
						
						
							|  |  |             [self checkForConnectivityInBackground];
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  |         return;
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     NSString *cantOpenMessage = nil;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #if TARGET_IPHONE_SIMULATOR
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     if ([[self.ratingsURL scheme] isEqualToString:iRateiOSAppStoreURLScheme]) {
 | 
						
						
						
							|  |  |         cantOpenMessage =
 | 
						
						
						
							|  |  |             @"iRate could not open the ratings page because the App Store is not available on the iOS simulator";
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #elif DEBUG
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     if (![[UIApplication sharedApplication] canOpenURL:self.ratingsURL]) {
 | 
						
						
						
							|  |  |         cantOpenMessage =
 | 
						
						
						
							|  |  |             [NSString stringWithFormat:@"iRate was unable to open the specified ratings URL: %@", self.ratingsURL];
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #endif
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     if (cantOpenMessage) {
 | 
						
						
						
							|  |  |         NSLog(@"%@", cantOpenMessage);
 | 
						
						
						
							|  |  |         NSError *error = [NSError errorWithDomain:iRateErrorDomain
 | 
						
						
						
							|  |  |                                              code:iRateErrorCouldNotOpenRatingPageURL
 | 
						
						
						
							|  |  |                                          userInfo:@{NSLocalizedDescriptionKey : cantOpenMessage}];
 | 
						
						
						
							|  |  |         [self.delegate iRateCouldNotConnectToAppStore:error];
 | 
						
						
						
							|  |  |         [[NSNotificationCenter defaultCenter] postNotificationName:iRateCouldNotConnectToAppStore object:error];
 | 
						
						
						
							|  |  |     } else {
 | 
						
						
						
							|  |  |         if (self.verboseLogging) {
 | 
						
						
						
							|  |  |             NSLog(@"iRate will open the App Store ratings page using the following URL: %@", self.ratingsURL);
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         [[UIApplication sharedApplication] openURL:self.ratingsURL];
 | 
						
						
						
							|  |  |         [self.delegate iRateDidOpenAppStore];
 | 
						
						
						
							|  |  |         [[NSNotificationCenter defaultCenter] postNotificationName:iRateDidOpenAppStore object:nil];
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
 | 
						
						
						
							|  |  |     [self didDismissAlert:alertView withButtonAtIndex:buttonIndex];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #else
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)openAppPageWhenAppStoreLaunched {
 | 
						
						
						
							|  |  |     // check if app store is running
 | 
						
						
						
							|  |  |     for (NSRunningApplication *app in [[NSWorkspace sharedWorkspace] runningApplications]) {
 | 
						
						
						
							|  |  |         if ([app.bundleIdentifier isEqualToString:iRateMacAppStoreBundleID]) {
 | 
						
						
						
							|  |  |             // open app page
 | 
						
						
						
							|  |  |             [[NSWorkspace sharedWorkspace] performSelector:@selector(openURL:)
 | 
						
						
						
							|  |  |                                                 withObject:self.ratingsURL
 | 
						
						
						
							|  |  |                                                 afterDelay:MAC_APP_STORE_REFRESH_DELAY];
 | 
						
						
						
							|  |  |             return;
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     // try again
 | 
						
						
						
							|  |  |     [self performSelector:@selector(openAppPageWhenAppStoreLaunched) withObject:nil afterDelay:0.0];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)openRatingsPageInAppStore {
 | 
						
						
						
							|  |  |     if (!_ratingsURL && !self.appStoreID) {
 | 
						
						
						
							|  |  |         self.checkingForAppStoreID = YES;
 | 
						
						
						
							|  |  |         if (!self.checkingForPrompt) {
 | 
						
						
						
							|  |  |             [self checkForConnectivityInBackground];
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  |         return;
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     if (self.verboseLogging) {
 | 
						
						
						
							|  |  |         NSLog(@"iRate will open the App Store ratings page using the following URL: %@", self.ratingsURL);
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     [[NSWorkspace sharedWorkspace] openURL:self.ratingsURL];
 | 
						
						
						
							|  |  |     [self openAppPageWhenAppStoreLaunched];
 | 
						
						
						
							|  |  |     [self.delegate iRateDidOpenAppStore];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(__unused void *)contextInfo {
 | 
						
						
						
							|  |  |     [self didDismissAlert:alert withButtonAtIndex:returnCode - NSAlertFirstButtonReturn];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #endif
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)logEvent:(BOOL)deferPrompt {
 | 
						
						
						
							|  |  |     [self incrementEventCount];
 | 
						
						
						
							|  |  |     if (!deferPrompt) {
 | 
						
						
						
							|  |  |         [self promptIfAllCriteriaMet];
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #pragma mark - User's actions
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)declineThisVersion {
 | 
						
						
						
							|  |  |     // ignore this version
 | 
						
						
						
							|  |  |     self.declinedThisVersion = YES;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     // log event
 | 
						
						
						
							|  |  |     [self.delegate iRateUserDidDeclineToRateApp];
 | 
						
						
						
							|  |  |     [[NSNotificationCenter defaultCenter] postNotificationName:iRateUserDidDeclineToRateApp object:nil];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)remindLater {
 | 
						
						
						
							|  |  |     // remind later
 | 
						
						
						
							|  |  |     self.lastReminded = [NSDate date];
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     // log event
 | 
						
						
						
							|  |  |     [self.delegate iRateUserDidRequestReminderToRateApp];
 | 
						
						
						
							|  |  |     [[NSNotificationCenter defaultCenter] postNotificationName:iRateUserDidRequestReminderToRateApp object:nil];
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - (void)rate {
 | 
						
						
						
							|  |  |     // mark as rated
 | 
						
						
						
							|  |  |     self.ratedThisVersion = YES;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     // log event
 | 
						
						
						
							|  |  |     [self.delegate iRateUserDidAttemptToRateApp];
 | 
						
						
						
							|  |  |     [[NSNotificationCenter defaultCenter] postNotificationName:iRateUserDidAttemptToRateApp object:nil];
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     if ([self.delegate iRateShouldOpenAppStore]) {
 | 
						
						
						
							|  |  |         // launch mac app store
 | 
						
						
						
							|  |  |         [self openRatingsPageInAppStore];
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | @end
 |