【Swift】requestReview()がiOS14.0から非推奨だったので対応した

2021.08.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ユーザーにレビューを促すSKStoreViewController.requestReview()がiOS14から非推奨になっていたので、推奨されている形に直す為に調べました。

環境

  • Xcode 12.5
  • Swift 5.4
  • iOS Deployment Target 14.1

requestReviewとは

ユーザーにアプリのレビューを促すこのような画面を出す処理になります。

'requestReview()' was deprecated in iOS 14.0

Deployment Targetを14.0以上に設定している場合、SKStoreReviewController.requestReview()を使用すると、'requestReview()' was deprecated in iOS 14.0と警告が出ます。

つまりは、iOS14.0で非推奨になったので使ってくれるなということですね。 非推奨になったからと言って利用できないわけではないですが、今後急に機能しなくなる可能性も多いにあるので早めに推奨される形に修正しましょう。

解決策

早速ですが、こちらのコードに置き換えたら解決しました。

if let scene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene {
    SKStoreReviewController.requestReview(in: scene)
}

解決方法は分かったのですが、何を意味しているのかを調べてみた。

connectedScenes

var connectedScenes: Set<UIScene> { get }

UIApplication.shared.connectedScenesは、

connectedScenesとは、メモリ内にある、アクティブな作業を行っている可能性のあるシーンです。connectedScenesに含まれるシーンは、フォアグラウンドまたはバックグラウンド、オンスクリーンまたはオフスクリーンの場合があります。

アプリがマルチウィンドウ対応し、複数画面を表示した時にconnectedScenesには複数の値がSet型で保持されます。

activationState

Sceneの現在の活性状態を表すactivationStateを調べてみると、

public enum ActivationState : Int {

        case unattached = -1
        case foregroundActive = 0
        case foregroundInactive = 1
        case background = 2
    }
  • unattached: シーンが現在アプリに接続されていないことを示す状態
  • foregroundActive: シーンがフォアグラウンドで実行されており、現在イベントを受信して​​いることを示す状態態
  • foregroundInactive: シーンがフォアグラウンドで実行されているが、イベントを受信して​​いないことを示す状態
  • シーンがバックグラウンドで実行されており、画面に表示されていないことを示す状態

なので、UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive })の部分で、アプリのシーンの中からフォアグラウンドで実行されていてイベントを受信している要素を見つけて返しています。

requestReview(in:)

iOS14から導入された従来のrequestReview()に代わるメソッドで、今までのreqeustReviewにどのシーンで使用するのかという引数の代入が必要となりました。

なんだか、これからマルチウィンドウ化が進んでいく未来がなんだか見えてきました。

もう少し実行内容を明確化したい

// 以前
SKStoreReviewController.requestReview()

// iOS 14.0~
if let scene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene {
    SKStoreReviewController.requestReview(in: scene)
}

これまでは、SKStoreReviewController.requestReview()だけでレビュー画面を表示できただけになんだか長くてパッと見わかりにくい気が、、。

てとこで、UIApplicationextensionを作成して、コードをリファクタリングしてみました。

UIApplication Extension

extension UIApplication {

    var forgroundActiveScene: UIWindowScene? {
        return self.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene
    }
}

リファクタリング後のコード

フォアグラウンドで活性化しているシーンsceneに代入しているのが分かりやすくなりました。

if let scene = UIApplication.shared.forgroundActiveScene {
    SKStoreReviewController.requestReview(in: scene)
}

おまけ

「このアプリはiOSのみに限定されていて、iPadのマルチウィンドウには対応するつもりはないから、connectedScenesは常に一つしかないんだ!」 という方は、

この書き方でもreviewRequest(in:)を動作させることが出来ます。

if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
    SKStoreReviewController.requestReview(in: scene)
}

このconnectedScenesSet型なので、要素が複数ある場合は必ずしもfirst.forgroundActiveであるとは決まっていません。

ですが、このconnectedScenesの要素が一つに限られる場合のみ、要素には現在起動しているアプリのその時点でのアクティブなウィンドウしか無い為、first.forgroundActiveのシーンを取得することが出来ます。

結局、一番スマートそうな解決策

表示する画面がある特定の画面の場合に、view.windowからwindowSceneを取る方法もあるよ。と教えていただきました。

if let scene = view.window?.windowScene {
    SKStoreReviewController.requestReview(in: scene)
}

単純に現在のviewに追加されているwindowwindowSceneからsceneを取得する方法です。

sceneの取得方法をあれこれ書いてみましたが、この方法が一番明確でシンプルで良さそうです。

365日ルール

レビューリクエスト画面は、365日で最大3回までしか表示されないルールがあるようです。

なので、どの時、どの場所で出すのが一番効果的かをしっかり考えてリクエスト出す必要がありそうです。

それに伴い、Human Interface Guidelinesに記載されていますが、ボタンなどの操作(例: レビューをするButton)でレビューリクエスト出す処理は行わないで下さいとのことです。リクエストリミットを超えてしまうと、ボタン等を押しても何も反応しなくなるのでユーザーには悪い体験を与えてしまいます。

おわりに

ユーザーに自らアプリを評価していただけるならもちろん嬉しい限りですが、ユーザーがレビューしやすい環境や仕組み作りが大事ということが分かりました。

たくさんレビューリクエストを出せばいいわけではないですし、ユーザーにある程度使ってもらって、アプリへの感想が少し溜まったあたりでレビューリクエストを出すのが良さそうですね。じゃあ、それはいつなんだよ?って感じですが、、。

色々試しながらクリティカルなレビューリクエストを模索していきたいと思います。

最後に、僕はどちらかというとタコが好きです。

参考