From c5b538838ebb3e790e14f3f4a021ea4e56c43e83 Mon Sep 17 00:00:00 2001 From: Moustafa Date: Sat, 25 Jan 2014 14:12:23 +0200 Subject: [PATCH 01/12] added support to override display name property with another property ARAppName --- Appirater.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Appirater.h b/Appirater.h index 83fcc2a3..9b59fe31 100644 --- a/Appirater.h +++ b/Appirater.h @@ -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 From 73f000292c967bc8596176002772c7f3ffbf5469 Mon Sep 17 00:00:00 2001 From: Moustafa Date: Sat, 25 Jan 2014 20:01:14 +0200 Subject: [PATCH 02/12] added notifications for different states / responses to be used for metrics --- Appirater.m | 10 ++++++++++ AppiraterMetrics.h | 16 ++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 AppiraterMetrics.h diff --git a/Appirater.m b/Appirater.m index 19ca8156..151008c7 100644 --- a/Appirater.m +++ b/Appirater.m @@ -35,6 +35,7 @@ */ #import "Appirater.h" +#import "AppiraterMetrics.h" #import #include @@ -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"; @@ -217,6 +223,7 @@ - (void)showRatingAlert { if (delegate && [delegate respondsToSelector:@selector(appiraterDidDisplayAlert:)]) { [delegate appiraterDidDisplayAlert:self]; } + [[NSNotificationCenter defaultCenter] postNotificationName:ARAppiraterDidDisplayAlertNotification object:self]; } - (BOOL)ratingConditionsHaveBeenMet { @@ -534,6 +541,7 @@ - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger) if(delegate && [delegate respondsToSelector:@selector(appiraterDidDeclineToRate:)]){ [delegate appiraterDidDeclineToRate:self]; } + [[NSNotificationCenter defaultCenter] postNotificationName:ARAppiraterDidDeclineToRateNotification object:self]; break; } case 1: @@ -543,6 +551,7 @@ - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger) if(delegate&& [delegate respondsToSelector:@selector(appiraterDidOptToRate:)]){ [delegate appiraterDidOptToRate:self]; } + [[NSNotificationCenter defaultCenter] postNotificationName:ARAppiraterDidOptToRateNotification object:self]; break; } case 2: @@ -552,6 +561,7 @@ - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger) if(delegate && [delegate respondsToSelector:@selector(appiraterDidOptToRemindLater:)]){ [delegate appiraterDidOptToRemindLater:self]; } + [[NSNotificationCenter defaultCenter] postNotificationName:ARAppiraterDidOptToRemindLaterNotification object:self]; break; default: break; diff --git a/AppiraterMetrics.h b/AppiraterMetrics.h new file mode 100644 index 00000000..d0c08327 --- /dev/null +++ b/AppiraterMetrics.h @@ -0,0 +1,16 @@ +// +// AppiraterMetrics.h +// UnitConverter +// +// Created by Moustafa on 1/25/14. +// Copyright (c) 2014 XTApps. All rights reserved. +// + +#import + +// notifications for different appirater events + +NSString *const ARAppiraterDidDisplayAlertNotification; +NSString *const ARAppiraterDidDeclineToRateNotification; +NSString *const ARAppiraterDidOptToRateNotification; +NSString *const ARAppiraterDidOptToRemindLaterNotification; \ No newline at end of file From 122594ef951186c48d03437df949f6529a0a314b Mon Sep 17 00:00:00 2001 From: Moustafa Hassan Date: Sat, 12 Mar 2016 00:42:54 +0200 Subject: [PATCH 03/12] fix metrics constants to be extern --- AppiraterMetrics.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/AppiraterMetrics.h b/AppiraterMetrics.h index d0c08327..c0b8f1c5 100644 --- a/AppiraterMetrics.h +++ b/AppiraterMetrics.h @@ -10,7 +10,7 @@ // notifications for different appirater events -NSString *const ARAppiraterDidDisplayAlertNotification; -NSString *const ARAppiraterDidDeclineToRateNotification; -NSString *const ARAppiraterDidOptToRateNotification; -NSString *const ARAppiraterDidOptToRemindLaterNotification; \ No newline at end of file +extern NSString *const ARAppiraterDidDisplayAlertNotification; +extern NSString *const ARAppiraterDidDeclineToRateNotification; +extern NSString *const ARAppiraterDidOptToRateNotification; +extern NSString *const ARAppiraterDidOptToRemindLaterNotification; \ No newline at end of file From d49c122c47cfa75aa2490afdc2c7e2d1e0168b9e Mon Sep 17 00:00:00 2001 From: Moustafa Hassan Date: Sun, 6 May 2018 18:24:02 +0200 Subject: [PATCH 04/12] integrate new iOS 10.3 API for requesting review in app when the review is requested, it's assumed the user has rated the app --- Appirater.m | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/Appirater.m b/Appirater.m index 151008c7..632f30bd 100644 --- a/Appirater.m +++ b/Appirater.m @@ -211,19 +211,34 @@ + (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 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]; + + } else { + + 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 delegate = _delegate; + if (delegate && [delegate respondsToSelector:@selector(appiraterDidDisplayAlert:)]) { + [delegate appiraterDidDisplayAlert:self]; + } + [[NSNotificationCenter defaultCenter] postNotificationName:ARAppiraterDidDisplayAlertNotification object:self]; } - [[NSNotificationCenter defaultCenter] postNotificationName:ARAppiraterDidDisplayAlertNotification object:self]; } - (BOOL)ratingConditionsHaveBeenMet { From e6503c6fe9bb84e32ac2281f27bbd7cd6e260fdb Mon Sep 17 00:00:00 2001 From: Moustafa Hassan Date: Thu, 10 May 2018 00:45:22 +0200 Subject: [PATCH 05/12] send notification when new iOS 10.3 rating prompt is assumed to be shown --- Appirater.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Appirater.m b/Appirater.m index 632f30bd..3ef94bb2 100644 --- a/Appirater.m +++ b/Appirater.m @@ -223,6 +223,9 @@ - (void)showRatingAlert { [userDefaults setBool:YES forKey:kAppiraterRatedCurrentVersion]; [userDefaults synchronize]; + // send notification as if rating alert is shown + [[NSNotificationCenter defaultCenter] postNotificationName:ARAppiraterDidDisplayAlertNotification object:self]; + } else { UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:APPIRATER_MESSAGE_TITLE From a15d0d2abadb4ee0f0aff82086d0f09561b83e48 Mon Sep 17 00:00:00 2001 From: Moustafa Hassan Date: Tue, 19 Jun 2018 00:33:03 +0200 Subject: [PATCH 06/12] avoid setting status bar type directly because it's deprecated since iOS 9 --- Appirater.m | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Appirater.m b/Appirater.m index 3ef94bb2..044d1d3c 100644 --- a/Appirater.m +++ b/Appirater.m @@ -523,7 +523,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 }]; @@ -594,7 +595,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]; From 11d938c2ae95818fd7d63eec60647de2b1d77e1b Mon Sep 17 00:00:00 2001 From: Moustafa Hassan Date: Tue, 19 Jun 2018 03:01:57 +0200 Subject: [PATCH 07/12] replace UIAlertView with UIAlertController --- Appirater.h | 6 +-- Appirater.m | 118 +++++++++++++++++++++++++++------------------------- 2 files changed, 64 insertions(+), 60 deletions(-) diff --git a/Appirater.h b/Appirater.h index 9b59fe31..dfe5c070 100644 --- a/Appirater.h +++ b/Appirater.h @@ -97,12 +97,12 @@ extern NSString *const kAppiraterReminderRequestDate; */ #define APPIRATER_RATE_LATER NSLocalizedStringFromTableInBundle(@"Remind me later", @"AppiraterLocalizable", [Appirater bundle], nil) -@interface Appirater : NSObject { +@interface Appirater : NSObject { - 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 *delegate; diff --git a/Appirater.m b/Appirater.m index 044d1d3c..769949bb 100644 --- a/Appirater.m +++ b/Appirater.m @@ -84,7 +84,7 @@ - (void)incrementUseCount; - (void)hideRatingAlert; @end -@implementation Appirater +@implementation Appirater @synthesize ratingAlert; @@ -227,20 +227,65 @@ - (void)showRatingAlert { [[NSNotificationCenter defaultCenter] postNotificationName:ARAppiraterDidDisplayAlertNotification object:self]; } else { - - 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]; - + + UIAlertController *alert = [UIAlertController alertControllerWithTitle:APPIRATER_MESSAGE_TITLE + message:APPIRATER_MESSAGE + preferredStyle:UIAlertControllerStyleAlert]; + + self.ratingAlert = alert; + + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; id delegate = _delegate; - if (delegate && [delegate respondsToSelector:@selector(appiraterDidDisplayAlert:)]) { - [delegate appiraterDidDisplayAlert:self]; - } - [[NSNotificationCenter defaultCenter] postNotificationName:ARAppiraterDidDisplayAlertNotification object:self]; + + 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]; + + [[[[[UIApplication sharedApplication] windows] lastObject] rootViewController] presentViewController:alert animated:YES completion:^{ + if (delegate && [delegate respondsToSelector:@selector(appiraterDidDisplayAlert:)]) { + [delegate appiraterDidDisplayAlert:self]; + } + [[NSNotificationCenter defaultCenter] postNotificationName:ARAppiraterDidDisplayAlertNotification object:self]; + }]; + } } @@ -428,10 +473,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]; } } @@ -546,47 +591,6 @@ + (void)rateApp { } } -- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { - NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; - - id 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]; - } - [[NSNotificationCenter defaultCenter] postNotificationName:ARAppiraterDidDeclineToRateNotification object:self]; - break; - } - case 1: - { - // they want to rate it - [Appirater rateApp]; - if(delegate&& [delegate respondsToSelector:@selector(appiraterDidOptToRate:)]){ - [delegate appiraterDidOptToRate:self]; - } - [[NSNotificationCenter defaultCenter] postNotificationName:ARAppiraterDidOptToRateNotification object: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]; - } - [[NSNotificationCenter defaultCenter] postNotificationName:ARAppiraterDidOptToRemindLaterNotification object:self]; - break; - default: - break; - } -} - //Delegate call from the StoreKit view. - (void)productViewControllerDidFinish:(SKStoreProductViewController *)viewController { [Appirater closeModal]; From 713916dffbe917e3c1c5923c971d474d78607798 Mon Sep 17 00:00:00 2001 From: Moustafa Hassan Date: Tue, 19 Jun 2018 15:12:24 +0200 Subject: [PATCH 08/12] remove NSURLConnection connection creation because it seems unnecessary --- Appirater.m | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Appirater.m b/Appirater.m index 769949bb..335f3057 100644 --- a/Appirater.m +++ b/Appirater.m @@ -182,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 { From c1985bd223360e10df138296b2193584dcb68f42 Mon Sep 17 00:00:00 2001 From: Moustafa Hassan Date: Tue, 19 Jun 2018 15:20:05 +0200 Subject: [PATCH 09/12] update readme --- README.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 95c3eb92..0ce7a11e 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,18 @@ -Introduction ------------- -Appirater is a class that you can drop into any iPhone app (iOS 4.0 or later) that will help remind your users +This fork of Appirator is modified from the original version from arashpayan in the following ways: + +* It's compatible with iOS 9.0+ and doesn't use any depcrecated APIs +* Makes use of the Apple new SKStoreReviewController for iOS 10.3+ + +The rest of this Readme is the original one from arashpayan + +##Introduction +Appirater is a class that you can drop into any iPhone app that will help remind your users to review your app on the App Store. The code is released under the MIT/X11, so feel free to modify and share your changes with the world. Read on below for how to get started. If you need any help using, the library check out the [Appirater group] [appiratergroup]. -Getting Started ---------------- +##Getting Started ###Cocoapods If you're new to Cocoapods [watch this](http://nsscreencast.com/episodes/5-cocoapods). To add Appirater to your app, add `pod "Appirater"` to your Podfile. @@ -19,8 +24,7 @@ Cocoapods support is still experimental, and might not work in all use cases. If 2. If your project doesn't use ARC, add the `-fobjc-arc` compiler flag to `Appirater.m` in your target's Build Phases » Compile Sources section. 3. Add the `CFNetwork`, `SystemConfiguration`, and `StoreKit` frameworks to your project. Be sure to **change Required to Optional** for StoreKit in your target's Build Phases » Link Binary with Libraries section. -Configuration -------------- +##Configuration 1. Appirater provides class methods to configure its behavior. See [`Appirater.h`] [Appirater.h] for more information. ```objc @@ -67,24 +71,20 @@ If you wanted to show the request after 5 days only you can set the following: [Appirater appLaunched:YES]; ``` -Help and Support Group ----------------------- +##Help and Support Group Requests for help, questions about usage, suggestions and other relevant topics should be posted at the [Appirater group] [appiratergroup]. As much as I'd like to help everyone who emails me, I can't respond to private emails, but I'll respond to posts on the group where others can benefit from the Q&As. -License -------- +##License Copyright 2013. [Arash Payan] [arash]. This library is distributed under the terms of the MIT/X11. While not required, I greatly encourage and appreciate any improvements that you make to this library be contributed back for the benefit of all who use Appirater. -Tips ----- +##Tips Bitcoin tips are welcome: 1PxVtrzR4oHEKPojVx41JJnWGuPLggYDQy -Ports for other SDKs --------------- +##Ports for other SDKs A few people have ported Appirater to other SDKs. The ports are listed here in hopes that they may assist developers of those SDKs. I don't know how closesly (if at all) they track the Objective-C version of Appirater. If you need support for any of the libraries, please contact the maintainer of the port. + MonoTouch Port (using C#). [Github] [monotouchport] From 566499d08124ccd5ac8524ec952d99e6aa6005b8 Mon Sep 17 00:00:00 2001 From: Moustafa Hassan Date: Tue, 19 Jun 2018 15:29:18 +0200 Subject: [PATCH 10/12] use the class method getRootViewController to display UIAlertController instead of trying to do it manually --- Appirater.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Appirater.m b/Appirater.m index 335f3057..ace280a2 100644 --- a/Appirater.m +++ b/Appirater.m @@ -288,7 +288,7 @@ - (void)showRatingAlert { [alert addAction:rateAction]; [alert addAction:remindAction]; - [[[[[UIApplication sharedApplication] windows] lastObject] rootViewController] presentViewController:alert animated:YES completion:^{ + [[[self class] getRootViewController] presentViewController:alert animated:YES completion:^{ if (delegate && [delegate respondsToSelector:@selector(appiraterDidDisplayAlert:)]) { [delegate appiraterDidDisplayAlert:self]; } From 58b29b54c684b1f145e7e60d9860ac49a0e041c5 Mon Sep 17 00:00:00 2001 From: Moustafa Hassan Date: Tue, 19 Jun 2018 15:35:38 +0200 Subject: [PATCH 11/12] update readme to render correctly on github --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 0ce7a11e..e237ff48 100644 --- a/README.md +++ b/README.md @@ -5,26 +5,26 @@ This fork of Appirator is modified from the original version from arashpayan in The rest of this Readme is the original one from arashpayan -##Introduction +## Introduction Appirater is a class that you can drop into any iPhone app that will help remind your users to review your app on the App Store. The code is released under the MIT/X11, so feel free to modify and share your changes with the world. Read on below for how to get started. If you need any help using, the library check out the [Appirater group] [appiratergroup]. -##Getting Started +## Getting Started -###Cocoapods +### Cocoapods If you're new to Cocoapods [watch this](http://nsscreencast.com/episodes/5-cocoapods). To add Appirater to your app, add `pod "Appirater"` to your Podfile. Cocoapods support is still experimental, and might not work in all use cases. If you experience problems, open an issue and install via Git submodule -###Git submodule +### Git submodule 1. Add the Appirater code into your project. 2. If your project doesn't use ARC, add the `-fobjc-arc` compiler flag to `Appirater.m` in your target's Build Phases » Compile Sources section. 3. Add the `CFNetwork`, `SystemConfiguration`, and `StoreKit` frameworks to your project. Be sure to **change Required to Optional** for StoreKit in your target's Build Phases » Link Binary with Libraries section. -##Configuration +## Configuration 1. Appirater provides class methods to configure its behavior. See [`Appirater.h`] [Appirater.h] for more information. ```objc @@ -41,10 +41,10 @@ Cocoapods support is still experimental, and might not work in all use cases. If 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. -###Development +### Development Setting `[Appirater setDebug:YES]` will ensure that the rating request is shown each time the app is launched. -###Production +### Production Make sure you set `[Appirater setDebug:NO]` to ensure the request is not shown every time the app is launched. Also make sure that each of these components are set in the `application:didFinishLaunchingWithOptions:` method. This example states that the rating request is only shown when the app has been launched 5 times **and** after 7 days. @@ -71,20 +71,20 @@ If you wanted to show the request after 5 days only you can set the following: [Appirater appLaunched:YES]; ``` -##Help and Support Group +## Help and Support Group Requests for help, questions about usage, suggestions and other relevant topics should be posted at the [Appirater group] [appiratergroup]. As much as I'd like to help everyone who emails me, I can't respond to private emails, but I'll respond to posts on the group where others can benefit from the Q&As. -##License +## License Copyright 2013. [Arash Payan] [arash]. This library is distributed under the terms of the MIT/X11. While not required, I greatly encourage and appreciate any improvements that you make to this library be contributed back for the benefit of all who use Appirater. -##Tips +## Tips Bitcoin tips are welcome: 1PxVtrzR4oHEKPojVx41JJnWGuPLggYDQy -##Ports for other SDKs +## Ports for other SDKs A few people have ported Appirater to other SDKs. The ports are listed here in hopes that they may assist developers of those SDKs. I don't know how closesly (if at all) they track the Objective-C version of Appirater. If you need support for any of the libraries, please contact the maintainer of the port. + MonoTouch Port (using C#). [Github] [monotouchport] From 5548a8c17c551eccd65feabbb13da2dd8ec41dfd Mon Sep 17 00:00:00 2001 From: Moustafa Hassan Date: Tue, 19 Jun 2018 18:18:18 +0200 Subject: [PATCH 12/12] remove deprecated interface --- Appirater.h | 12 ------------ Appirater.m | 4 ---- 2 files changed, 16 deletions(-) diff --git a/Appirater.h b/Appirater.h index dfe5c070..5af0fea8 100644 --- a/Appirater.h +++ b/Appirater.h @@ -273,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 diff --git a/Appirater.m b/Appirater.m index ace280a2..521d8f8d 100644 --- a/Appirater.m +++ b/Appirater.m @@ -470,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), ^{