In this post, I am going to share the code (Swift) to ask users to leave a review for your app, and my logic behind when to prompt users to leave a review. What logic? I mean as a user the last thing I want is for an app to ask me to leave a review, the first time I open it. That’s just annoying and in that case I am more likely to leave a negative review. Anyway let’s start with,

Background

At first when My Day To-Do launched, prompting users to leave a review for the app was a lower priority item on the list of things to-do. However download spikes over years pushed it to a higher priority item and something had to be done ASAP (If you want to know more about the download spike, you can read this post). In my goal to add the logic to prompt users for a review, I discovered that there is more than one way to do this, depending on the iOS version on the user’s device. In summary, for anyone using iOS10.3 and above you will write a lot less code than you will for those using versions below iOS 10.3.

Problem

Provide a means for users of my iOS app to leave a review for the app i.e. a prompt or something asking them to review the app.

Solution

There are many things to consider for this solution. Things such as,

When to ask users to leave a review?

The last thing I wanted for My Day To-Do is for the users to open the app and be prompted for a review. I only wanted to prompt the users who have used the app a certain number of times to leave a review. I mean if someone has used your app more than once, chances are that they like it and are more likely to leave a positive review or constructive criticism in their negative review that you can work on. At the same time, you also cannot wait forever (a  few weeks) to prompt users and ask them to leave a review they are more likely to stop using your app. I mean the priority is USERS FIRST and if there is something in your app that they do not like (and for good reason), it has to be addressed ASAP. Therefore while coming up with my logic, I had to make a choice that strikes a balance between the aforementioned things.

The logic behind user review prompt

How I solved this problem is by maintaining a counter in UserDefaults of how many times does the user access the ‘Day Tasks’ tab of My Day To-Do. Once the counter crosses a certain threshold X, I prompt the users to leave a review.

fyi, My Day To-Do is a tab based task management app with the main tab being the ‘Day Tasks’ tab, where your day tasks are loaded for a particular date. 

For users using iOS 10.3 and above

This one is really simple, it’s literally just a few lines of code

import StoreKit

func askForUserReview(userDefaults: UserDefaults) {
        let reviewReqCount = userDefaults.integer(forKey: Constants.REVIEW_REQUEST_COUNT)
        if let reReqCount = reviewReqCount {
        if reReqCount > X {

        SKStoreReviewController.requestReview()
        if #available(iOS 10.3, *) {}
    }
}

SKStoreReviewController is a part of the StoreKit framework, so make sure that you have that import statement in your class.

The code above is pretty explanatory but let me clarify a few things to avoid confusion (if any?)

We have a function called askForUserReview that expects a userDefaults as a parameter, I mean we could declare a userDefaults as a class variable but I prefer avoiding that in favour of function params. Why? Just in case I start writing recursive code, this habit would help, personally I find it much easier to debug code this way. Listing all the reasons is beyond the scope of this post, so I won’t.

let reviewReqCount = userDefaults.integer(forKey: Constants.REVIEW_REQUEST_COUNT)

Next, we get the review request count value. I mentioned earlier that we only ask users to leave a review for the app if they have used the app a certain number of times which we can track through a counter stored in userDefaults. Regarding Constants.REVIEW_REQUEST_COUNT, I generally avoid hard coding strings in code, especially those that are constants. Hence I have a Constants class with a static variable REVIEW_REQUEST_COUNT which is the key used to store and retrieve the reviewRequestCounter.

I will avoid talking about the if condition for unwrapping optionals, I mean that should be immediately obvious to anyone who has worked with Swift. If you have not? then read here to know more about it.

if reReqCount > X {
    if #available(iOS 10.3, *) {
        SKStoreReviewController.requestReview()
    }
}

The next thing we do is to check  if our reviewRequestCounter is above X, remember X is just arbitrary number (integer), I mean it’s just another constant e.g. X = 10 or X = 25  etc. Then we check if the user is on a device running iOS10.3 or above. If so then we request the user to leave a review for the app, via SKStoreReviewController.requestReview() method and that’s it, it really is that simple to show a review request prompt to the user.

What if the use’s device is below iOS 10.3?

Awesome question and let’s see how to achieve that,

func askForUserReview(userDefaults: UserDefaults) {
    let reviewReqCount = userDefaults.integer(forKey: Constants.REVIEW_REQUEST_COUNT)
    if let reReqCount = reviewReqCount {
        if reReqCount > X {
            if #available(iOS 10.3, *) {
                SKStoreReviewController.requestReview()
            } else {
                let title = NSLocalizedString("reviewReqTitle", comment: "")
                let message = NSLocalizedString("reviewReqMsg", comment: "")
                let okTxt = NSLocalizedString("ok", comment: "")
                let cancelTxt = NSLocalizedString("cancel", comment: "")
                if hostViewController.presentingViewController == nil {
                    let alertWithConfirm = UIAlertController(title: title,  message: message, preferredStyle: .alert)
                    let ok = UIAlertAction(title: okTxt, style: .cancel) {
                        Void in
                        self.rateApp(appId: "id1066820078") { success in
                            print("RateApp (success)")
                        }
                        self.incrementReviewRequestCount(reviewReqCount: reReqCount,userDefaults: userDefaults)
                    }
                    let cancel = UIAlertAction(title: cancelTxt, style: .destructive, handler: nil)
                    alertWithConfirm.addAction(ok)
                    alertWithConfirm.addAction(cancel)
                    hostViewController.present(alertWithConfirm, animated: true, completion: nil)
                }
            }
        }
    }
}
func rateApp(appId: String, completion: @escaping ((_ success: Bool)->())) {
    guard let url = URL(string : "itms-apps://itunes.apple.com/app/" + appId) else {
        completion(false)
        return
    }
    completion(UIApplication.shared.openURL(url))
}

In summary, what’s happening in the code above is, we prompt the user with an alert (UIAlertController) and ask them, “Are you enjoying the app? Would you like to leave a review?” and they have the option of tapping the Yes or No buttons. If they say yes, we redirect them to the app store page of the app via it’s app id which in this case is the app id of My Day To-Do.

Now let’s examine individual sections of the code above to gain a better understanding,

let title = NSLocalizedString("reviewReqTitle", comment: "")
let message = NSLocalizedString("reviewReqMsg", comment: "")

let cancelTxt = NSLocalizedString("cancel", comment: "")
let okTxt = NSLocalizedString("ok", comment: "")
Here the text for the dialog prompt shown to the user asking them whether or not they want to leave a review for the app is being initialised. You can read more about NSLocalizedString here but it’s generally a good idea to have all static text in your app come from a strings file, so in case you want to localise it, you are ready for it. If you want a better understanding of how to localise your iOS app, have a read of this tutorial.

p.s. In case of users with iOS versions 10.3 and above, we do not have to show any Alert dialogs or anything, the SKStoreReviewController.requestReview takes care of everything for us.

if hostViewController.presentingViewController == nil {
     let alertWithConfirm = UIAlertController(title: title,  message: message, preferredStyle: .alert)
     let ok = UIAlertAction(title: okTxt, style: .cancel) {
      Void in
        self.rateApp(appId: "id1066820078") { success in
            print("RateApp (success)")
         }
    }
    let cancel = UIAlertAction(title: cancelTxt, style: .destructive, handler: nil)
    alertWithConfirm.addAction(ok)
    alertWithConfirm.addAction(cancel)
    hostViewController.present(alertWithConfirm, animated: true, completion: nil)
}

Next, is just a simple check to ensure if the ViewController is already presenting another viewController. If not, then show (present) the Alert dialog to ask users for an app review using the text initialised earlier with the logic to handle (UIAlertAction) the OK button press, tap etc (in case the user agrees to leave an app review). In the code above, if the user chooses to leave a review for the app, the control is passed to the rateApp method.

func rateApp(appId: String, completion: @escaping ((_ success: Bool)->())) {
    guard let url = URL(string : "itms-apps://itunes.apple.com/app/" + appId) else {
        completion(false)
        return
    }
    completion(UIApplication.shared.openURL(url))
}

The id is at the end, I have highlighted that part of the url in bold, so if you want to get the App ID for your app, I assume you should be able to find it in it’s app store URL.

Lastly, if you need to know more about completionHandlers, have a read of this article and decide when it’s best for you to use them.

Conclusion

Phew! That took longer than I initially thought, anyway in this post we examined how to prompt users to leave a review for your iOS app. If you haven’t already added a means to ask users to leave a review for your app, then do that ASAP. Think of a way in which it makes the most sense for your app to ask users for a review and then add a review prompt. If you do not have enough time to add a fallback to iOS versions before 10.3 then at least do so for those with iOS10.3 and above. I have shown you just how simple it is to prompt the user to leave a reiew of your app on the App Store, so in case you don’t have this feature in your app, then do so ASAP!

As usual, if you find any of my posts useful support us by  buying or even trying one of our products and leave us a review on the app store.

‎My Day To-Do - Smart Task List
‎My Day To-Do - Smart Task List
‎My Day To-Do Lite - Task list
‎My Day To-Do Lite - Task list
‎Snap! I was there
‎Snap! I was there
Developer: Bhuman Soni
Price: $3.99
Numbers Game: Calculation Master
Numbers Game: Calculation Master
‎Simple 'N' Easy Task List
‎Simple 'N' Easy Task List
‎Captain's Personal Log
‎Captain's Personal Log
Developer: Bhuman Soni
Price: $4.99
Categories: iOSiosapp

Leave a Reply

Your email address will not be published. Required fields are marked *