Permalink
Browse files

Add plist configuration

Allow Appirater to be configured via optional Appirater.plist file.
If omitted, it defaults to the old defaults defined in Appirater.h,
except for the iTunes App ID, which defaults to the Info.plist
`iTunesAppID` string entry (if omitted it will be 0)
  • Loading branch information...
1 parent 3a9bd6c commit 06324932a586e834d6b902e7cb5359aeebb214ac @jlopez committed Aug 24, 2012
Showing with 139 additions and 30 deletions.
  1. +5 −8 Appirater.h
  2. +98 −20 Appirater.m
  3. +33 −0 Appirater.plist.sample
  4. +3 −2 README.md
View
@@ -34,7 +34,7 @@
* Copyright 2012 Arash Payan. All rights reserved.
*/
-#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
extern NSString *const kAppiraterFirstUseDate;
extern NSString *const kAppiraterUseCount;
@@ -47,7 +47,7 @@ extern NSString *const kAppiraterReminderRequestDate;
/*
Place your Apple generated software id here.
*/
-#define APPIRATER_APP_ID 301377083
+#define APPIRATER_APP_ID [bundle objectForInfoDictionaryKey:@"iTunesAppID"]
/*
@@ -64,14 +64,12 @@ extern NSString *const kAppiraterReminderRequestDate;
This is the message your users will see once they've passed the day+launches
threshold.
*/
-#define APPIRATER_LOCALIZED_MESSAGE NSLocalizedString(@"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!", nil)
-#define APPIRATER_MESSAGE [NSString stringWithFormat:APPIRATER_LOCALIZED_MESSAGE, APPIRATER_APP_NAME]
+#define APPIRATER_MESSAGE NSLocalizedString(@"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!", nil)
/*
This is the title of the message alert that users will see.
*/
-#define APPIRATER_LOCALIZED_MESSAGE_TITLE NSLocalizedString(@"Rate %@", nil)
-#define APPIRATER_MESSAGE_TITLE [NSString stringWithFormat:APPIRATER_LOCALIZED_MESSAGE_TITLE, APPIRATER_APP_NAME]
+#define APPIRATER_MESSAGE_TITLE NSLocalizedString(@"Rate %@", nil)
/*
The text of the button that rejects reviewing the app.
@@ -81,8 +79,7 @@ extern NSString *const kAppiraterReminderRequestDate;
/*
Text of button that will send user to app review page.
*/
-#define APPIRATER_LOCALIZED_RATE_BUTTON NSLocalizedString(@"Rate %@", nil)
-#define APPIRATER_RATE_BUTTON [NSString stringWithFormat:APPIRATER_LOCALIZED_RATE_BUTTON, APPIRATER_APP_NAME]
+#define APPIRATER_RATE_BUTTON NSLocalizedString(@"Rate %@", nil)
/*
Text for button to remind the user to review later.
View
@@ -46,20 +46,98 @@
NSString *const kAppiraterDeclinedToRate = @"kAppiraterDeclinedToRate";
NSString *const kAppiraterReminderRequestDate = @"kAppiraterReminderRequestDate";
-NSString *templateReviewURL = @"itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=APP_ID";
+NSString *templateReviewURL = @"itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=%@";
+
+NSString *const kConfigAppID = @"AppID";
+NSString *const kConfigAppName = @"AppName";
+NSString *const kConfigMessage = @"Message";
+NSString *const kConfigMessageTitle = @"MessageTitle";
+NSString *const kConfigCancelButton = @"CancelButton";
+NSString *const kConfigRateButton = @"RateButton";
+NSString *const kConfigRateLater = @"RateLater";
+NSString *const kConfigDaysUntilPrompt = @"DaysUntilPrompt";
+NSString *const kConfigUsesUntilPrompt = @"UsesUntilPrompt";
+NSString *const kConfigSigEventsUntilPrompt = @"SigEventsUntilPrompt";
+NSString *const kConfigTimeBeforeReminding = @"TimeBeforeReminding";
+NSString *const kConfigDebug = @"Debug";
+
+@interface Appirater () {
+@private
+ NSDictionary *configuration;
+ BOOL debug;
+}
+
+@property (nonatomic, readonly, getter = isDebug) BOOL debug;
-@interface Appirater ()
- (BOOL)connectedToNetwork;
+ (Appirater*)sharedInstance;
- (void)showRatingAlert;
- (BOOL)ratingConditionsHaveBeenMet;
- (void)incrementUseCount;
- (void)hideRatingAlert;
+- (NSString *)configurationStringForKey:(NSString *)key;
+- (NSInteger)configurationIntegerForKey:(NSString *)key;
+
@end
-@implementation Appirater
+@implementation Appirater
@synthesize ratingAlert;
+@synthesize debug;
+
+- (id)init {
+ if (self = [super init]) {
+ NSBundle *bundle = [NSBundle mainBundle];
+
+ NSMutableDictionary *defaults = [NSMutableDictionary dictionaryWithCapacity:10];
+ [defaults setObject:APPIRATER_APP_ID forKey:kConfigAppID];
+ [defaults setObject:APPIRATER_APP_NAME forKey:kConfigAppName];
+ [defaults setObject:APPIRATER_MESSAGE forKey:kConfigMessage];
+ [defaults setObject:APPIRATER_MESSAGE_TITLE forKey:kConfigMessageTitle];
+ [defaults setObject:APPIRATER_CANCEL_BUTTON forKey:kConfigCancelButton];
+ [defaults setObject:APPIRATER_RATE_BUTTON forKey:kConfigRateButton];
+ [defaults setObject:APPIRATER_RATE_LATER forKey:kConfigRateLater];
+ [defaults setObject:[NSNumber numberWithInteger:APPIRATER_DAYS_UNTIL_PROMPT] forKey:kConfigDaysUntilPrompt];
+ [defaults setObject:[NSNumber numberWithInteger:APPIRATER_USES_UNTIL_PROMPT] forKey:kConfigUsesUntilPrompt];
+ [defaults setObject:[NSNumber numberWithInteger:APPIRATER_SIG_EVENTS_UNTIL_PROMPT] forKey:kConfigSigEventsUntilPrompt];
+ [defaults setObject:[NSNumber numberWithInteger:APPIRATER_TIME_BEFORE_REMINDING] forKey:kConfigTimeBeforeReminding];
+ [defaults setObject:[NSNumber numberWithBool:APPIRATER_DEBUG] forKey:kConfigDebug];
+
+ NSString *path = [bundle pathForResource:@"Appirater" ofType:@"plist"];
+ NSDictionary *dict = path ? [NSDictionary dictionaryWithContentsOfFile:path] : nil;
+ if (dict)
+ [defaults addEntriesFromDictionary:dict];
+
+ NSString *appName = [defaults objectForKey:kConfigAppName];
+ for (NSString *key in [defaults allKeys]) {
+ id value = [defaults objectForKey:key];
+ if ([value isKindOfClass:[NSString class]]) {
+ value = [value stringByReplacingOccurrencesOfString:@"%@" withString:appName];
+ [defaults setObject:value forKey:key];
+ }
+ }
+
+ configuration = [[NSDictionary alloc] initWithDictionary:defaults];
+ debug = [[configuration objectForKey:kConfigDebug] boolValue];
+
+ if (debug)
+ NSLog(@"Appirater Config: %@", configuration);
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [configuration release];
+ [super dealloc];
+}
+
+- (NSString *)configurationStringForKey:(NSString *)key {
+ return [configuration objectForKey:key];
+}
+
+- (NSInteger)configurationIntegerForKey:(NSString *)key {
+ return [[configuration objectForKey:key] integerValue];
+}
- (BOOL)connectedToNetwork {
// Create zero addy
@@ -108,35 +186,35 @@ + (Appirater*)sharedInstance {
}
- (void)showRatingAlert {
- UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:APPIRATER_MESSAGE_TITLE
- message:APPIRATER_MESSAGE
+ UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:[self configurationStringForKey:kConfigMessageTitle]
+ message:[self configurationStringForKey:kConfigMessage]
delegate:self
- cancelButtonTitle:APPIRATER_CANCEL_BUTTON
- otherButtonTitles:APPIRATER_RATE_BUTTON, APPIRATER_RATE_LATER, nil] autorelease];
+ cancelButtonTitle:[self configurationStringForKey:kConfigCancelButton]
+ otherButtonTitles:[self configurationStringForKey:kConfigRateButton], [self configurationStringForKey:kConfigRateLater], nil] autorelease];
self.ratingAlert = alertView;
[alertView show];
}
- (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 * [self configurationIntegerForKey:kConfigDaysUntilPrompt];
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 <= [self configurationIntegerForKey:kConfigUsesUntilPrompt])
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 <= [self configurationIntegerForKey:kConfigSigEventsUntilPrompt])
return NO;
// has the user previously declined to rate this version of the app?
@@ -150,7 +228,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 * [self configurationIntegerForKey:kConfigTimeBeforeReminding];
if (timeSinceReminderRequest < timeUntilReminder)
return NO;
@@ -160,7 +238,7 @@ - (BOOL)ratingConditionsHaveBeenMet {
- (void)incrementUseCount {
// get the app's version
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleVersionKey];
-
+
// get the version number that we've been tracking
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSString *trackingVersion = [userDefaults stringForKey:kAppiraterCurrentVersion];
@@ -170,7 +248,7 @@ - (void)incrementUseCount {
[userDefaults setObject:version forKey:kAppiraterCurrentVersion];
}
- if (APPIRATER_DEBUG)
+ if (debug)
NSLog(@"APPIRATER Tracking version: %@", trackingVersion);
if ([trackingVersion isEqualToString:version])
@@ -187,7 +265,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
@@ -218,7 +296,7 @@ - (void)incrementSignificantEventCount {
[userDefaults setObject:version forKey:kAppiraterCurrentVersion];
}
- if (APPIRATER_DEBUG)
+ if (debug)
NSLog(@"APPIRATER Tracking version: %@", trackingVersion);
if ([trackingVersion isEqualToString:version])
@@ -235,7 +313,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
@@ -294,14 +372,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 ([[self sharedInstance] isDebug])
NSLog(@"APPIRATER appWillResignActive");
[[Appirater sharedInstance] hideRatingAlert];
}
@@ -325,7 +403,7 @@ + (void)rateApp {
NSLog(@"APPIRATER NOTE: iTunes App Store is not supported on the iOS simulator. Unable to open App Store page.");
#else
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
- NSString *reviewURL = [templateReviewURL stringByReplacingOccurrencesOfString:@"APP_ID" withString:[NSString stringWithFormat:@"%d", APPIRATER_APP_ID]];
+ NSString *reviewURL = [NSString stringWithFormat:templateReviewURL, [[self sharedInstance] configurationStringForKey:kConfigAppID]];
[userDefaults setBool:YES forKey:kAppiraterRatedCurrentVersion];
[userDefaults synchronize];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:reviewURL]];
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <!-- All these options have suitable defaults -->
+ <!-- See Appirater.h for more information -->
+ <!-- %@ is always replaced with AppName -->
+ <key>AppID</key>
+ <string>1234</string>
+ <key>AppName</key>
+ <string>Appirater</string>
+ <key>Message</key>
+ <string>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!</string>
+ <key>MessageTitle</key>
+ <string>Rate %@</string>
+ <key>CancelButton</key>
+ <string>No, Thanks</string>
+ <key>RateButton</key>
+ <string>Rate %@</string>
+ <key>RateLater</key>
+ <string>Remind me later</string>
+ <key>DaysUntilPrompt</key>
+ <integer>30</integer>
+ <key>UsesUntilPrompt</key>
+ <integer>20</integer>
+ <key>SigEventsUntilPrompt</key>
+ <integer>-1</integer>
+ <key>TimeBeforeReminding</key>
+ <integer>1</integer>
+ <key>Debug</key>
+ <false/>
+</dict>
+</plist>
View
@@ -13,7 +13,8 @@ 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. Set an Info.plist string entry `iTunesAppID` to your Apple provided software id.
+7. Optionally, include an Appirater.plist file containing customization parameters (see Appirater.plist.sample)
License
-------
@@ -30,4 +31,4 @@ MonoTouch Port
[homepage]: http://arashpayan.com/blog/index.php/2009/09/07/presenting-appirater/
[arash]: http://arashpayan.com
[ivan]: https://www.facebook.com/nikitinivan
-[monotouchport]: https://github.com/chebum/Appirater-for-MonoTouch
+[monotouchport]: https://github.com/chebum/Appirater-for-MonoTouch

0 comments on commit 0632493

Please sign in to comment.