|
1 /* |
|
2 This file is part of Appirater. |
|
3 |
|
4 Copyright (c) 2012, Arash Payan |
|
5 All rights reserved. |
|
6 |
|
7 Permission is hereby granted, free of charge, to any person |
|
8 obtaining a copy of this software and associated documentation |
|
9 files (the "Software"), to deal in the Software without |
|
10 restriction, including without limitation the rights to use, |
|
11 copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
12 copies of the Software, and to permit persons to whom the |
|
13 Software is furnished to do so, subject to the following |
|
14 conditions: |
|
15 |
|
16 The above copyright notice and this permission notice shall be |
|
17 included in all copies or substantial portions of the Software. |
|
18 |
|
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
|
21 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|
22 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
|
23 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
|
24 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|
25 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
|
26 OTHER DEALINGS IN THE SOFTWARE. |
|
27 */ |
|
28 /* |
|
29 * Appirater.h |
|
30 * appirater |
|
31 * |
|
32 * Created by Arash Payan on 9/5/09. |
|
33 * http://arashpayan.com |
|
34 * Copyright 2012 Arash Payan. All rights reserved. |
|
35 */ |
|
36 |
|
37 #import <Foundation/Foundation.h> |
|
38 #import "AppiraterDelegate.h" |
|
39 #import <StoreKit/StoreKit.h> |
|
40 |
|
41 extern NSString *const kAppiraterFirstUseDate; |
|
42 extern NSString *const kAppiraterUseCount; |
|
43 extern NSString *const kAppiraterSignificantEventCount; |
|
44 extern NSString *const kAppiraterCurrentVersion; |
|
45 extern NSString *const kAppiraterRatedCurrentVersion; |
|
46 extern NSString *const kAppiraterDeclinedToRate; |
|
47 extern NSString *const kAppiraterReminderRequestDate; |
|
48 |
|
49 /*! |
|
50 Your localized app's name. |
|
51 */ |
|
52 #define APPIRATER_LOCALIZED_APP_NAME [[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:@"CFBundleDisplayName"] |
|
53 |
|
54 /*! |
|
55 Your app's name. |
|
56 */ |
|
57 #define APPIRATER_APP_NAME APPIRATER_LOCALIZED_APP_NAME ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"] |
|
58 |
|
59 /*! |
|
60 This is the message your users will see once they've passed the day+launches |
|
61 threshold. |
|
62 */ |
|
63 #define APPIRATER_LOCALIZED_MESSAGE NSLocalizedStringFromTableInBundle(@"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!", @"AppiraterLocalizable", [Appirater bundle], nil) |
|
64 #define APPIRATER_MESSAGE [NSString stringWithFormat:APPIRATER_LOCALIZED_MESSAGE, APPIRATER_APP_NAME] |
|
65 |
|
66 /*! |
|
67 This is the title of the message alert that users will see. |
|
68 */ |
|
69 #define APPIRATER_LOCALIZED_MESSAGE_TITLE NSLocalizedStringFromTableInBundle(@"Rate %@", @"AppiraterLocalizable", [Appirater bundle], nil) |
|
70 #define APPIRATER_MESSAGE_TITLE [NSString stringWithFormat:APPIRATER_LOCALIZED_MESSAGE_TITLE, APPIRATER_APP_NAME] |
|
71 |
|
72 /*! |
|
73 The text of the button that rejects reviewing the app. |
|
74 */ |
|
75 #define APPIRATER_CANCEL_BUTTON NSLocalizedStringFromTableInBundle(@"No, Thanks", @"AppiraterLocalizable", [Appirater bundle], nil) |
|
76 |
|
77 /*! |
|
78 Text of button that will send user to app review page. |
|
79 */ |
|
80 #define APPIRATER_LOCALIZED_RATE_BUTTON NSLocalizedStringFromTableInBundle(@"Rate %@", @"AppiraterLocalizable", [Appirater bundle], nil) |
|
81 #define APPIRATER_RATE_BUTTON [NSString stringWithFormat:APPIRATER_LOCALIZED_RATE_BUTTON, APPIRATER_APP_NAME] |
|
82 |
|
83 /*! |
|
84 Text for button to remind the user to review later. |
|
85 */ |
|
86 #define APPIRATER_RATE_LATER NSLocalizedStringFromTableInBundle(@"Remind me later", @"AppiraterLocalizable", [Appirater bundle], nil) |
|
87 |
|
88 @interface Appirater : NSObject <UIAlertViewDelegate, SKStoreProductViewControllerDelegate> { |
|
89 |
|
90 UIAlertView *ratingAlert; |
|
91 } |
|
92 |
|
93 @property(nonatomic, strong) UIAlertView *ratingAlert; |
|
94 @property(nonatomic) BOOL openInAppStore; |
|
95 #if __has_feature(objc_arc_weak) |
|
96 @property(nonatomic, weak) NSObject <AppiraterDelegate> *delegate; |
|
97 #else |
|
98 @property(nonatomic, unsafe_unretained) NSObject <AppiraterDelegate> *delegate; |
|
99 #endif |
|
100 |
|
101 /*! |
|
102 Tells Appirater that the app has launched, and on devices that do NOT |
|
103 support multitasking, the 'uses' count will be incremented. You should |
|
104 call this method at the end of your application delegate's |
|
105 application:didFinishLaunchingWithOptions: method. |
|
106 |
|
107 If the app has been used enough to be rated (and enough significant events), |
|
108 you can suppress the rating alert |
|
109 by passing NO for canPromptForRating. The rating alert will simply be postponed |
|
110 until it is called again with YES for canPromptForRating. The rating alert |
|
111 can also be triggered by appEnteredForeground: and userDidSignificantEvent: |
|
112 (as long as you pass YES for canPromptForRating in those methods). |
|
113 */ |
|
114 + (void)appLaunched:(BOOL)canPromptForRating; |
|
115 |
|
116 /*! |
|
117 Tells Appirater that the app was brought to the foreground on multitasking |
|
118 devices. You should call this method from the application delegate's |
|
119 applicationWillEnterForeground: method. |
|
120 |
|
121 If the app has been used enough to be rated (and enough significant events), |
|
122 you can suppress the rating alert |
|
123 by passing NO for canPromptForRating. The rating alert will simply be postponed |
|
124 until it is called again with YES for canPromptForRating. The rating alert |
|
125 can also be triggered by appLaunched: and userDidSignificantEvent: |
|
126 (as long as you pass YES for canPromptForRating in those methods). |
|
127 */ |
|
128 + (void)appEnteredForeground:(BOOL)canPromptForRating; |
|
129 |
|
130 /*! |
|
131 Tells Appirater that the user performed a significant event. A significant |
|
132 event is whatever you want it to be. If you're app is used to make VoIP |
|
133 calls, then you might want to call this method whenever the user places |
|
134 a call. If it's a game, you might want to call this whenever the user |
|
135 beats a level boss. |
|
136 |
|
137 If the user has performed enough significant events and used the app enough, |
|
138 you can suppress the rating alert by passing NO for canPromptForRating. The |
|
139 rating alert will simply be postponed until it is called again with YES for |
|
140 canPromptForRating. The rating alert can also be triggered by appLaunched: |
|
141 and appEnteredForeground: (as long as you pass YES for canPromptForRating |
|
142 in those methods). |
|
143 */ |
|
144 + (void)userDidSignificantEvent:(BOOL)canPromptForRating; |
|
145 |
|
146 /*! |
|
147 Tells Appirater to try and show the prompt (a rating alert). The prompt will be showed |
|
148 if there is connection available, the user hasn't declined to rate |
|
149 or hasn't rated current version. |
|
150 |
|
151 You could call to show the prompt regardless Appirater settings, |
|
152 e.g., in case of some special event in your app. |
|
153 */ |
|
154 + (void)tryToShowPrompt; |
|
155 |
|
156 /*! |
|
157 Tells Appirater to show the prompt (a rating alert). |
|
158 Similar to tryToShowPrompt, but without checks (the prompt is always displayed). |
|
159 Passing false will hide the rate later button on the prompt. |
|
160 |
|
161 The only case where you should call this is if your app has an |
|
162 explicit "Rate this app" command somewhere. This is similar to rateApp, |
|
163 but instead of jumping to the review directly, an intermediary prompt is displayed. |
|
164 */ |
|
165 + (void)forceShowPrompt:(BOOL)displayRateLaterButton; |
|
166 |
|
167 /*! |
|
168 Tells Appirater to open the App Store page where the user can specify a |
|
169 rating for the app. Also records the fact that this has happened, so the |
|
170 user won't be prompted again to rate the app. |
|
171 |
|
172 The only case where you should call this directly is if your app has an |
|
173 explicit "Rate this app" command somewhere. In all other cases, don't worry |
|
174 about calling this -- instead, just call the other functions listed above, |
|
175 and let Appirater handle the bookkeeping of deciding when to ask the user |
|
176 whether to rate the app. |
|
177 */ |
|
178 + (void)rateApp; |
|
179 |
|
180 /*! |
|
181 Tells Appirater to immediately close any open rating modals (e.g. StoreKit rating VCs). |
|
182 */ |
|
183 + (void)closeModal; |
|
184 |
|
185 /*! |
|
186 Asks Appirater if the user has declined to rate; |
|
187 */ |
|
188 - (BOOL)userHasDeclinedToRate; |
|
189 |
|
190 /*! |
|
191 Asks Appirater if the user has rated the current version. |
|
192 Note that this is not a guarantee that the user has actually rated the app in the |
|
193 app store, but they've just clicked the rate button on the Appirater dialog. |
|
194 */ |
|
195 - (BOOL)userHasRatedCurrentVersion; |
|
196 |
|
197 @end |
|
198 |
|
199 @interface Appirater(Configuration) |
|
200 |
|
201 /*! |
|
202 Set your Apple generated software id here. |
|
203 */ |
|
204 + (void) setAppId:(NSString*)appId; |
|
205 |
|
206 /*! |
|
207 Users will need to have the same version of your app installed for this many |
|
208 days before they will be prompted to rate it. |
|
209 */ |
|
210 + (void) setDaysUntilPrompt:(double)value; |
|
211 |
|
212 /*! |
|
213 An example of a 'use' would be if the user launched the app. Bringing the app |
|
214 into the foreground (on devices that support it) would also be considered |
|
215 a 'use'. You tell Appirater about these events using the two methods: |
|
216 [Appirater appLaunched:] |
|
217 [Appirater appEnteredForeground:] |
|
218 |
|
219 Users need to 'use' the same version of the app this many times before |
|
220 before they will be prompted to rate it. |
|
221 */ |
|
222 + (void) setUsesUntilPrompt:(NSInteger)value; |
|
223 |
|
224 /*! |
|
225 A significant event can be anything you want to be in your app. In a |
|
226 telephone app, a significant event might be placing or receiving a call. |
|
227 In a game, it might be beating a level or a boss. This is just another |
|
228 layer of filtering that can be used to make sure that only the most |
|
229 loyal of your users are being prompted to rate you on the app store. |
|
230 If you leave this at a value of -1, then this won't be a criterion |
|
231 used for rating. To tell Appirater that the user has performed |
|
232 a significant event, call the method: |
|
233 [Appirater userDidSignificantEvent:]; |
|
234 */ |
|
235 + (void) setSignificantEventsUntilPrompt:(NSInteger)value; |
|
236 |
|
237 |
|
238 /*! |
|
239 Once the rating alert is presented to the user, they might select |
|
240 'Remind me later'. This value specifies how long (in days) Appirater |
|
241 will wait before reminding them. |
|
242 */ |
|
243 + (void) setTimeBeforeReminding:(double)value; |
|
244 |
|
245 /*! |
|
246 Set customized title for alert view. |
|
247 */ |
|
248 + (void) setCustomAlertTitle:(NSString *)title; |
|
249 |
|
250 /*! |
|
251 Set customized message for alert view. |
|
252 */ |
|
253 + (void) setCustomAlertMessage:(NSString *)message; |
|
254 |
|
255 /*! |
|
256 Set customized cancel button title for alert view. |
|
257 */ |
|
258 + (void) setCustomAlertCancelButtonTitle:(NSString *)cancelTitle; |
|
259 |
|
260 /*! |
|
261 Set customized rate button title for alert view. |
|
262 */ |
|
263 + (void) setCustomAlertRateButtonTitle:(NSString *)rateTitle; |
|
264 |
|
265 /*! |
|
266 Set customized rate later button title for alert view. |
|
267 */ |
|
268 + (void) setCustomAlertRateLaterButtonTitle:(NSString *)rateLaterTitle; |
|
269 |
|
270 /*! |
|
271 'YES' will show the Appirater alert everytime. Useful for testing how your message |
|
272 looks and making sure the link to your app's review page works. |
|
273 */ |
|
274 + (void) setDebug:(BOOL)debug; |
|
275 |
|
276 /*! |
|
277 Set the delegate if you want to know when Appirater does something |
|
278 */ |
|
279 + (void)setDelegate:(id<AppiraterDelegate>)delegate; |
|
280 |
|
281 /*! |
|
282 Set whether or not Appirater uses animation (currently respected when pushing modal StoreKit rating VCs). |
|
283 */ |
|
284 + (void)setUsesAnimation:(BOOL)animation; |
|
285 |
|
286 /*! |
|
287 If set to YES, Appirater will open App Store link (instead of SKStoreProductViewController on iOS 6). Default YES. |
|
288 */ |
|
289 + (void)setOpenInAppStore:(BOOL)openInAppStore; |
|
290 |
|
291 /*! |
|
292 If set to YES, the main bundle will always be used to load localized strings. |
|
293 Set this to YES if you have provided your own custom localizations in AppiraterLocalizable.strings |
|
294 in your main bundle. Default is NO. |
|
295 */ |
|
296 + (void)setAlwaysUseMainBundle:(BOOL)useMainBundle; |
|
297 |
|
298 @end |
|
299 |
|
300 |
|
301 /*! |
|
302 Methods in this interface are public out of necessity, but may change without notice |
|
303 */ |
|
304 @interface Appirater(Unsafe) |
|
305 |
|
306 /*! |
|
307 The bundle localized strings will be loaded from. |
|
308 */ |
|
309 +(NSBundle *)bundle; |
|
310 |
|
311 @end |
|
312 |
|
313 @interface Appirater(Deprecated) |
|
314 |
|
315 /*! |
|
316 DEPRECATED: While still functional, it's better to use |
|
317 appLaunched:(BOOL)canPromptForRating instead. |
|
318 |
|
319 Calls [Appirater appLaunched:YES]. See appLaunched: for details of functionality. |
|
320 */ |
|
321 + (void)appLaunched __attribute__((deprecated)); |
|
322 |
|
323 /*! |
|
324 DEPRECATED: While still functional, it's better to use |
|
325 tryToShowPrompt instead. |
|
326 |
|
327 Calls [Appirater tryToShowPrompt]. See tryToShowPrompt for details of functionality. |
|
328 */ |
|
329 + (void)showPrompt __attribute__((deprecated)); |
|
330 |
|
331 @end |