arashpayan / appirater Goto Github PK
View Code? Open in Web Editor NEWA utility that reminds your iPhone app's users to review the app.
Home Page: http://arashpayan.com/blog/2009/09/07/presenting-appirater/
A utility that reminds your iPhone app's users to review the app.
Home Page: http://arashpayan.com/blog/2009/09/07/presenting-appirater/
finnish localized string file is corrupted
Hello there,
Can someone point me to release notes or a changelog for Appirater? We have been using 1.0.5 from CocoaPods, and I noticed that it has recently been bumped to 2.0.1. I want to know what requirements and behaviour have changed between these versions before updating, but I can find no trace of such documentation.
thanks,
b
Hello,
I installed appirater with cocoapods (pod 'Appirater', '~> 1.0.1') but the localizable files are not present. Am I missing something?
Thanks
I've just integrated Appirater into our app (awesome work, btw!) and noticed that the iPad-only app store URL is being targeted by Appirater every time, no matter that our app is Universal. It even goes to the wrong URL when running on the iPhone. As a workaround, I am hardcoding the iPad URL to match the iPhone / Universal URL.
Added all code to an universal iOS app. The alert shows no problem on the iPhone/iPod Touch, but will not show on iPad. Any ideas?
Sorry, this issue is a mistake. Please delete it.
How do i use setSignificantEventsUntilPrompt and setTimeBeforeReminding properties? Thanks
Since APPIRATER_LOCALIZED_MESSAGE_TITLE and APPIRATER_LOCALIZED_RATE_BUTTON both refer to the same key ("Rate %@") in the strings file, you can't set separate text for these without editing the class. There may be some cases where you prefer to have the title and rate button differ.
Get the following exception if I press on rate App:
-[UIWindow presentViewController:animated:completion:]: unrecognized selector sent to instance 0x1fd82fb0
Line 409 in Appirater.m is causing the problem, I guess the root viewController can not be found.
In the README.md file, it says "If you wanted to show the request after 5 days only you can set the following."
However, the code seems to be doing "5 times" instead of "5 days".
Following the instructions, and not using any "significant events" appirater comes up the first time the app launches. Any ideas? It also comes up any time the app enters the foreground. Tried reinstalling with no luck.
iOS 5.1
Xcode 4.4
Hi,
Appirater is really cool, but I am not able to show my Apps Name on the UIAlertView. Instead of the Name (Winzis Pairs) I see only "null"...
Another question: How can Appirater be tested? Currently I have to wait 1 day until I see the UIAlertView, which is not really practicable. How do you handle this?
Thanks and BR,
Stefan
When the alert is displayed in my app it doesn't show the message:
It only says Rate Ice Cold
(Ice Cold is the name of my app)
Any ideas about how I can solve this?
In iOS 6, a new URL has been added, which replaces LANGUAGE for the 2 character country code. However, in the UK, the value that replaces LANGUAGE comes back as en-GB (which doesn't work and yields a broken url).
There are a few issues in + (void)appLaunched:(BOOL)canPromptForRating.
P.S. This is a great piece of code, keep up the good work!
Does anyone know if this works with iOS 6, as I believe the links to review have changed.
Hi, I'm trying to use Appirater but when compiling I get the following error:
"_SCNetworkReachabilityGetFlags", referenced from:
-[Appirater(hidden) connectedToNetwork] in Appirater.o
"_SCNetworkReachabilityCreateWithAddress", referenced from:
-[Appirater(hidden) connectedToNetwork] in Appirater.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
Renaming Localizable.strings would avoid issues when you have multiple localization files in your bundle.
This has been implemented by
where Appirater.strings is used instead of Localizable.strings
One of the biggest complaints I have with apple's app store is that as a developer I can't respond to user's reviews. It would be nice if appirater would give users an option to email the developer if they have complaints or suggestions. I've does something similar in some of my apps with good success. No bad reviews and useful feedback.
SKStoreProductViewController *storeViewController = [[SKStoreProductViewController alloc] init];
NSNumber *appId = [NSNumber numberWithInteger:_appId.integerValue];
[storeViewController loadProductWithParameters:@{SKStoreProductParameterITunesItemIdentifier:appId} completionBlock:nil];
storeViewController.delegate = self.sharedInstance;
"SKStoreProductParameterITunesItemIdentifier:appId" the appId must be string, simply change it to SKStoreProductParameterITunesItemIdentifier:_appId will work.
I want to know what settings to add so that Appirator will show up immediately when opening the app, for testing purposes. I'm building the app in Xcode of course and closing and re-launching it multiple times from my device to test. I have tried all combinations of adding the methods or changing the static values to 0s or 1s, but I can't get it to pop up. I suspect that I may have something else wrong with my setup that is preventing it from working, but can anyone confirm what would make it show up at each launch?
I currently have the messages below at the beginning in my AppDelegate.m didFinishLaunchingWithOptions method.
[Appirater setDaysUntilPrompt:0];
[Appirater setUsesUntilPrompt:0];
[Appirater setSignificantEventsUntilPrompt:-1];
[Appirater setTimeBeforeReminding:0];
Thanks for reading.
While trying to add appirater to my iPad app I ran into a problem when trying to make the app compile under both iOS 3.2 and 4.2. The error resulted from the call to device.multitaskingSupported
.
I was able to fix this by making it a method call instead of accessing the property. I also switched the if statement to a slightly more robust version. I also had to use isMultitaskingSupported
, or the method call wouldn't work.
Here is the code I changed from line 296 of Appirater.m:
UIDevice *device = [UIDevice currentDevice]; if ([device respondsToSelector:@selector(isMultitaskingSupported)]) { if([device isMultitaskingSupported]) { return; } }
Hi,
My app uses Navigation Controller, and closeModal couldn't close the AppStore view because it couldn't find the topMostViewController .
I fixed this issue by not using closeModal, but instead doing the following, at Appirater.m -
-(void)productViewControllerDidFinish:(SKStoreProductViewController *)viewController {
MyDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate.navigationController.topViewController dismissModalViewControllerAnimated:_usesAnimation];
}
This is not a good way to solve this issue, as this is a very specific way to deal with it. Unfortunately, I'm running out of time to release my app and will leave the code in this way, but I'm aware that this issue should be solved inside topMostViewController .
Thanks!
If, e.g., the view controller that presents the SKStoreProductViewController that Appirater creates and presents has a hidden status bar, the SKStoreProductViewController should as well, on iOS 7.
The recent addition of the delegate notion includes a property annotated "weak", which won't compile for iOS4.x targets. We need to change this to unsafe_unretained for platforms before iOS5.
i.e. change
@Property(nonatomic, weak) NSObject *delegate;
to
@Property(nonatomic, unsafe_unretained) NSObject *delegate;
If you launch an app on a multi-tasking iOS, incrementAndRate is never called. When the dev calls
[Appirater appLaunched:YES];
That method checks for multi-tasking:
if ([device respondsToSelector:@selector(isMultitaskingSupported)] &&
[device isMultitaskingSupported])
{
return;
}
Since multi-tasking is available, the method immediately returns without incrementing counts or checking if the rating dialog should be shown. It will not be until the user exits the app and relaunches it (assuming that it was still running in the background) that Appiraters appEnteredForeground will be called and the increments and checks performed. Note that applicationWillEnterForeground will not be called when an app is launched initially, only when it is being launched from the background.
In addition, for developers this means that setting APPIRATER_DEBUG to YES will have no effect unless you background the app and bring it to the foreground.
There is no guarantee that any app will remain in the background. Backgrounded apps can be killed by the OS at any time or the user can kill backgrounded apps.
To resolve the problem, appLaunched still needs to call incrementAndRate regardless if multi-tasking is supported.
Though the link still works on iOS 6, iOS [REDACTED] redirects to a blank page. Do you think this is temporary, or is Apple removing the direct link to the review page?
Apple fixed the review link issue on iOS6 app store, and it works again.
But, it doesn't go to the review page where you can start writing right away as you did on iOS5.
I'm not sure if there is better way, but I am doing like this at the moment.
(void)rateApp {
NSLog(@"APPIRATER NOTE: iTunes App Store is not supported on the iOS simulator. Unable to open App Store page.");
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSString *reviewURL = [templateReviewURL stringByReplacingOccurrencesOfString:@"APP_ID" withString:[NSString stringWithFormat:@"%@", _appId]];
[userDefaults setBool:YES forKey:kAppiraterRatedCurrentVersion];
[userDefaults synchronize];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:reviewURL]];
}
Somebody have recently added appirater to the CocoaPods package manager repo.
CocoaPods is a tool for managing dependencies for OS X and iOS Xcode projects and provides a central repository for iOS/OS X libraries. This makes adding libraries to a project and updating them extremely easy and it will help users to resolve dependencies of the libraries they use.
However, appirater doesn't have any version tags. Now we use current HEAD as version 0.0.3, but a version tag will make dependency resolution much easier.
Semantic version tags (instead of plain commit hashes/revisions) allow for resolution of cross-dependencies.
In case you didn’t know this yet; you can tag the current HEAD as, for instance, version 1.0.0, like so:
$ git tag -a 1.0.0 -m "Tag release 1.0.0"
$ git push --tags
I don't really know what happened of this crash, since there is only one single crash for one user among hundreds of users.
Appirater uses dispatch_async to schedule work in the low priority global queue, this causes defaults changed events to be posted from multiple threads and assorted race conditions in naive apps. I would believe that this should be mentioned in the readme as it surprised me and causes some head scratching to find out where that crash came from.
in iOS 6 it does. in iOS 7 you cannot press the button to write a review if you use SKStoreProductViewController. I think Apple doesn't want apps allowing users to write reviews easily.
Hello,
Here are Armenian translation.
"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!" = "Եթե Դուք հաճույքով եք օգտագործում %@-ը, դեմ չե՞ք լինի տրամադրել մեկ րոպե այն գնահատելու համար: Այն չի պահանջի ձեզանից ավելի քան մեկ րոպե: Շնորհակալություն աջակցության համար:";
"Rate %@" = "Գնահատել %@-ը";
"No, Thanks" = "Ոչ, շնորհակալություն";
"Remind me later" = "Հիշեցնել ավելի ուշ";
Best regards,
Vardan Gevorgyan
The iTunes URL protocol to open the app store (itms-apps://) won't work in simulator. Most devs understand this, but it would probably be a good idea to put some checking around the code to provide a reminder. I've modified the alertView:clickedButtonAtIndex as follows:
#if (TARGET_IPHONE_SIMULATOR)
NSLog(@"iTunes URL protocol (itms-apps://) doesn't work in the simulator.");
#else
Hi,
Starting from iOS 6, it's possible to show an iTunes controller within the app with the SKITunesProductViewController class.
I believe this could be used to rate the app. This means the user wouldn't need to abandon the app being rated in order to rate it.
Implementing this wouldn't be trivial, since we need to push the view controller. I believe we would need to make some changes to the delegate protocol:
We need to get the view controller that will be used to push and dismiss the modal controller. If the user doesn't implement this delegate method, we may fall back to jumping to the iTunes URL.
We need to let the delegate know when we're pushing a view controller (e.g. so a game can pause) and when we're dismissing it (e.g. so a game can unpause).
We may need to ask the delegate if we should push with animations enabled or not, as pushing with animations can be troublesome in some (rare) cases.
Thoughts?
Regards,
In ratingConditionsHaveBeenMet I would suggest to place an additional check if the app is in debug mode before checking the APPIRATER_DEBUG flag. This will ensure that developers don't accidentally submit an app to the app store that displays the rating dialog on every launch.
- (BOOL)ratingConditionsHaveBeenMet {
#ifdef DEBUG
if (APPIRATER_DEBUG)
return YES;
#endif
I'm assuming here that most devs have a DEBUG flag defined on the debug builds (if not, they should).
I've got this warn message running appirater with MacOS X Lion.
"NSAlert is being used from a background thread, which is not safe. This is probably going to crash sometimes. Break on _NSAlertWarnUnsafeBackgroundThreadUsage to debug. This will be logged only once. This may break in the future."
Hi,
Thanks for your code. Great idea!
It contains a bunch of leaks though. Maybe you should put on the Static Analyser (check your build settings). These are the leaks that the static analyser detects:
• unreleased UIAlertview (line 185) -- after show, it should be released
• testConnection (line 83) -- should be released
• Appirater unreleased (line 93) -- after detaching a new thread, it can be auto-released (it's retained by the thread)
M
A recent commit "changed" this, but I don't think it was the right thing to do. In my app I use CFBundleName for the full name of the app, and CFBundleDisplayName for the name that appears under the app icon. I'd like Appirater to use the full name, not the short name. Perhaps I'm doing it wrong?
I am receiving a crash immediately upon app launch when running the latest version of Appirater on the iOS 5.0 simulator.
The debugger is pointing to the dispatch_async
line of code on line 345 of Appirator.m. Any ideas why this would happen?
+ (void)appLaunched:(BOOL)canPromptForRating {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
^{
[[Appirater sharedInstance] incrementAndRate:canPromptForRating];
});
}
The settings I am using:
[Appirater setAppId:@"1234567890"];
[Appirater setDaysUntilPrompt:1];
[Appirater setUsesUntilPrompt:10];
[Appirater setSignificantEventsUntilPrompt:-1];
[Appirater setTimeBeforeReminding:5];
[Appirater setDebug:NO];
[Appirater appLaunched:YES];
diff --git a/Appirater.m b/Appirater.m
index 0d2bb62..bbcd13e 100644
--- a/Appirater.m
+++ b/Appirater.m
@@ -85,7 +85,7 @@ NSString *templateReviewURL = @"itms-apps://ax.itunes.apple.com/WebObjects/MZSto
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];
+ NSURLConnection *testConnection = [[[NSURLConnection alloc] initWithRequest:testRequest delegate:self] autorelease];
return ((isReachable && !needsConnection) || nonWiFi) ? (testConnection ? YES : NO) : NO;
}
If the UIAlertView is present and the user moves the app to the background, Appirater gets stuck in a vicious circle of briefly presenting the alert and then dismissing it.
As a brute force measure, I am simply cycling through subviews from applicationDidEnterBackground:
and calling dismissWithClickedButtonIndex:
on the UIAlertView. This works for my particular implementation, but is obviously not safe for everyone.
Hi,
this is a great project. I really like it. Thanks for creating it.
There is one thing missing, though its not difficult to add it myself, but just wanted to note that it would be great to add NSLocalizedString to the master Branch for multilingual support if someone needs it like myself.
Buju77
If running on iOS 6, then Appirater uses Storekit's ability to present a product page on the app store in a modal view.
However I'd question whether this actually does more harm than good in getting users to leave ratings or reviews since it involves one more user action than the URL method.
Storekit (iOS 6)
Designed for handling in app purchases rather than reviews, so the reviews tab cannot be selected automatically and the user must:
URL method to App Store app (pre-iOS 6)
This takes the user directly to the "Reviews" tab, so they only need to:
Yes it's only one more action, but every action counts when it comes to getting feedback from users! Personally I don't think leaving the host app is a problem since the user doesn't know what is about to happen until they press the button!
It is better to move at least to checks: "// has the user already rated the app?" and "// has the user previously declined to rate this version of the app?" to method head. They are cheaper than time interval checks so after application is rated (or rating was declined by user) the check won't waste the processor time that much as creating NSDate and NSTimeInterval objects.
I'd like to move where the rating dialog is show, instead of when the app starts, to after a certain feature has been used. However I still want to preserve all of the app uses, as normal.
From reading the comments in the h file, it sounds like all I need to do is call [Appirater appLaunched:NO]; in app delegate then call [Appirater appLaunched:YES]; at the certain desired point in my app ?
However, it does say that calling appLaunched will increment uses, so I'm concerned that the second call will increment the uses as well as the first?
Obviously I can't just call [Appirater appLaunched:YES]; at the certain point, as this doesn't occur every time the app runs.
Thanks in advance.
In line 202 Appirater is adding itself as an observer to NSNotificationCenter without unregistering from NSNotificationCenter again. Documentation says:
"Be sure to invoke removeObserver: (or removeObserver:name:object:) before notificationObserver or any object specified in addObserver:selector:name:object: is deallocated."
Fix could be to call removeObserver:self in an overridden dealloc-method.
here is where the code throws the error
for (UIView *subView in [window subviews])
{
UIResponder *responder = [subView nextResponder];
if([responder isKindOfClass:[UIViewController class]]) {
return [self topMostViewController: (UIViewController *) responder];
}
}
return nil; <----------flag is thrown here
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.