From f452be64717b9e7b6e8dc90c5fc8341de1850c52 Mon Sep 17 00:00:00 2001 From: Hermes Pique Date: Fri, 31 Aug 2012 14:04:42 +0200 Subject: [PATCH 1/5] Mark appLaunched as deprecated --- Appirater.h | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Appirater.h b/Appirater.h index 1ad2b603..1d3fe9f9 100644 --- a/Appirater.h +++ b/Appirater.h @@ -140,14 +140,6 @@ extern NSString *const kAppiraterReminderRequestDate; @property(nonatomic, retain) UIAlertView *ratingAlert; -/* - DEPRECATED: While still functional, it's better to use - appLaunched:(BOOL)canPromptForRating instead. - - Calls [Appirater appLaunched:YES]. See appLaunched: for details of functionality. - */ -+ (void)appLaunched; - /* Tells Appirater that the app has launched, and on devices that do NOT support multitasking, the 'uses' count will be incremented. You should @@ -207,3 +199,15 @@ extern NSString *const kAppiraterReminderRequestDate; + (void)rateApp; @end + +@interface Appirater(Deprecated) + +/* + DEPRECATED: While still functional, it's better to use + appLaunched:(BOOL)canPromptForRating instead. + + Calls [Appirater appLaunched:YES]. See appLaunched: for details of functionality. + */ ++ (void)appLaunched __attribute__((deprecated)); + +@end From 63c2ac739684bd634f89488cbbfbcd30930066b2 Mon Sep 17 00:00:00 2001 From: Hermes Pique Date: Fri, 31 Aug 2012 14:04:58 +0200 Subject: [PATCH 2/5] Add .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..9bea4330 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +.DS_Store From 6fa095419f11e0ebcbc959fa5dab23fa5c2c60ed Mon Sep 17 00:00:00 2001 From: Hermes Pique Date: Fri, 31 Aug 2012 17:09:36 +0200 Subject: [PATCH 3/5] Convert to ARC --- Appirater.h | 2 +- Appirater.m | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Appirater.h b/Appirater.h index 1d3fe9f9..6cdd3563 100644 --- a/Appirater.h +++ b/Appirater.h @@ -138,7 +138,7 @@ extern NSString *const kAppiraterReminderRequestDate; UIAlertView *ratingAlert; } -@property(nonatomic, retain) UIAlertView *ratingAlert; +@property(nonatomic, strong) UIAlertView *ratingAlert; /* Tells Appirater that the app has launched, and on devices that do NOT diff --git a/Appirater.m b/Appirater.m index 8a43ca7d..460f4be0 100644 --- a/Appirater.m +++ b/Appirater.m @@ -88,7 +88,7 @@ - (BOOL)connectedToNetwork { NSURL *testURL = [NSURL URLWithString:@"http://www.apple.com/"]; NSURLRequest *testRequest = [NSURLRequest requestWithURL:testURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:20.0]; - NSURLConnection *testConnection = [[[NSURLConnection alloc] initWithRequest:testRequest delegate:self] autorelease]; + NSURLConnection *testConnection = [[NSURLConnection alloc] initWithRequest:testRequest delegate:self]; return ((isReachable && !needsConnection) || nonWiFi) ? (testConnection ? YES : NO) : NO; } @@ -109,11 +109,11 @@ + (Appirater*)sharedInstance { } - (void)showRatingAlert { - UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:APPIRATER_MESSAGE_TITLE + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:APPIRATER_MESSAGE_TITLE message:APPIRATER_MESSAGE delegate:self cancelButtonTitle:APPIRATER_CANCEL_BUTTON - otherButtonTitles:APPIRATER_RATE_BUTTON, APPIRATER_RATE_LATER, nil] autorelease]; + otherButtonTitles:APPIRATER_RATE_BUTTON, APPIRATER_RATE_LATER, nil]; self.ratingAlert = alertView; [alertView show]; } From 96dbd138d6f2f0282a146ba8302c2c5aa4e27638 Mon Sep 17 00:00:00 2001 From: Hermes Pique Date: Fri, 31 Aug 2012 17:28:04 +0200 Subject: [PATCH 4/5] Dynamic configuration --- Appirater.h | 104 +++++++++++++++++++++++++++------------------------- Appirater.m | 58 ++++++++++++++++++++++------- 2 files changed, 100 insertions(+), 62 deletions(-) diff --git a/Appirater.h b/Appirater.h index 6cdd3563..2b5e3138 100644 --- a/Appirater.h +++ b/Appirater.h @@ -44,12 +44,6 @@ extern NSString *const kAppiraterRatedCurrentVersion; extern NSString *const kAppiraterDeclinedToRate; extern NSString *const kAppiraterReminderRequestDate; -/* - Place your Apple generated software id here. - */ -#define APPIRATER_APP_ID 301377083 - - /* Your localized app's name. */ @@ -89,49 +83,6 @@ extern NSString *const kAppiraterReminderRequestDate; */ #define APPIRATER_RATE_LATER NSLocalizedString(@"Remind me later", nil) -/* - Users will need to have the same version of your app installed for this many - days before they will be prompted to rate it. - */ -#define APPIRATER_DAYS_UNTIL_PROMPT 30 // double - -/* - An example of a 'use' would be if the user launched the app. Bringing the app - into the foreground (on devices that support it) would also be considered - a 'use'. You tell Appirater about these events using the two methods: - [Appirater appLaunched:] - [Appirater appEnteredForeground:] - - Users need to 'use' the same version of the app this many times before - before they will be prompted to rate it. - */ -#define APPIRATER_USES_UNTIL_PROMPT 20 // integer - -/* - A significant event can be anything you want to be in your app. In a - telephone app, a significant event might be placing or receiving a call. - In a game, it might be beating a level or a boss. This is just another - layer of filtering that can be used to make sure that only the most - loyal of your users are being prompted to rate you on the app store. - If you leave this at a value of -1, then this won't be a criteria - used for rating. To tell Appirater that the user has performed - a significant event, call the method: - [Appirater userDidSignificantEvent:]; - */ -#define APPIRATER_SIG_EVENTS_UNTIL_PROMPT -1 // integer - -/* - Once the rating alert is presented to the user, they might select - 'Remind me later'. This value specifies how long (in days) Appirater - will wait before reminding them. - */ -#define APPIRATER_TIME_BEFORE_REMINDING 1 // double - -/* - 'YES' will show the Appirater alert everytime. Useful for testing how your message - looks and making sure the link to your app's review page works. - */ -#define APPIRATER_DEBUG YES @interface Appirater : NSObject { @@ -200,6 +151,61 @@ extern NSString *const kAppiraterReminderRequestDate; @end +@interface Appirater(Configuration) + +/* + Set your Apple generated software id here. + */ ++ (void) setAppId:(NSString*)appId; + +/* + Users will need to have the same version of your app installed for this many + days before they will be prompted to rate it. + */ ++ (void) setDaysUntilPrompt:(double)value; + +/* + An example of a 'use' would be if the user launched the app. Bringing the app + into the foreground (on devices that support it) would also be considered + a 'use'. You tell Appirater about these events using the two methods: + [Appirater appLaunched:] + [Appirater appEnteredForeground:] + + Users need to 'use' the same version of the app this many times before + before they will be prompted to rate it. + */ ++ (void) setUsesUntilPrompt:(NSInteger)value; + +/* + A significant event can be anything you want to be in your app. In a + telephone app, a significant event might be placing or receiving a call. + In a game, it might be beating a level or a boss. This is just another + layer of filtering that can be used to make sure that only the most + loyal of your users are being prompted to rate you on the app store. + If you leave this at a value of -1, then this won't be a criteria + used for rating. To tell Appirater that the user has performed + a significant event, call the method: + [Appirater userDidSignificantEvent:]; + */ ++ (void) setSignificantEventsUntilPrompt:(NSInteger)value; + + +/* + Once the rating alert is presented to the user, they might select + 'Remind me later'. This value specifies how long (in days) Appirater + will wait before reminding them. + */ ++ (void) setTimeBeforeReminding:(double)value; + +/* + 'YES' will show the Appirater alert everytime. Useful for testing how your message + looks and making sure the link to your app's review page works. + */ ++ (void) setDebug:(BOOL)debug; + +@end + + @interface Appirater(Deprecated) /* diff --git a/Appirater.m b/Appirater.m index 460f4be0..5c5a5da2 100644 --- a/Appirater.m +++ b/Appirater.m @@ -49,6 +49,13 @@ NSString *templateReviewURL = @"itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=APP_ID"; NSString *templateReviewURLiOS6 = @"itms-apps://itunes.apple.com/LANGUAGE/app/idAPP_ID"; +static NSString *_appId; +static double _daysUntilPrompt = 30; +static NSInteger _usesUntilPrompt = 20; +static NSInteger _significantEventsUntilPrompt = -1; +static double _timeBeforeReminding = 1; +static BOOL _debug = NO; + @interface Appirater () - (BOOL)connectedToNetwork; + (Appirater*)sharedInstance; @@ -62,6 +69,31 @@ @implementation Appirater @synthesize ratingAlert; ++ (void) setAppId:(NSString *)appId { + _appId = appId; +} + ++ (void) setDaysUntilPrompt:(double)value { + _daysUntilPrompt = value; +} + ++ (void) setUsesUntilPrompt:(NSInteger)value { + _usesUntilPrompt = value; +} + ++ (void) setSignificantEventsUntilPrompt:(NSInteger)value { + _significantEventsUntilPrompt = value; +} + ++ (void) setTimeBeforeReminding:(double)value { + _timeBeforeReminding = value; +} + ++ (void) setDebug:(BOOL)debug { + _debug = debug; +} + + - (BOOL)connectedToNetwork { // Create zero addy struct sockaddr_in zeroAddress; @@ -119,25 +151,25 @@ - (void)showRatingAlert { } - (BOOL)ratingConditionsHaveBeenMet { - if (APPIRATER_DEBUG) + if (_debug) return YES; NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; NSDate *dateOfFirstLaunch = [NSDate dateWithTimeIntervalSince1970:[userDefaults doubleForKey:kAppiraterFirstUseDate]]; NSTimeInterval timeSinceFirstLaunch = [[NSDate date] timeIntervalSinceDate:dateOfFirstLaunch]; - NSTimeInterval timeUntilRate = 60 * 60 * 24 * APPIRATER_DAYS_UNTIL_PROMPT; + NSTimeInterval timeUntilRate = 60 * 60 * 24 * _daysUntilPrompt; if (timeSinceFirstLaunch < timeUntilRate) return NO; // check if the app has been used enough int useCount = [userDefaults integerForKey:kAppiraterUseCount]; - if (useCount <= APPIRATER_USES_UNTIL_PROMPT) + if (useCount <= _usesUntilPrompt) return NO; // check if the user has done enough significant events int sigEventCount = [userDefaults integerForKey:kAppiraterSignificantEventCount]; - if (sigEventCount <= APPIRATER_SIG_EVENTS_UNTIL_PROMPT) + if (sigEventCount <= _significantEventsUntilPrompt) return NO; // has the user previously declined to rate this version of the app? @@ -151,7 +183,7 @@ - (BOOL)ratingConditionsHaveBeenMet { // if the user wanted to be reminded later, has enough time passed? NSDate *reminderRequestDate = [NSDate dateWithTimeIntervalSince1970:[userDefaults doubleForKey:kAppiraterReminderRequestDate]]; NSTimeInterval timeSinceReminderRequest = [[NSDate date] timeIntervalSinceDate:reminderRequestDate]; - NSTimeInterval timeUntilReminder = 60 * 60 * 24 * APPIRATER_TIME_BEFORE_REMINDING; + NSTimeInterval timeUntilReminder = 60 * 60 * 24 * _timeBeforeReminding; if (timeSinceReminderRequest < timeUntilReminder) return NO; @@ -171,7 +203,7 @@ - (void)incrementUseCount { [userDefaults setObject:version forKey:kAppiraterCurrentVersion]; } - if (APPIRATER_DEBUG) + if (_debug) NSLog(@"APPIRATER Tracking version: %@", trackingVersion); if ([trackingVersion isEqualToString:version]) @@ -188,7 +220,7 @@ - (void)incrementUseCount { int useCount = [userDefaults integerForKey:kAppiraterUseCount]; useCount++; [userDefaults setInteger:useCount forKey:kAppiraterUseCount]; - if (APPIRATER_DEBUG) + if (_debug) NSLog(@"APPIRATER Use count: %d", useCount); } else @@ -219,7 +251,7 @@ - (void)incrementSignificantEventCount { [userDefaults setObject:version forKey:kAppiraterCurrentVersion]; } - if (APPIRATER_DEBUG) + if (_debug) NSLog(@"APPIRATER Tracking version: %@", trackingVersion); if ([trackingVersion isEqualToString:version]) @@ -236,7 +268,7 @@ - (void)incrementSignificantEventCount { int sigEventCount = [userDefaults integerForKey:kAppiraterSignificantEventCount]; sigEventCount++; [userDefaults setInteger:sigEventCount forKey:kAppiraterSignificantEventCount]; - if (APPIRATER_DEBUG) + if (_debug) NSLog(@"APPIRATER Significant event count: %d", sigEventCount); } else @@ -295,14 +327,14 @@ + (void)appLaunched:(BOOL)canPromptForRating { - (void)hideRatingAlert { if (self.ratingAlert.visible) { - if (APPIRATER_DEBUG) + if (_debug) NSLog(@"APPIRATER Hiding Alert"); [self.ratingAlert dismissWithClickedButtonIndex:-1 animated:NO]; } } + (void)appWillResignActive { - if (APPIRATER_DEBUG) + if (_debug) NSLog(@"APPIRATER appWillResignActive"); [[Appirater sharedInstance] hideRatingAlert]; } @@ -330,12 +362,12 @@ + (void)rateApp { // added work arround for wrong URL Scheme used in new App store on iOS 6 NSString *reviewURL; if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 6.0) { - reviewURL = [templateReviewURLiOS6 stringByReplacingOccurrencesOfString:@"APP_ID" withString:[NSString stringWithFormat:@"%d", APPIRATER_APP_ID]]; + reviewURL = [templateReviewURLiOS6 stringByReplacingOccurrencesOfString:@"APP_ID" withString:[NSString stringWithFormat:@"%@", _appId]]; reviewURL = [reviewURL stringByReplacingOccurrencesOfString:@"LANGUAGE" withString:[NSString stringWithFormat:@"%@", [[NSLocale preferredLanguages] objectAtIndex:0]]]; } else { - reviewURL = [templateReviewURL stringByReplacingOccurrencesOfString:@"APP_ID" withString:[NSString stringWithFormat:@"%d", APPIRATER_APP_ID]]; + reviewURL = [templateReviewURL stringByReplacingOccurrencesOfString:@"APP_ID" withString:[NSString stringWithFormat:@"%@", _appId]]; } [userDefaults setBool:YES forKey:kAppiraterRatedCurrentVersion]; From f876e2917a08c561023a5853409117ca85b3e773 Mon Sep 17 00:00:00 2001 From: Hermes Pique Date: Sat, 1 Sep 2012 00:25:57 +0200 Subject: [PATCH 5/5] Update step 6 with setAppId: --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 12416ac2..166b4d84 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Getting Started 3. Call `[Appirater appLaunched:YES]` at the end of your app delegate's `application:didFinishLaunchingWithOptions:` method. 4. Call `[Appirater appEnteredForeground:YES]` in your app delegate's `applicationWillEnterForeground:` method. 5. (OPTIONAL) Call `[Appirater userDidSignificantEvent:YES]` when the user does something 'significant' in the app. -6. Finally, set the `APPIRATER_APP_ID` in `Appirater.h` to your Apple provided software id. +6. Finally, call `[Appirater setAppId:@"yourAppId"]` with your Apple provided software id. License -------