Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

overriding display name and adding metrics notifications #161

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions Appirater.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,27 @@ extern NSString *const kAppiraterRatedCurrentVersion;
extern NSString *const kAppiraterDeclinedToRate;
extern NSString *const kAppiraterReminderRequestDate;

/*!
Your localized special app's name.
to override the localized app display name: CFBundleDisplayName
*/
#define APPIRATER_LOCALIZED_SPECIAL_APP_NAME [[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:@"ARAppName"]

/*!
Your localized app's name.
*/
#define APPIRATER_LOCALIZED_APP_NAME [[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:@"CFBundleDisplayName"]
#define APPIRATER_LOCALIZED_APP_NAME APPIRATER_LOCALIZED_SPECIAL_APP_NAME ? APPIRATER_LOCALIZED_SPECIAL_APP_NAME : [[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:@"CFBundleDisplayName"]

/*!
Your special app's name.
to override the app display name: CFBundleDisplayName
*/
#define APPIRATER_SPECIAL_APP_NAME APPIRATER_LOCALIZED_APP_NAME ? APPIRATER_LOCALIZED_APP_NAME : [[[NSBundle mainBundle] infoDictionary] objectForKey:@"ARAppName"]

/*!
Your app's name.
*/
#define APPIRATER_APP_NAME APPIRATER_LOCALIZED_APP_NAME ? APPIRATER_LOCALIZED_APP_NAME : [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"]
#define APPIRATER_APP_NAME APPIRATER_SPECIAL_APP_NAME ? APPIRATER_SPECIAL_APP_NAME : [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"]

/*!
This is the message your users will see once they've passed the day+launches
Expand Down Expand Up @@ -85,12 +97,12 @@ extern NSString *const kAppiraterReminderRequestDate;
*/
#define APPIRATER_RATE_LATER NSLocalizedStringFromTableInBundle(@"Remind me later", @"AppiraterLocalizable", [Appirater bundle], nil)

@interface Appirater : NSObject <UIAlertViewDelegate, SKStoreProductViewControllerDelegate> {
@interface Appirater : NSObject <SKStoreProductViewControllerDelegate> {

UIAlertView *ratingAlert;
UIAlertController *ratingAlert;
}

@property(nonatomic, strong) UIAlertView *ratingAlert;
@property(nonatomic, strong) UIAlertController *ratingAlert;
@property(nonatomic) BOOL openInAppStore;
#if __has_feature(objc_arc_weak)
@property(nonatomic, weak) NSObject <AppiraterDelegate> *delegate;
Expand Down Expand Up @@ -261,15 +273,3 @@ extern NSString *const kAppiraterReminderRequestDate;
+(NSBundle *)bundle;

@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
165 changes: 102 additions & 63 deletions Appirater.m
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
*/

#import "Appirater.h"
#import "AppiraterMetrics.h"
#import <SystemConfiguration/SCNetworkReachability.h>
#include <netinet/in.h>

Expand All @@ -50,6 +51,11 @@
NSString *const kAppiraterDeclinedToRate = @"kAppiraterDeclinedToRate";
NSString *const kAppiraterReminderRequestDate = @"kAppiraterReminderRequestDate";

NSString *const ARAppiraterDidDisplayAlertNotification = @"ARAppiraterDidDisplayAlertNotification";
NSString *const ARAppiraterDidDeclineToRateNotification = @"ARAppiraterDidDeclineToRateNotification";
NSString *const ARAppiraterDidOptToRateNotification = @"ARAppiraterDidOptToRateNotification";
NSString *const ARAppiraterDidOptToRemindLaterNotification = @"ARAppiraterDidOptToRemindLaterNotification";

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";

Expand Down Expand Up @@ -78,7 +84,7 @@ - (void)incrementUseCount;
- (void)hideRatingAlert;
@end

@implementation Appirater
@implementation Appirater

@synthesize ratingAlert;

Expand Down Expand Up @@ -176,16 +182,25 @@ - (BOOL)connectedToNetwork {
NSLog(@"Error. Could not recover network reachability flags");
return NO;
}

// needsConnection check is not needed, because testConnection will always contains NSURLConnection address
// to remove needsConnection and testConnection from the checks below

BOOL isReachable = flags & kSCNetworkFlagsReachable;
BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired;
//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];
//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;
//return ((isReachable && !needsConnection) || nonWiFi) ? (testConnection ? YES : NO) : NO;
// after removing needs connection check
BOOL connected = (isReachable || nonWiFi) ? YES : NO;
if (_debug) {
NSLog(@"APPIRATER connected to network: %@", (connected ? @"Yes" : @"No"));
}
return connected;
}

+ (Appirater*)sharedInstance {
Expand All @@ -205,17 +220,81 @@ + (Appirater*)sharedInstance {
}

- (void)showRatingAlert {
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];
self.ratingAlert = alertView;
[alertView show];

id <AppiraterDelegate> delegate = _delegate;
if (delegate && [delegate respondsToSelector:@selector(appiraterDidDisplayAlert:)]) {
[delegate appiraterDidDisplayAlert:self];

if (@available(iOS 10.3, *)) {

// use the new built-in review prompt starting from 10.3

[SKStoreReviewController requestReview];

// record it as if user rated to avoid prompting again for this same version
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setBool:YES forKey:kAppiraterRatedCurrentVersion];
[userDefaults synchronize];

// send notification as if rating alert is shown
[[NSNotificationCenter defaultCenter] postNotificationName:ARAppiraterDidDisplayAlertNotification object:self];

} else {

UIAlertController *alert = [UIAlertController alertControllerWithTitle:APPIRATER_MESSAGE_TITLE
message:APPIRATER_MESSAGE
preferredStyle:UIAlertControllerStyleAlert];

self.ratingAlert = alert;

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
id <AppiraterDelegate> delegate = _delegate;

UIAlertAction *cancelAction = [UIAlertAction
actionWithTitle:APPIRATER_CANCEL_BUTTON
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * _Nonnull action) {
// they don't want to rate it
[userDefaults setBool:YES forKey:kAppiraterDeclinedToRate];
[userDefaults synchronize];
if(delegate && [delegate respondsToSelector:@selector(appiraterDidDeclineToRate:)]){
[delegate appiraterDidDeclineToRate:self];
}
[[NSNotificationCenter defaultCenter] postNotificationName:ARAppiraterDidDeclineToRateNotification object:self];
}];

UIAlertAction *rateAction = [UIAlertAction
actionWithTitle:APPIRATER_RATE_BUTTON
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
// they want to rate it
[Appirater rateApp];
if(delegate&& [delegate respondsToSelector:@selector(appiraterDidOptToRate:)]){
[delegate appiraterDidOptToRate:self];
}
[[NSNotificationCenter defaultCenter] postNotificationName:ARAppiraterDidOptToRateNotification object:self];
}];

UIAlertAction *remindAction = [UIAlertAction
actionWithTitle:APPIRATER_RATE_LATER
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
// remind them later
[userDefaults setDouble:[[NSDate date] timeIntervalSince1970] forKey:kAppiraterReminderRequestDate];
[userDefaults synchronize];
if(delegate && [delegate respondsToSelector:@selector(appiraterDidOptToRemindLater:)]){
[delegate appiraterDidOptToRemindLater:self];
}
[[NSNotificationCenter defaultCenter] postNotificationName:ARAppiraterDidOptToRemindLaterNotification object:self];
}];

[alert addAction:cancelAction];
[alert addAction:rateAction];
[alert addAction:remindAction];

[[[self class] getRootViewController] presentViewController:alert animated:YES completion:^{
if (delegate && [delegate respondsToSelector:@selector(appiraterDidDisplayAlert:)]) {
[delegate appiraterDidDisplayAlert:self];
}
[[NSNotificationCenter defaultCenter] postNotificationName:ARAppiraterDidDisplayAlertNotification object:self];
}];

}
}

Expand Down Expand Up @@ -391,10 +470,6 @@ - (BOOL)userHasRatedCurrentVersion {
return [[NSUserDefaults standardUserDefaults] boolForKey:kAppiraterRatedCurrentVersion];
}

+ (void)appLaunched {
[Appirater appLaunched:YES];
}

+ (void)appLaunched:(BOOL)canPromptForRating {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
^{
Expand All @@ -403,10 +478,10 @@ + (void)appLaunched:(BOOL)canPromptForRating {
}

- (void)hideRatingAlert {
if (self.ratingAlert.visible) {
if (self.ratingAlert.presentingViewController) {
if (_debug)
NSLog(@"APPIRATER Hiding Alert");
[self.ratingAlert dismissWithClickedButtonIndex:-1 animated:NO];
[self.ratingAlert dismissViewControllerAnimated:NO completion:nil];
}
}

Expand Down Expand Up @@ -498,7 +573,8 @@ + (void)rateApp {
//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];
// setting status bar style is depcrecated since iOS 9
//[[UIApplication sharedApplication]setStatusBarStyle:UIStatusBarStyleLightContent animated:_usesAnimation];
#endif
}];

Expand All @@ -520,44 +596,6 @@ + (void)rateApp {
}
}

- (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];
Expand All @@ -566,7 +604,8 @@ - (void)productViewControllerDidFinish:(SKStoreProductViewController *)viewContr
//Close the in-app rating (StoreKit) view and restore the previous status bar style.
+ (void)closeModal {
if (_modalOpen) {
[[UIApplication sharedApplication]setStatusBarStyle:_statusBarStyle animated:_usesAnimation];
// setting status bar style is depcrecated since iOS 9
//[[UIApplication sharedApplication]setStatusBarStyle:_statusBarStyle animated:_usesAnimation];
BOOL usedAnimation = _usesAnimation;
[self setModalOpen:NO];

Expand Down
16 changes: 16 additions & 0 deletions AppiraterMetrics.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// AppiraterMetrics.h
// UnitConverter
//
// Created by Moustafa on 1/25/14.
// Copyright (c) 2014 XTApps. All rights reserved.
//

#import <Foundation/Foundation.h>

// notifications for different appirater events

extern NSString *const ARAppiraterDidDisplayAlertNotification;
extern NSString *const ARAppiraterDidDeclineToRateNotification;
extern NSString *const ARAppiraterDidOptToRateNotification;
extern NSString *const ARAppiraterDidOptToRemindLaterNotification;
Loading