iphone: Drop unused Appirater thirdparty API
This commit is contained in:
parent
49c065d29c
commit
481e511082
6 changed files with 0 additions and 970 deletions
|
@ -1,200 +0,0 @@
|
||||||
/*
|
|
||||||
This file is part of Appirater.
|
|
||||||
|
|
||||||
Copyright (c) 2010, Arash Payan
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person
|
|
||||||
obtaining a copy of this software and associated documentation
|
|
||||||
files (the "Software"), to deal in the Software without
|
|
||||||
restriction, including without limitation the rights to use,
|
|
||||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the
|
|
||||||
Software is furnished to do so, subject to the following
|
|
||||||
conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
||||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* Appirater.h
|
|
||||||
* appirater
|
|
||||||
*
|
|
||||||
* Created by Arash Payan on 9/5/09.
|
|
||||||
* http://arashpayan.com
|
|
||||||
* Copyright 2010 Arash Payan. All rights reserved.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
|
|
||||||
extern NSString *const kAppiraterFirstUseDate;
|
|
||||||
extern NSString *const kAppiraterUseCount;
|
|
||||||
extern NSString *const kAppiraterSignificantEventCount;
|
|
||||||
extern NSString *const kAppiraterCurrentVersion;
|
|
||||||
extern NSString *const kAppiraterRatedCurrentVersion;
|
|
||||||
extern NSString *const kAppiraterDeclinedToRate;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Place your Apple generated software id here.
|
|
||||||
*/
|
|
||||||
#define APPIRATER_APP_ID 301377083
|
|
||||||
|
|
||||||
/*
|
|
||||||
Your app's name.
|
|
||||||
*/
|
|
||||||
#define APPIRATER_APP_NAME [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleNameKey]
|
|
||||||
|
|
||||||
/*
|
|
||||||
This is the message your users will see once they've passed the day+launches
|
|
||||||
threshold.
|
|
||||||
*/
|
|
||||||
#define APPIRATER_MESSAGE [NSString stringWithFormat:@"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!", APPIRATER_APP_NAME]
|
|
||||||
|
|
||||||
/*
|
|
||||||
This is the title of the message alert that users will see.
|
|
||||||
*/
|
|
||||||
#define APPIRATER_MESSAGE_TITLE [NSString stringWithFormat:@"Rate %@", APPIRATER_APP_NAME]
|
|
||||||
|
|
||||||
/*
|
|
||||||
The text of the button that rejects reviewing the app.
|
|
||||||
*/
|
|
||||||
#define APPIRATER_CANCEL_BUTTON @"No, Thanks"
|
|
||||||
|
|
||||||
/*
|
|
||||||
Text of button that will send user to app review page.
|
|
||||||
*/
|
|
||||||
#define APPIRATER_RATE_BUTTON [NSString stringWithFormat:@"Rate %@", APPIRATER_APP_NAME]
|
|
||||||
|
|
||||||
/*
|
|
||||||
Text for button to remind the user to review later.
|
|
||||||
*/
|
|
||||||
#define APPIRATER_RATE_LATER @"Remind me later"
|
|
||||||
|
|
||||||
/*
|
|
||||||
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 NO
|
|
||||||
|
|
||||||
@interface Appirater : NSObject <UIAlertViewDelegate> {
|
|
||||||
|
|
||||||
UIAlertView *ratingAlert;
|
|
||||||
}
|
|
||||||
|
|
||||||
@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:(int)p_app_id;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Tells Appirater that the app has launched, and on devices that do NOT
|
|
||||||
support multitasking, the 'uses' count will be incremented. You should
|
|
||||||
call this method at the end of your application delegate's
|
|
||||||
application:didFinishLaunchingWithOptions: method.
|
|
||||||
|
|
||||||
If the app has been used enough to be rated (and enough significant events),
|
|
||||||
you can suppress the rating alert
|
|
||||||
by passing NO for canPromptForRating. The rating alert will simply be postponed
|
|
||||||
until it is called again with YES for canPromptForRating. The rating alert
|
|
||||||
can also be triggered by appEnteredForeground: and userDidSignificantEvent:
|
|
||||||
(as long as you pass YES for canPromptForRating in those methods).
|
|
||||||
*/
|
|
||||||
+ (void)appLaunched:(BOOL)canPromptForRating app_id:(int)p_app_id;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Tells Appirater that the app was brought to the foreground on multitasking
|
|
||||||
devices. You should call this method from the application delegate's
|
|
||||||
applicationWillEnterForeground: method.
|
|
||||||
|
|
||||||
If the app has been used enough to be rated (and enough significant events),
|
|
||||||
you can suppress the rating alert
|
|
||||||
by passing NO for canPromptForRating. The rating alert will simply be postponed
|
|
||||||
until it is called again with YES for canPromptForRating. The rating alert
|
|
||||||
can also be triggered by appLaunched: and userDidSignificantEvent:
|
|
||||||
(as long as you pass YES for canPromptForRating in those methods).
|
|
||||||
*/
|
|
||||||
+ (void)appEnteredForeground:(BOOL)canPromptForRating;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Tells Appirater that the user performed a significant event. A significant
|
|
||||||
event is whatever you want it to be. If you're app is used to make VoIP
|
|
||||||
calls, then you might want to call this method whenever the user places
|
|
||||||
a call. If it's a game, you might want to call this whenever the user
|
|
||||||
beats a level boss.
|
|
||||||
|
|
||||||
If the user has performed enough significant events and used the app enough,
|
|
||||||
you can suppress the rating alert by passing NO for canPromptForRating. The
|
|
||||||
rating alert will simply be postponed until it is called again with YES for
|
|
||||||
canPromptForRating. The rating alert can also be triggered by appLaunched:
|
|
||||||
and appEnteredForeground: (as long as you pass YES for canPromptForRating
|
|
||||||
in those methods).
|
|
||||||
*/
|
|
||||||
+ (void)userDidSignificantEvent:(BOOL)canPromptForRating;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Tells Appirater to open the App Store page where the user can specify a
|
|
||||||
rating for the app. Also records the fact that this has happened, so the
|
|
||||||
user won't be prompted again to rate the app.
|
|
||||||
|
|
||||||
The only case where you should call this directly is if your app has an
|
|
||||||
explicit "Rate this app" command somewhere. In all other cases, don't worry
|
|
||||||
about calling this -- instead, just call the other functions listed above,
|
|
||||||
and let Appirater handle the bookkeeping of deciding when to ask the user
|
|
||||||
whether to rate the app.
|
|
||||||
*/
|
|
||||||
+ (void)rateApp;
|
|
||||||
|
|
||||||
@end
|
|
|
@ -1,732 +0,0 @@
|
||||||
/*
|
|
||||||
This file is part of Appirater.
|
|
||||||
|
|
||||||
Copyright (c) 2012, Arash Payan
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person
|
|
||||||
obtaining a copy of this software and associated documentation
|
|
||||||
files (the "Software"), to deal in the Software without
|
|
||||||
restriction, including without limitation the rights to use,
|
|
||||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the
|
|
||||||
Software is furnished to do so, subject to the following
|
|
||||||
conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
||||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* Appirater.m
|
|
||||||
* appirater
|
|
||||||
*
|
|
||||||
* Created by Arash Payan on 9/5/09.
|
|
||||||
* http://arashpayan.com
|
|
||||||
* Copyright 2012 Arash Payan. All rights reserved.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "Appirater.h"
|
|
||||||
#import <SystemConfiguration/SCNetworkReachability.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
|
|
||||||
#if ! __has_feature(objc_arc)
|
|
||||||
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NSString *const kAppiraterFirstUseDate = @"kAppiraterFirstUseDate";
|
|
||||||
NSString *const kAppiraterUseCount = @"kAppiraterUseCount";
|
|
||||||
NSString *const kAppiraterSignificantEventCount = @"kAppiraterSignificantEventCount";
|
|
||||||
NSString *const kAppiraterCurrentVersion = @"kAppiraterCurrentVersion";
|
|
||||||
NSString *const kAppiraterRatedCurrentVersion = @"kAppiraterRatedCurrentVersion";
|
|
||||||
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 *templateReviewURLiOS7 = @"itms-apps://itunes.apple.com/app/idAPP_ID";
|
|
||||||
NSString *templateReviewURLiOS8 = @"itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?id=APP_ID&onlyLatestVersion=true&pageNumber=0&sortOrdering=1&type=Purple+Software";
|
|
||||||
|
|
||||||
static NSString *_appId;
|
|
||||||
static double _daysUntilPrompt = 30;
|
|
||||||
static NSInteger _usesUntilPrompt = 20;
|
|
||||||
static NSInteger _significantEventsUntilPrompt = -1;
|
|
||||||
static double _timeBeforeReminding = 1;
|
|
||||||
static BOOL _debug = NO;
|
|
||||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0
|
|
||||||
static id<AppiraterDelegate> _delegate;
|
|
||||||
#else
|
|
||||||
__weak static id<AppiraterDelegate> _delegate;
|
|
||||||
#endif
|
|
||||||
static BOOL _usesAnimation = TRUE;
|
|
||||||
static UIStatusBarStyle _statusBarStyle;
|
|
||||||
static BOOL _modalOpen = false;
|
|
||||||
static BOOL _alwaysUseMainBundle = NO;
|
|
||||||
|
|
||||||
@interface Appirater ()
|
|
||||||
@property (nonatomic, copy) NSString *alertTitle;
|
|
||||||
@property (nonatomic, copy) NSString *alertMessage;
|
|
||||||
@property (nonatomic, copy) NSString *alertCancelTitle;
|
|
||||||
@property (nonatomic, copy) NSString *alertRateTitle;
|
|
||||||
@property (nonatomic, copy) NSString *alertRateLaterTitle;
|
|
||||||
- (BOOL)connectedToNetwork;
|
|
||||||
+ (Appirater*)sharedInstance;
|
|
||||||
- (void)showPromptWithChecks:(BOOL)withChecks
|
|
||||||
displayRateLaterButton:(BOOL)displayRateLaterButton;
|
|
||||||
- (void)showRatingAlert:(BOOL)displayRateLaterButton;
|
|
||||||
- (void)showRatingAlert;
|
|
||||||
- (BOOL)ratingAlertIsAppropriate;
|
|
||||||
- (BOOL)ratingConditionsHaveBeenMet;
|
|
||||||
- (void)incrementUseCount;
|
|
||||||
- (void)hideRatingAlert;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@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) setCustomAlertTitle:(NSString *)title
|
|
||||||
{
|
|
||||||
[self sharedInstance].alertTitle = title;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void) setCustomAlertMessage:(NSString *)message
|
|
||||||
{
|
|
||||||
[self sharedInstance].alertMessage = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void) setCustomAlertCancelButtonTitle:(NSString *)cancelTitle
|
|
||||||
{
|
|
||||||
[self sharedInstance].alertCancelTitle = cancelTitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void) setCustomAlertRateButtonTitle:(NSString *)rateTitle
|
|
||||||
{
|
|
||||||
[self sharedInstance].alertRateTitle = rateTitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void) setCustomAlertRateLaterButtonTitle:(NSString *)rateLaterTitle
|
|
||||||
{
|
|
||||||
[self sharedInstance].alertRateLaterTitle = rateLaterTitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void) setDebug:(BOOL)debug {
|
|
||||||
_debug = debug;
|
|
||||||
}
|
|
||||||
+ (void)setDelegate:(id<AppiraterDelegate>)delegate{
|
|
||||||
_delegate = delegate;
|
|
||||||
}
|
|
||||||
+ (void)setUsesAnimation:(BOOL)animation {
|
|
||||||
_usesAnimation = animation;
|
|
||||||
}
|
|
||||||
+ (void)setOpenInAppStore:(BOOL)openInAppStore {
|
|
||||||
[Appirater sharedInstance].openInAppStore = openInAppStore;
|
|
||||||
}
|
|
||||||
+ (void)setStatusBarStyle:(UIStatusBarStyle)style {
|
|
||||||
_statusBarStyle = style;
|
|
||||||
}
|
|
||||||
+ (void)setModalOpen:(BOOL)open {
|
|
||||||
_modalOpen = open;
|
|
||||||
}
|
|
||||||
+ (void)setAlwaysUseMainBundle:(BOOL)alwaysUseMainBundle {
|
|
||||||
_alwaysUseMainBundle = alwaysUseMainBundle;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSBundle *)bundle
|
|
||||||
{
|
|
||||||
NSBundle *bundle;
|
|
||||||
|
|
||||||
if (_alwaysUseMainBundle) {
|
|
||||||
bundle = [NSBundle mainBundle];
|
|
||||||
} else {
|
|
||||||
NSURL *appiraterBundleURL = [[NSBundle mainBundle] URLForResource:@"Appirater" withExtension:@"bundle"];
|
|
||||||
|
|
||||||
if (appiraterBundleURL) {
|
|
||||||
// Appirater.bundle will likely only exist when used via CocoaPods
|
|
||||||
bundle = [NSBundle bundleWithURL:appiraterBundleURL];
|
|
||||||
} else {
|
|
||||||
bundle = [NSBundle mainBundle];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bundle;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)alertTitle
|
|
||||||
{
|
|
||||||
return _alertTitle ? _alertTitle : APPIRATER_MESSAGE_TITLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)alertMessage
|
|
||||||
{
|
|
||||||
return _alertMessage ? _alertMessage : APPIRATER_MESSAGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)alertCancelTitle
|
|
||||||
{
|
|
||||||
return _alertCancelTitle ? _alertCancelTitle : APPIRATER_CANCEL_BUTTON;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)alertRateTitle
|
|
||||||
{
|
|
||||||
return _alertRateTitle ? _alertRateTitle : APPIRATER_RATE_BUTTON;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)alertRateLaterTitle
|
|
||||||
{
|
|
||||||
return _alertRateLaterTitle ? _alertRateLaterTitle : APPIRATER_RATE_LATER;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)dealloc {
|
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)init {
|
|
||||||
self = [super init];
|
|
||||||
if (self) {
|
|
||||||
if ([[UIDevice currentDevice].systemVersion floatValue] >= 7.0) {
|
|
||||||
self.openInAppStore = YES;
|
|
||||||
} else {
|
|
||||||
self.openInAppStore = NO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)connectedToNetwork {
|
|
||||||
// Create zero addy
|
|
||||||
struct sockaddr_in zeroAddress;
|
|
||||||
bzero(&zeroAddress, sizeof(zeroAddress));
|
|
||||||
zeroAddress.sin_len = sizeof(zeroAddress);
|
|
||||||
zeroAddress.sin_family = AF_INET;
|
|
||||||
|
|
||||||
// Recover reachability flags
|
|
||||||
SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress);
|
|
||||||
SCNetworkReachabilityFlags flags;
|
|
||||||
|
|
||||||
Boolean didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
|
|
||||||
CFRelease(defaultRouteReachability);
|
|
||||||
|
|
||||||
if (!didRetrieveFlags)
|
|
||||||
{
|
|
||||||
NSLog(@"Error. Could not recover network reachability flags");
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL isReachable = flags & kSCNetworkFlagsReachable;
|
|
||||||
BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired;
|
|
||||||
BOOL nonWiFi = flags & kSCNetworkReachabilityFlagsTransientConnection;
|
|
||||||
|
|
||||||
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];
|
|
||||||
|
|
||||||
return ((isReachable && !needsConnection) || nonWiFi) ? (testConnection ? YES : NO) : NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (Appirater*)sharedInstance {
|
|
||||||
static Appirater *appirater = nil;
|
|
||||||
if (appirater == nil)
|
|
||||||
{
|
|
||||||
static dispatch_once_t onceToken;
|
|
||||||
dispatch_once(&onceToken, ^{
|
|
||||||
appirater = [[Appirater alloc] init];
|
|
||||||
appirater.delegate = _delegate;
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillResignActive) name:
|
|
||||||
UIApplicationWillResignActiveNotification object:nil];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return appirater;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)showRatingAlert:(BOOL)displayRateLaterButton {
|
|
||||||
UIAlertView *alertView = nil;
|
|
||||||
id <AppiraterDelegate> delegate = _delegate;
|
|
||||||
|
|
||||||
if(delegate && [delegate respondsToSelector:@selector(appiraterShouldDisplayAlert:)] && ![delegate appiraterShouldDisplayAlert:self]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (displayRateLaterButton) {
|
|
||||||
alertView = [[UIAlertView alloc] initWithTitle:self.alertTitle
|
|
||||||
message:self.alertMessage
|
|
||||||
delegate:self
|
|
||||||
cancelButtonTitle:self.alertCancelTitle
|
|
||||||
otherButtonTitles:self.alertRateTitle, self.alertRateLaterTitle, nil];
|
|
||||||
} else {
|
|
||||||
alertView = [[UIAlertView alloc] initWithTitle:self.alertTitle
|
|
||||||
message:self.alertMessage
|
|
||||||
delegate:self
|
|
||||||
cancelButtonTitle:self.alertCancelTitle
|
|
||||||
otherButtonTitles:self.alertRateTitle, nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
self.ratingAlert = alertView;
|
|
||||||
[alertView show];
|
|
||||||
|
|
||||||
if (delegate && [delegate respondsToSelector:@selector(appiraterDidDisplayAlert:)]) {
|
|
||||||
[delegate appiraterDidDisplayAlert:self];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)showRatingAlert
|
|
||||||
{
|
|
||||||
[self showRatingAlert:true];
|
|
||||||
}
|
|
||||||
|
|
||||||
// is this an ok time to show the alert? (regardless of whether the rating conditions have been met)
|
|
||||||
//
|
|
||||||
// things checked here:
|
|
||||||
// * connectivity with network
|
|
||||||
// * whether user has rated before
|
|
||||||
// * whether user has declined to rate
|
|
||||||
// * whether rating alert is currently showing visibly
|
|
||||||
// things NOT checked here:
|
|
||||||
// * time since first launch
|
|
||||||
// * number of uses of app
|
|
||||||
// * number of significant events
|
|
||||||
// * time since last reminder
|
|
||||||
- (BOOL)ratingAlertIsAppropriate {
|
|
||||||
return ([self connectedToNetwork]
|
|
||||||
&& ![self userHasDeclinedToRate]
|
|
||||||
&& !self.ratingAlert.visible
|
|
||||||
&& ![self userHasRatedCurrentVersion]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// have the rating conditions been met/earned? (regardless of whether this would be a moment when it's appropriate to show a new rating alert)
|
|
||||||
//
|
|
||||||
// things checked here:
|
|
||||||
// * time since first launch
|
|
||||||
// * number of uses of app
|
|
||||||
// * number of significant events
|
|
||||||
// * time since last reminder
|
|
||||||
// things NOT checked here:
|
|
||||||
// * connectivity with network
|
|
||||||
// * whether user has rated before
|
|
||||||
// * whether user has declined to rate
|
|
||||||
// * whether rating alert is currently showing visibly
|
|
||||||
- (BOOL)ratingConditionsHaveBeenMet {
|
|
||||||
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 * _daysUntilPrompt;
|
|
||||||
if (timeSinceFirstLaunch < timeUntilRate)
|
|
||||||
return NO;
|
|
||||||
|
|
||||||
// check if the app has been used enough
|
|
||||||
NSInteger useCount = [userDefaults integerForKey:kAppiraterUseCount];
|
|
||||||
if (useCount < _usesUntilPrompt)
|
|
||||||
return NO;
|
|
||||||
|
|
||||||
// check if the user has done enough significant events
|
|
||||||
NSInteger sigEventCount = [userDefaults integerForKey:kAppiraterSignificantEventCount];
|
|
||||||
if (sigEventCount < _significantEventsUntilPrompt)
|
|
||||||
return NO;
|
|
||||||
|
|
||||||
// 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 * _timeBeforeReminding;
|
|
||||||
if (timeSinceReminderRequest < timeUntilReminder)
|
|
||||||
return NO;
|
|
||||||
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (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];
|
|
||||||
if (trackingVersion == nil)
|
|
||||||
{
|
|
||||||
trackingVersion = version;
|
|
||||||
[userDefaults setObject:version forKey:kAppiraterCurrentVersion];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_debug)
|
|
||||||
NSLog(@"APPIRATER Tracking version: %@", trackingVersion);
|
|
||||||
|
|
||||||
if ([trackingVersion isEqualToString:version])
|
|
||||||
{
|
|
||||||
// check if the first use date has been set. if not, set it.
|
|
||||||
NSTimeInterval timeInterval = [userDefaults doubleForKey:kAppiraterFirstUseDate];
|
|
||||||
if (timeInterval == 0)
|
|
||||||
{
|
|
||||||
timeInterval = [[NSDate date] timeIntervalSince1970];
|
|
||||||
[userDefaults setDouble:timeInterval forKey:kAppiraterFirstUseDate];
|
|
||||||
}
|
|
||||||
|
|
||||||
// increment the use count
|
|
||||||
NSInteger useCount = [userDefaults integerForKey:kAppiraterUseCount];
|
|
||||||
useCount++;
|
|
||||||
[userDefaults setInteger:useCount forKey:kAppiraterUseCount];
|
|
||||||
if (_debug)
|
|
||||||
NSLog(@"APPIRATER Use count: %@", @(useCount));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// it's a new version of the app, so restart tracking
|
|
||||||
[userDefaults setObject:version forKey:kAppiraterCurrentVersion];
|
|
||||||
[userDefaults setDouble:[[NSDate date] timeIntervalSince1970] forKey:kAppiraterFirstUseDate];
|
|
||||||
[userDefaults setInteger:1 forKey:kAppiraterUseCount];
|
|
||||||
[userDefaults setInteger:0 forKey:kAppiraterSignificantEventCount];
|
|
||||||
[userDefaults setBool:NO forKey:kAppiraterRatedCurrentVersion];
|
|
||||||
[userDefaults setBool:NO forKey:kAppiraterDeclinedToRate];
|
|
||||||
[userDefaults setDouble:0 forKey:kAppiraterReminderRequestDate];
|
|
||||||
}
|
|
||||||
|
|
||||||
[userDefaults synchronize];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)incrementSignificantEventCount {
|
|
||||||
// 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];
|
|
||||||
if (trackingVersion == nil)
|
|
||||||
{
|
|
||||||
trackingVersion = version;
|
|
||||||
[userDefaults setObject:version forKey:kAppiraterCurrentVersion];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_debug)
|
|
||||||
NSLog(@"APPIRATER Tracking version: %@", trackingVersion);
|
|
||||||
|
|
||||||
if ([trackingVersion isEqualToString:version])
|
|
||||||
{
|
|
||||||
// check if the first use date has been set. if not, set it.
|
|
||||||
NSTimeInterval timeInterval = [userDefaults doubleForKey:kAppiraterFirstUseDate];
|
|
||||||
if (timeInterval == 0)
|
|
||||||
{
|
|
||||||
timeInterval = [[NSDate date] timeIntervalSince1970];
|
|
||||||
[userDefaults setDouble:timeInterval forKey:kAppiraterFirstUseDate];
|
|
||||||
}
|
|
||||||
|
|
||||||
// increment the significant event count
|
|
||||||
NSInteger sigEventCount = [userDefaults integerForKey:kAppiraterSignificantEventCount];
|
|
||||||
sigEventCount++;
|
|
||||||
[userDefaults setInteger:sigEventCount forKey:kAppiraterSignificantEventCount];
|
|
||||||
if (_debug)
|
|
||||||
NSLog(@"APPIRATER Significant event count: %@", @(sigEventCount));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// it's a new version of the app, so restart tracking
|
|
||||||
[userDefaults setObject:version forKey:kAppiraterCurrentVersion];
|
|
||||||
[userDefaults setDouble:0 forKey:kAppiraterFirstUseDate];
|
|
||||||
[userDefaults setInteger:0 forKey:kAppiraterUseCount];
|
|
||||||
[userDefaults setInteger:1 forKey:kAppiraterSignificantEventCount];
|
|
||||||
[userDefaults setBool:NO forKey:kAppiraterRatedCurrentVersion];
|
|
||||||
[userDefaults setBool:NO forKey:kAppiraterDeclinedToRate];
|
|
||||||
[userDefaults setDouble:0 forKey:kAppiraterReminderRequestDate];
|
|
||||||
}
|
|
||||||
|
|
||||||
[userDefaults synchronize];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)incrementAndRate:(BOOL)canPromptForRating {
|
|
||||||
[self incrementUseCount];
|
|
||||||
|
|
||||||
if (canPromptForRating &&
|
|
||||||
[self ratingConditionsHaveBeenMet] &&
|
|
||||||
[self ratingAlertIsAppropriate])
|
|
||||||
{
|
|
||||||
dispatch_async(dispatch_get_main_queue(),
|
|
||||||
^{
|
|
||||||
[self showRatingAlert];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)incrementSignificantEventAndRate:(BOOL)canPromptForRating {
|
|
||||||
[self incrementSignificantEventCount];
|
|
||||||
|
|
||||||
if (canPromptForRating &&
|
|
||||||
[self ratingConditionsHaveBeenMet] &&
|
|
||||||
[self ratingAlertIsAppropriate])
|
|
||||||
{
|
|
||||||
dispatch_async(dispatch_get_main_queue(),
|
|
||||||
^{
|
|
||||||
[self showRatingAlert];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)userHasDeclinedToRate {
|
|
||||||
return [[NSUserDefaults standardUserDefaults] boolForKey:kAppiraterDeclinedToRate];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)userHasRatedCurrentVersion {
|
|
||||||
return [[NSUserDefaults standardUserDefaults] boolForKey:kAppiraterRatedCurrentVersion];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wdeprecated-implementations"
|
|
||||||
+ (void)appLaunched {
|
|
||||||
[Appirater appLaunched:YES];
|
|
||||||
}
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
|
|
||||||
+ (void)appLaunched:(BOOL)canPromptForRating {
|
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
|
|
||||||
^{
|
|
||||||
Appirater *a = [Appirater sharedInstance];
|
|
||||||
if (_debug) {
|
|
||||||
dispatch_async(dispatch_get_main_queue(),
|
|
||||||
^{
|
|
||||||
[a showRatingAlert];
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
[a incrementAndRate:canPromptForRating];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)hideRatingAlert {
|
|
||||||
if (self.ratingAlert.visible) {
|
|
||||||
if (_debug)
|
|
||||||
NSLog(@"APPIRATER Hiding Alert");
|
|
||||||
[self.ratingAlert dismissWithClickedButtonIndex:-1 animated:NO];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)appWillResignActive {
|
|
||||||
if (_debug)
|
|
||||||
NSLog(@"APPIRATER appWillResignActive");
|
|
||||||
[[Appirater sharedInstance] hideRatingAlert];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)appEnteredForeground:(BOOL)canPromptForRating {
|
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
|
|
||||||
^{
|
|
||||||
[[Appirater sharedInstance] incrementAndRate:canPromptForRating];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)userDidSignificantEvent:(BOOL)canPromptForRating {
|
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
|
|
||||||
^{
|
|
||||||
[[Appirater sharedInstance] incrementSignificantEventAndRate:canPromptForRating];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wdeprecated-implementations"
|
|
||||||
+ (void)showPrompt {
|
|
||||||
[Appirater tryToShowPrompt];
|
|
||||||
}
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
|
|
||||||
+ (void)tryToShowPrompt {
|
|
||||||
[[Appirater sharedInstance] showPromptWithChecks:true
|
|
||||||
displayRateLaterButton:true];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)forceShowPrompt:(BOOL)displayRateLaterButton {
|
|
||||||
[[Appirater sharedInstance] showPromptWithChecks:false
|
|
||||||
displayRateLaterButton:displayRateLaterButton];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)showPromptWithChecks:(BOOL)withChecks
|
|
||||||
displayRateLaterButton:(BOOL)displayRateLaterButton {
|
|
||||||
if (withChecks == NO || [self ratingAlertIsAppropriate]) {
|
|
||||||
[self showRatingAlert:displayRateLaterButton];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (id)getRootViewController {
|
|
||||||
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
|
|
||||||
if (window.windowLevel != UIWindowLevelNormal) {
|
|
||||||
NSArray *windows = [[UIApplication sharedApplication] windows];
|
|
||||||
for(window in windows) {
|
|
||||||
if (window.windowLevel == UIWindowLevelNormal) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [Appirater iterateSubViewsForViewController:window]; // iOS 8+ deep traverse
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (id)iterateSubViewsForViewController:(UIView *) parentView {
|
|
||||||
for (UIView *subView in [parentView subviews]) {
|
|
||||||
UIResponder *responder = [subView nextResponder];
|
|
||||||
if([responder isKindOfClass:[UIViewController class]]) {
|
|
||||||
return [self topMostViewController: (UIViewController *) responder];
|
|
||||||
}
|
|
||||||
id found = [Appirater iterateSubViewsForViewController:subView];
|
|
||||||
if( nil != found) {
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (UIViewController *) topMostViewController: (UIViewController *) controller {
|
|
||||||
BOOL isPresenting = NO;
|
|
||||||
do {
|
|
||||||
// this path is called only on iOS 6+, so -presentedViewController is fine here.
|
|
||||||
UIViewController *presented = [controller presentedViewController];
|
|
||||||
isPresenting = presented != nil;
|
|
||||||
if(presented != nil) {
|
|
||||||
controller = presented;
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (isPresenting);
|
|
||||||
|
|
||||||
return controller;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)rateApp {
|
|
||||||
|
|
||||||
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
|
|
||||||
[userDefaults setBool:YES forKey:kAppiraterRatedCurrentVersion];
|
|
||||||
[userDefaults synchronize];
|
|
||||||
|
|
||||||
//Use the in-app StoreKit view if available (iOS 6) and imported. This works in the simulator.
|
|
||||||
if (![Appirater sharedInstance].openInAppStore && NSStringFromClass([SKStoreProductViewController class]) != nil) {
|
|
||||||
|
|
||||||
SKStoreProductViewController *storeViewController = [[SKStoreProductViewController alloc] init];
|
|
||||||
NSNumber *appId = [NSNumber numberWithInteger:_appId.integerValue];
|
|
||||||
[storeViewController loadProductWithParameters:@{SKStoreProductParameterITunesItemIdentifier:appId} completionBlock:nil];
|
|
||||||
storeViewController.delegate = self.sharedInstance;
|
|
||||||
|
|
||||||
id <AppiraterDelegate> delegate = self.sharedInstance.delegate;
|
|
||||||
if ([delegate respondsToSelector:@selector(appiraterWillPresentModalView:animated:)]) {
|
|
||||||
[delegate appiraterWillPresentModalView:self.sharedInstance animated:_usesAnimation];
|
|
||||||
}
|
|
||||||
[[self getRootViewController] presentViewController:storeViewController animated:_usesAnimation completion:^{
|
|
||||||
[self setModalOpen:YES];
|
|
||||||
//Temporarily use a black status bar to match the StoreKit view.
|
|
||||||
[self setStatusBarStyle:[UIApplication sharedApplication].statusBarStyle];
|
|
||||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
|
|
||||||
[[UIApplication sharedApplication]setStatusBarStyle:UIStatusBarStyleLightContent animated:_usesAnimation];
|
|
||||||
#endif
|
|
||||||
}];
|
|
||||||
|
|
||||||
//Use the standard openUrl method if StoreKit is unavailable.
|
|
||||||
} else {
|
|
||||||
|
|
||||||
#if TARGET_IPHONE_SIMULATOR
|
|
||||||
NSLog(@"APPIRATER NOTE: iTunes App Store is not supported on the iOS simulator. Unable to open App Store page.");
|
|
||||||
#else
|
|
||||||
NSString *reviewURL = [templateReviewURL stringByReplacingOccurrencesOfString:@"APP_ID" withString:[NSString stringWithFormat:@"%@", _appId]];
|
|
||||||
|
|
||||||
// iOS 7 needs a different templateReviewURL @see https://github.com/arashpayan/appirater/issues/131
|
|
||||||
// Fixes condition @see https://github.com/arashpayan/appirater/issues/205
|
|
||||||
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0 && [[[UIDevice currentDevice] systemVersion] floatValue] < 8.0) {
|
|
||||||
reviewURL = [templateReviewURLiOS7 stringByReplacingOccurrencesOfString:@"APP_ID" withString:[NSString stringWithFormat:@"%@", _appId]];
|
|
||||||
}
|
|
||||||
// iOS 8 needs a different templateReviewURL also @see https://github.com/arashpayan/appirater/issues/182
|
|
||||||
else if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
|
|
||||||
{
|
|
||||||
reviewURL = [templateReviewURLiOS8 stringByReplacingOccurrencesOfString:@"APP_ID" withString:[NSString stringWithFormat:@"%@", _appId]];
|
|
||||||
}
|
|
||||||
|
|
||||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:reviewURL]];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
|
|
||||||
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
|
|
||||||
|
|
||||||
id <AppiraterDelegate> delegate = _delegate;
|
|
||||||
|
|
||||||
switch (buttonIndex) {
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
// they don't want to rate it
|
|
||||||
[userDefaults setBool:YES forKey:kAppiraterDeclinedToRate];
|
|
||||||
[userDefaults synchronize];
|
|
||||||
if(delegate && [delegate respondsToSelector:@selector(appiraterDidDeclineToRate:)]){
|
|
||||||
[delegate appiraterDidDeclineToRate:self];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
// they want to rate it
|
|
||||||
[Appirater rateApp];
|
|
||||||
if(delegate&& [delegate respondsToSelector:@selector(appiraterDidOptToRate:)]){
|
|
||||||
[delegate appiraterDidOptToRate:self];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
// remind them later
|
|
||||||
[userDefaults setDouble:[[NSDate date] timeIntervalSince1970] forKey:kAppiraterReminderRequestDate];
|
|
||||||
[userDefaults synchronize];
|
|
||||||
if(delegate && [delegate respondsToSelector:@selector(appiraterDidOptToRemindLater:)]){
|
|
||||||
[delegate appiraterDidOptToRemindLater:self];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Delegate call from the StoreKit view.
|
|
||||||
- (void)productViewControllerDidFinish:(SKStoreProductViewController *)viewController {
|
|
||||||
[Appirater closeModal];
|
|
||||||
}
|
|
||||||
|
|
||||||
//Close the in-app rating (StoreKit) view and restore the previous status bar style.
|
|
||||||
+ (void)closeModal {
|
|
||||||
if (_modalOpen) {
|
|
||||||
[[UIApplication sharedApplication]setStatusBarStyle:_statusBarStyle animated:_usesAnimation];
|
|
||||||
BOOL usedAnimation = _usesAnimation;
|
|
||||||
[self setModalOpen:NO];
|
|
||||||
|
|
||||||
// get the top most controller (= the StoreKit Controller) and dismiss it
|
|
||||||
UIViewController *presentingController = [UIApplication sharedApplication].keyWindow.rootViewController;
|
|
||||||
presentingController = [self topMostViewController: presentingController];
|
|
||||||
[presentingController dismissViewControllerAnimated:_usesAnimation completion:^{
|
|
||||||
id <AppiraterDelegate> delegate = self.sharedInstance.delegate;
|
|
||||||
if ([delegate respondsToSelector:@selector(appiraterDidDismissModalView:animated:)]) {
|
|
||||||
[delegate appiraterDidDismissModalView:(Appirater *)self animated:usedAnimation];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
[self.class setStatusBarStyle:(UIStatusBarStyle)nil];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
|
@ -1,23 +0,0 @@
|
||||||
//
|
|
||||||
// AppiraterDelegate.h
|
|
||||||
// Banana Stand
|
|
||||||
//
|
|
||||||
// Created by Robert Haining on 9/25/12.
|
|
||||||
// Copyright (c) 2012 News.me. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
@class Appirater;
|
|
||||||
|
|
||||||
@protocol AppiraterDelegate <NSObject>
|
|
||||||
|
|
||||||
@optional
|
|
||||||
-(BOOL)appiraterShouldDisplayAlert:(Appirater *)appirater;
|
|
||||||
-(void)appiraterDidDisplayAlert:(Appirater *)appirater;
|
|
||||||
-(void)appiraterDidDeclineToRate:(Appirater *)appirater;
|
|
||||||
-(void)appiraterDidOptToRate:(Appirater *)appirater;
|
|
||||||
-(void)appiraterDidOptToRemindLater:(Appirater *)appirater;
|
|
||||||
-(void)appiraterWillPresentModalView:(Appirater *)appirater animated:(BOOL)animated;
|
|
||||||
-(void)appiraterDidDismissModalView:(Appirater *)appirater animated:(BOOL)animated;
|
|
||||||
@end
|
|
|
@ -15,7 +15,6 @@ iphone_lib = [
|
||||||
'game_center.mm',
|
'game_center.mm',
|
||||||
'in_app_store.mm',
|
'in_app_store.mm',
|
||||||
'icloud.mm',
|
'icloud.mm',
|
||||||
#'Appirater.m',
|
|
||||||
'ios.mm',
|
'ios.mm',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -30,10 +29,6 @@ if env['ios_gles22_override'] == "yes":
|
||||||
env_ios.Append(CPPFLAGS=['-DGLES2_OVERRIDE'])
|
env_ios.Append(CPPFLAGS=['-DGLES2_OVERRIDE'])
|
||||||
|
|
||||||
|
|
||||||
# if env['ios_appirater'] == "yes":
|
|
||||||
# env_ios.Append(CPPFLAGS=['-DAPPIRATER_ENABLED'])
|
|
||||||
|
|
||||||
|
|
||||||
obj = env_ios.Object('godot_iphone.cpp')
|
obj = env_ios.Object('godot_iphone.cpp')
|
||||||
|
|
||||||
prog = None
|
prog = None
|
||||||
|
|
|
@ -52,10 +52,6 @@
|
||||||
#define kRenderingFrequency 60
|
#define kRenderingFrequency 60
|
||||||
#define kAccelerometerFrequency 100.0 // Hz
|
#define kAccelerometerFrequency 100.0 // Hz
|
||||||
|
|
||||||
#ifdef APPIRATER_ENABLED
|
|
||||||
#import "Appirater.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Error _shell_open(String);
|
Error _shell_open(String);
|
||||||
void _set_keep_screen_on(bool p_enabled);
|
void _set_keep_screen_on(bool p_enabled);
|
||||||
|
|
||||||
|
@ -188,11 +184,6 @@ static int frame_count = 0;
|
||||||
Main::start();
|
Main::start();
|
||||||
++frame_count;
|
++frame_count;
|
||||||
|
|
||||||
#ifdef APPIRATER_ENABLED
|
|
||||||
int aid = GlobalConfig::get_singleton()->get("ios/app_id");
|
|
||||||
[Appirater appLaunched:YES app_id:aid];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}; break; // no fallthrough
|
}; break; // no fallthrough
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
|
|
|
@ -30,7 +30,6 @@ def get_opts():
|
||||||
('store_kit', 'Support for in-app store', 'yes'),
|
('store_kit', 'Support for in-app store', 'yes'),
|
||||||
('icloud', 'Support for iCloud', 'yes'),
|
('icloud', 'Support for iCloud', 'yes'),
|
||||||
('ios_gles22_override', 'Force GLES2.0 on iOS', 'yes'),
|
('ios_gles22_override', 'Force GLES2.0 on iOS', 'yes'),
|
||||||
('ios_appirater', 'Enable Appirater', 'no'),
|
|
||||||
('ios_exceptions', 'Use exceptions when compiling on playbook', 'yes'),
|
('ios_exceptions', 'Use exceptions when compiling on playbook', 'yes'),
|
||||||
('ios_triple', 'Triple for ios toolchain', ''),
|
('ios_triple', 'Triple for ios toolchain', ''),
|
||||||
('ios_sim', 'Build simulator binary', 'no'),
|
('ios_sim', 'Build simulator binary', 'no'),
|
||||||
|
|
Loading…
Reference in a new issue