How to Add "Write a Review" / "Rate Us" Feature to My App? - ios

I wish to add some sort of a "Write a Review" or "Rate Us" feature to my app so my customers can easily rate and review my app.
Best practice I can think of is to have some sort of pop-up or open a UIWebView within my app so the user is not kicked off of my app while opening the App Store application as done in:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"itms://itunes.com/apps/myAppName"]];
Does anyone knows of a way to do that?

StoreKit API (iOS 10.3 and up)
As of iOS 10.3, the StoreKit API provides a way to request a review on the App Store without leaving your app. When called, the system may present the user with an alert that requests a review. The user may provide a star rating directly inside the alert, continue on to write a review, or dismiss the alert. StoreKit handles just about everything for you. To present the review request, make the following call where it is appropriate in your app:
// Objective-C
[SKStoreReviewController requestReview]
// Swift
SKStoreReviewController.requestReview()
As per Apple's instructions, you should not call these in response to a direct user-interaction (i.e. tapping a button that says "Write a Review") because it may not always display the alert. Indeed, the alert may only be displayed three times every 365 days.
Important Note: Although this seems fairly simple, you'll still need to write some kind of logic in order to space out your prompts. For example, to present the prompt only after X number of launches, days, or significant events.
If you fail to do this and just stick the review prompt anywhere (a viewDidAppear call, for example), your users will be rather annoyed because they'll see it pretty quickly and repeatedly. Then, either they leave a bad review (because they're annoyed) or aren't asked to review again for a whole year.
Below is an example of what the alert looks like. For more information, see Apple's documentation.
iRate (iOS 7.0 and up)
If your app runs on versions of iOS earlier than 10.3 or you need more robust control over requesting ratings from users, iRate is a good solution.
For devices with iOS 10.3 or greater, iRate uses the aforementioned StoreKit API. For devices running iOS 7.0 to 10.2, iRate uses a uialertview and storekit to ask the user for a rating (or to remind them later). Everything is customizable, from the title of the Cancel button to the interval at which it reminds the user.
By default, iRate automatically opens when certain requirements are met (e.g. app launched X number of times, user passed X number of levels), but you can also use a variety of methods and your own logic (with the help of iRate methods) to manually display an iRate popup.
Setup
To install, just drag the header file, the implementation file, and the .bundle (for localization) into your project.
Import the header in your AppDelegate: #import "iRate.h"
Add the StoreKit Framework to your project - More on StoreKit from Apple Documentation
In your application: didFinishLaunchingWithOptions: method, set the following:
// Configure iRate
[iRate sharedInstance].daysUntilPrompt = 5;
[iRate sharedInstance].usesUntilPrompt = 15;
Properties
The property below is useful for testing purposes. Set it to YES during testing to make sure the dialog appears properly. When set to YES it will appear immediately on startup, disregarding other display settings. Set this to NO for release versions of your app.
[iRate sharedInstance].previewMode = NO;
The appStoreID property allows you to set the ID of your app. This is only required if you have both Mac and iOS apps with the same Bundle Identifier. The App ID set here must also match the Bundle ID set in Xcode and iTunes Connect:
[iRate sharedInstance].appStoreID = 555555555;
More Details are available on the iRate GitHub page.

A really good one I use is Appirater: https://github.com/arashpayan/appirater/
It automatically prompts your users to leave reviews, you just have to provide your app id.

Declare Variable
let reviewService = ReviewService.shared
In View Did Appear
self.reviewService.rateAlert(from: self)
Import the Class
import UIKit
import StoreKit
class ReviewService: NSObject {
static let shared = ReviewService()
private var lastRequest : Date? {
get {
return UserDefaults.standard.value(forKey: "lastRequest") as? Date
}
set {
UserDefaults.standard.set(newValue, forKey: "lastRequest")
}
}
private var oneDayAgo : Date {
return Calendar.current.date(byAdding: .day, value: -1, to: Date()) ?? Date()
}
private var shouldReview : Bool {
if lastRequest == nil {
return true
}
else if let lastRequest = self.lastRequest , lastRequest < oneDayAgo {
return true
}
else {
return false
}
}
func requestReview(isWrittenReview : Bool = false) {
if isWrittenReview {
let appID = "##########" // App Id
let urlStr = "https://itunes.apple.com/app/id\(appID)?action=write-review"
guard let url = URL(string: urlStr), UIApplication.shared.canOpenURL(url) else { return }
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
else {
SKStoreReviewController.requestReview()
}
}
//MARK:- Rate App
func rateAlert(from : UIViewController?) {
guard shouldReview else {
print("Don't Show")
return
}
guard let vc = from else {
return
}
lastRequest = Date()
let alert = UIAlertController(title: "Rate our App", message: "If you love our app, please take a moment to rate it in the App Store", preferredStyle: .alert)
let action1 = UIAlertAction(title: "Rate", style: .default, handler: {(_ action: UIAlertAction?) -> Void in
self.requestReview(isWrittenReview: false)
})
let action2 = UIAlertAction(title: "Send Feedback", style: .default, handler: {(_ action: UIAlertAction?) -> Void in
self.requestReview(isWrittenReview: true)
})
let action3 = UIAlertAction(title: "Close", style: .default, handler: nil)
alert.addAction(action1)
alert.addAction(action2)
alert.addAction(action3)
vc.present(alert,animated: true)
}
}

You can use my tiny wrapper around SKStoreReviewController.
// Review after 3 launches
AppReview.requestIf(launches: 3)
// Review after 5 days
AppReview.requestIf(days: 5)
// Review after 3 launches and 5 days
AppReview.requestIf(launches: 3, days: 5)
https://github.com/mezhevikin/AppReview

Related

push notification in ios using firebase

How can I use push notification capabilities in my project? I don't have developer account, I tried this code
#IBAction func PhoneSignIn(_ sender: Any) {
let alert = UIAlertController(title: "Phone number", message: "Is this your phone number? \n \(PhoneOu.text!)", preferredStyle: .alert)
let action = UIAlertAction(title: "Yes", style: .default) { (UIAlertAction) in
PhoneAuthProvider.provider().verifyPhoneNumber(self.PhoneOu.text!, uiDelegate: nil) { (verificationID, error) in
if error != nil {
print("eror: \(String(describing: error?.localizedDescription))")
} else {
let defaults = UserDefaults.standard
defaults.set(verificationID, forKey: "authVID")
self.performSegue(withIdentifier: "code", sender: Any?.self)
}
}
}
let cancel = UIAlertAction(title: "No", style: .cancel, handler: nil)
alert.addAction(action)
alert.addAction(cancel)
self.present(alert, animated: true, completion: nil)
}
When you call verifyPhoneNumber:UIDelegate:completion:, Firebase sends a silent push notification to your app, or issues a reCAPTCHA challenge to the user. After your app receives the notification or the user completes the reCAPTCHA challenge, Firebase sends an SMS message containing an authentication code to the specified phone number and passes a verification ID to your completion function. You will need both the verification code and the verification ID to sign in the user.
If you don't have a developer account, this is currently not possible using push notifications, better use reCAPTCHA:
Set up reCAPTCHA verification:
To enable the Firebase SDK to use reCAPTCHA verification:
Add custom URL schemes to your Xcode project:
a. Open your project configuration: double-click the project name in the left tree view. Select your app from the TARGETS section, then select the Info tab, and expand the URL Types section.
b. Click the + button, and add a URL scheme for your reversed client ID. To find this value, open the [![GoogleService-Info.plist][1]][1] configuration file, and look for the REVERSED_CLIENT_ID key. Copy the value of that key, and paste it into the URL Schemes box on the configuration page. Leave the other fields blank.
When completed, your config should look something similar to the following (but with your application-specific values):
Optional: If you want to customize the way your app presents the SFSafariViewController or UIWebView when displaying the reCAPTCHA to the user, create a custom class that conforms to the FIRAuthUIDelegate protocol, and pass it to verifyPhoneNumber:UIDelegate:completion:.
Read more:
Authenticate with Firebase on iOS using a Phone Number

Facing issue in Siri Integration with custom intents

I’m trying to integrate Siri Shortcuts to my application. The concept which I’m trying is to get reward points of my card with secret pin confirmation. Please find what I have done for this below.
Enabled Siri in capabilities and added Siri Intent definition file.
Added new custom intent named say Rewards.
Defined the title. Subtitle and params(accType, pin) with confirmation enabled. Pin will be sent separately to user.
Then defined the intent response with param ‘rewardPoints’ and defined the response messages.
Added Siri intent extensions.
Added custom intent to info.plist files within project and intent extension.
Verified and added new handler for the custom intent and define the resolve, handle and confirm methods as below. For now, I’m returning random no for reward points.
//
// RewardsIntentHandler.swift
// SiriIntentExt
//
import UIKit
import Intents
class RewardsIntentHandler: NSObject, RewardsIntentHandling {
func resolveAccType(for intent:RewardsIntent, with completion: #escaping ([INStringResolutionResult]) -> Void) {
guard let accType = intent.accType else {
completion([INStringResolutionResult.needsValue()])
return
}
completion([INStringResolutionResult.success(with: accType)])
}
func resolvePin(for intent:RewardsIntent, with completion: #escaping ([INIntegerResolutionResult]) -> Void) {
guard let verifyPin = intent.pin else {
completion([INIntegerResolutionResult.needsValue()])
return
}
completion([INIntegerResolutionResult.confirmationRequired(with: verifyPin as? Int)])
}
func confirm(intent: RewardsIntent, completion: #escaping (RewardsIntentResponse) -> Void) {
completion(RewardsIntentResponse.init(code: RewardsIntentResponseCode.ready, userActivity: nil))
}
func handle(intent: RewardsIntent, completion: #escaping (RewardsIntentResponse) -> Void) {
guard intent.accType != nil else {
completion(RewardsIntentResponse.init(code: RewardsIntentResponseCode.continueInApp, userActivity: nil))
return
}
guard intent.pin != nil else {
completion(RewardsIntentResponse.init(code: RewardsIntentResponseCode.continueInApp, userActivity: nil))
return
}
let response = RewardsIntentResponse.success(rewardPoints: NSNumber(value: 3453))
completion(response)
}
}
Modified the IntentHandler to return rewards handler for rewards intent
//
// IntentHandler.swift
// SiriIntentExt
//
import Intents
class IntentHandler: INExtension {
override func handler(for intent: INIntent) -> Any {
if intent is RewardsIntent {
return RewardsIntentHandler()
}
return self
}
}
Donated the intent on view load as below.
//
// ViewController.swift
// Shortcuts
//
import UIKit
import Intents
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
siriAuthorisarion()
donateRewardIntent()
}
func siriAuthorisarion() {
INPreferences.requestSiriAuthorization { (status) in
print("Siri Authorization Status - ", status)
}
}
func donateRewardIntent() {
let rewardsIntent = RewardsIntent()
rewardsIntent.suggestedInvocationPhrase = "Reward Points"
rewardsIntent.accType = "test account"
let interaction = INInteraction(intent: rewardsIntent, response: nil)
interaction.donate { error in
if let error = error {
print("Donating intent failed with error \(error)")
}
DispatchQueue.main.async {
let alert = UIAlertController.init(title: ((error != nil) ? "Error" : "Success"), message: ((error != nil) ? "Oops!!! Error occured on donating intent." : "Intent donated succussfully!!!"), preferredStyle: .alert)
alert.addAction(UIAlertAction.init(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
}
}
I'm facing problem from the above code base. Siri is not requesting for pin and not able to get the exact reward points for the account.
Have following questions.
Can we add the intents programmatically to Siri instead adding from shortcuts app or settings. So that user can directly use the functionality once installing the application.
Once intent is added using Shortcuts app, I’m trying the ask Siri for reward points. Its immediately requesting for my app shortcuts defined. Once we say 'yes' to request, I need to be asked for pin. But Siri replies with some problem with my app. What to be done for asking for next param value.
In the handler file, I have added the resolve methods for each parameters. I feel, resolve methods are not getting called to validate the values. Do we need to handle anything to make resolve methods work?
How can I debug the handler implementation using breakpoint within resolve/handle/confirm methods.
Thanks in advance.
Find my analysis for the above questions.
Can we add the intents programmatically to Siri instead adding from shortcuts app or settings. So that user can directly use the functionality once installing the application.
By default, intents are provided for specific domains such as messaging, payments, photos, workout, etc. No need to explicitly add intents through shortcuts for theses specific domains. Apart from these domains if we are creating custom intent, we are in need to donate and add the intents to Siri using shortcut/settings application.
Once intent is added using Shortcuts app, I’m trying the ask Siri for reward points. Its immediately requesting for my app shortcuts defined. Once we say 'yes' to request, I need to be asked for pin. But Siri replies with some problem with my app. What to be done for asking for next param value.
From iOS13, Apple has added Siri parameters and Siri suggestion for custom intents to request the missing parameters. Till iOS12, we don't have parameters option for custom intents.
In the handler file, I have added the resolve methods for each parameters. I feel, resolve methods are not getting called to validate the values. Do we need to handle anything to make resolve methods work?
In iOS12, we cannot add resolve methods for parameters in custom intents. Resolve methods handled only for specific domains provided within Intents extensions as mentioned in question 1. From iOS13, we can have resolve methods for custom intents based on the parameters.
How can I debug the handler implementation using breakpoint within resolve/handle/confirm methods.
We can add breakpoints and debug intent handler methods.
Thanks.

Force user to update the app programmatically in iOS

In my iOS app I have enabled force app update feature. It is like this.
If there is a critical bug fix. In the server we are setting the new release version. And in splash screen I am checking the current app version and if its lower than the service version, shows a message to update the app.
I have put 2 buttons "Update now", "Update later"
I have 2 questions
If I click now. App should open my app in the appstore with the button UPDATE. Currently I use the link "http://appstore.com/mycompanynamepvtltd"
This opens list of my company apps but it has the button OPEN, not the UPDATE even there is a new update for my app. whats the url to go for update page?
If he click the button "Update Later" is it ok to close the app programmatically? Does this cause to reject my app in the appstore?
Please help me for these 2 questions
Point 2 : You should only allow force update as an option if you don't want user to update later. Closing the app programmatically is not the right option.
Point 1 : You can use a good library available for this purpose.
Usage in Swift:
Library
func applicationDidBecomeActive(application: UIApplication) {
/* Perform daily (.daily) or weekly (.weekly) checks for new version of your app.
Useful if user returns to your app from the background after extended period of time.
Place in applicationDidBecomeActive(_:)*/
Siren.shared.checkVersion(checkType: .daily)
}
Usage in Objective-C: Library
-(void)applicationDidBecomeActive:(UIApplication *)application {
// Perform daily check for new version of your app
[[Harpy sharedInstance] checkVersionDaily];
}
How it works : It used lookup api which returns app details like link including version and compares it.
For an example, look up Yelp Software application by iTunes ID by calling https://itunes.apple.com/lookup?id=284910350
For more info, please visit link
Don't close the app programmatically. Apple can reject the app. Better approach will be do not allow user to use the app. Keep the update button. Either user will go to app store or close the app by himself.
According to Apple, your app should not terminate on its own. Since the user did not hit the Home button, any return to the Home screen gives the user the impression that your app crashed. This is confusing, non-standard behavior and should be avoided.
Please check this forum:
https://forums.developer.apple.com/thread/52767.
It is happening with lot of people. In my project I redirected the user to our website page of downloading app from app store. In that way if the user is not getting update button in app store, at least the user can use the website in safari for the time being.
To specifically answer your question:
Use this URL to directly open to your app in the app store:
https://apps.apple.com/app/id########## where ########## is your app's 10 digit numeric ID. You can find that ID in App Store Connect under the App Information section. It's called "Apple ID".
I actually have terminate functionality built into my app if it becomes so out of date that it can no longer act on the data it receives from the server (my app is an information app that requires connectivity to my web service). My app has not been rejected for having this functionality after a dozen updates over a couple years, although that function has never been invoked. I will be switching to a static message instead of terminating the app, just to be safe to avoid future updates from being rejected.
I have found that the review process is at least somewhat subjective, and different reviewers may focus on different things and reject over something that has previously been overlooked many times.
func appUpdateAvailable() -> (Bool,String?) {
guard let info = Bundle.main.infoDictionary,
let identifier = info["CFBundleIdentifier"] as? String else {
return (false,nil)
}
// let storeInfoURL: String = "http://itunes.apple.com/lookupbundleId=\(identifier)&country=IN"
let storeInfoURL:String = "https://itunes.apple.com/IN/lookup?
bundleId=\(identifier)"
var upgradeAvailable = false
var versionAvailable = ""
// Get the main bundle of the app so that we can determine the app's
version number
let bundle = Bundle.main
if let infoDictionary = bundle.infoDictionary {
// The URL for this app on the iTunes store uses the Apple ID
for the This never changes, so it is a constant
let urlOnAppStore = NSURL(string: storeInfoURL)
if let dataInJSON = NSData(contentsOf: urlOnAppStore! as URL) {
// Try to deserialize the JSON that we got
if let dict: NSDictionary = try?
JSONSerialization.jsonObject(with: dataInJSON as Data, options:
JSONSerialization.ReadingOptions.allowFragments) as! [String:
AnyObject] as NSDictionary? {
if let results:NSArray = dict["results"] as? NSArray {
if let version = (results[0] as! [String:Any]).
["version"] as? String {
// Get the version number of the current version
installed on device
if let currentVersion =
infoDictionary["CFBundleShortVersionString"] as? String {
// Check if they are the same. If not, an
upgrade is available.
print("\(version)")
if version != currentVersion {
upgradeAvailable = true
versionAvailable = version
}
}
}
}
}
}
}
return (upgradeAvailable,versionAvailable)
}
func checkAppVersion(controller: UIViewController){
let appVersion = ForceUpdateAppVersion.shared.appUpdateAvailable()
if appVersion.0 {
alertController(controller: controller, title: "New Update", message: "New version \(appVersion.1 ?? "") is available")
}
}
func alertController(controller:UIViewController,title: String,message: String){
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Update", style: .default, handler: { alert in
guard let url = URL(string: "itms-apps://itunes.apple.com/app/ewap/id1536714073") else { return }
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
UIApplication.shared.openURL(url)
}
}))
DispatchQueue.main.async {
controller.present(alertController, animated: true)
}
}
Use appgrades.io. Keep your app focus on delivering the business value and let 3rd party solution do their tricks. With appgrades, you can, once SDK integrated, create a custom view/alert to display for your old versions users asking them to update their apps. You can customize everything in the restriction view/alert to make it appear as part of your app.

Set rating right in the App (Swift 3, iOS 10.3)

I have a menu-button in my app. If user clicks this button he sees UIAlertView which include app-link to the App Store.
Here is the code:
#IBAction func navButton(_ sender: AnyObject) {
let alertController = UIAlertController(title: "Menu", message: "Thanks for using our app!", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Rate Us on the App Store", style: .default, handler: { (action: UIAlertAction) in
print("Send user to the App Store App Page")
let url = URL(string: "itms-apps://itunes.apple.com/app/id")
if UIApplication.shared.canOpenURL(url!) == true {
UIApplication.shared.openURL(url!)
}
}))
I know that in iOS 10.3 there was an opportunity to set a rating right in the application. What should I change, so that when a user clicks on a link in UIAlertView, he could set a rating right in the application?
I found some information on Apple Developer website (https://developer.apple.com/reference/storekit/skstorereviewcontroller) but I don't know how to do this in my app.
It's one class function based on looking at the docs.
SKStore​Review​Controller.requestReview()
It also states you shouldn't call this function dependent on a user pressing a button or any other type of action because it is not guaranteed to be called. It would be a bad user experience if you indicate they are about to be shown a review modal and then nothing appears.
If you use this new option in your app it seems the best option is to just place it somewhere that won't interrupt any important actions being conducted by the user and let the framework do the work.
You can use criteria the user isn't aware of to choose when to call the function, i.e. launched the app x amount of times, used x number of days in a row, etc.
Edit: alternative
If you want to keep more control over the ability to request reviews you can continue the old way and append the following to your store URL to bring them directly to the review page.
action=write-review
guard let url = URL(string: "appstoreURLString&action=write-review") else { return }
UIApplication.shared.open(url, options: [:], completionHandler: nil)

How to use requestReview (SKStore​Review​Controller) to show review popup in the current viewController after a random period of time

I've read about this new feature available in iOS 10.3 and thought it will be more flexible and out of the box. But after I read the docs I found out that you need to decide the time to show it and the viewController who calls it. Is there any way I can make it trigger after a random period of time in any viewController is showing at that moment?
In your AppDelegate:
Swift:
import StoreKit
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let shortestTime: UInt32 = 50
let longestTime: UInt32 = 500
guard let timeInterval = TimeInterval(exactly: arc4random_uniform(longestTime - shortestTime) + shortestTime) else { return true }
Timer.scheduledTimer(timeInterval: timeInterval, target: self, selector: #selector(AppDelegate.requestReview), userInfo: nil, repeats: false)
}
#objc func requestReview() {
SKStoreReviewController.requestReview()
}
Objective-C:
#import <StoreKit/StoreKit.h>
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
int shortestTime = 50;
int longestTime = 500;
int timeInterval = arc4random_uniform(longestTime - shortestTime) + shortestTime;
[NSTimer scheduledTimerWithTimeInterval:timeInterval target:self selector:#selector(requestReview) userInfo:nil repeats:NO];
}
- (void)requestReview {
[SKStoreReviewController requestReview];
}
The code above will ask Apple to prompt the user to rate the app at a random time between 50 and 500 seconds after the app finishes launching.
Remember that according to Apple's docs, there is no guarantee that the rating prompt will be presented when the requestReview is called.
For Objective - C:
Add StoreKit.framework
Then in your viewController.h
#import <StoreKit/StoreKit.h>
Then in your function call :
[SKStoreReviewController requestReview];
For Swift
Add StoreKit.framework
In your ViewController.swift
import StoreKit
Then in your function call :
if #available(iOS 10.3, *) {
SKStoreReviewController.requestReview()
} else {
// Open App Store with OpenURL method
}
That's it ! Apple will take care of when it would show the rating (randomly).
When in development it will get called every time you call it.
Edited : No need to check OS version, StoreKit won't popup if the OS is less than 10.3, thank Zakaria.
Popping up at a random time is not a good way to use that routine, and is not only in contravention of Apple's advice, but will give you less-than-great results.
Annoying the user with a pop up at a random time will never be as successful as prompting them at an appropriate time- such as when they have just completed a level or created a document, and have that warm fuzzy feeling of achievement.
Taking Peter Johnson's advice, I created a simple class where you can just stick the method in at the desired spot in your code and it'll pop up at a spot where the user's just had a success.
struct DefaultKeys {
static let uses = "uses"
}
class ReviewUtility {
// Default Keys stored in Structs.swift
static let sharedInstance = ReviewUtility()
private init() {}
func recordLaunch() {
let defaults = UserDefaults.standard
// if there's no value set when the app launches, create one
guard defaults.value(forKey: DefaultKeys.uses) != nil else { defaults.set(1, forKey: DefaultKeys.uses); return }
// read the value
var totalLaunches: Int = defaults.value(forKey: DefaultKeys.uses) as! Int
// increment it
totalLaunches += 1
// write the new value
UserDefaults.standard.set(totalLaunches, forKey: DefaultKeys.uses)
// pick whatever interval you want
if totalLaunches % 20 == 0 {
// not sure if necessary, but being neurotic
if #available(iOS 10.3, *) {
// do storekit review here
SKStoreReviewController.requestReview()
}
}
}
}
To use it, stick this where you want it to be called and hopefully you won't tick off users with randomness.
ReviewUtility.sharedInstance.recordLaunch()
Showing the dialog at random time is not probably a good idea. Please see the Apple guideline which mentions: Don’t interrupt the user, especially when they’re performing a time-sensitive or stressful task.
This is what Apple suggests:
Ask for a rating only after the user has demonstrated engagement with your app. For example, prompt the user upon the completion of a game level or productivity task. Never ask for a rating on first launch or during onboarding. Allow ample time to form an opinion.
Don’t be a pest. Repeated rating prompts can be irritating, and may even negatively influence the user’s opinion of your app. Allow at least a week or two between rating requests and only prompt again after the user has demonstrated additional engagement with your app.
This post is also quite interesting...
I cant add comments yet but if you are using Appirater you might want to check the version to see if its lower than 10.3 so the other Appirater review message box pops up.

Resources