SKStoreReviewController如何检测用户在设置中关闭了“评价此应用程序”(RTA)或达到了3次限制?

20
自从iOS 10.3版本开始,苹果公司将应用评论提示(Rate This App)的次数限制在每年三次,并且可以在用户设置中关闭。
问:我们如何检测已经达到了3次限制或者用户已经关闭了RTA,以便在应用程序中不会显示弹出窗口,询问:“您喜欢这个应用吗?如果是,请写一条评论?[是/否]”,因为如果用户点击是,则不会显示任何内容。
官方文档中并没有提供太多信息:https://developer.apple.com/reference/storekit/skstorereviewcontroller 引用:
尽管在您的应用程序的用户体验流程中调用此方法是有意义的,但评级/评论请求视图的实际显示受App Store政策的管理。由于此方法可能或可能不会呈现警报,因此不适合响应按钮点击或其他用户操作来调用它。
4个回答

13

前言

询问用户是否喜欢该应用可能会导致您的应用被拒绝。以下是一个例子: https://twitter.com/pietbrauer/status/791883047373246464

如果链接失效了,这里是苹果公司的回复摘录:

3.2.2 … 您的应用包含可以操纵 App Store 上的用户评论或排名的内容和功能。具体而言,您的应用筛选用户评论,并仅引导打算在 App Store 上给您的应用评4-5星的用户完成评分...

我个人认为,如果您真正尝试解决用户的问题,并在此之后给他们留下撰写评论的机会,这可以是一种有效的策略,但问题在于苹果公司是否会这样看待它。

可能的解决方案

  1. 弹出窗口询问用户是否喜欢使用该应用。
  2. 尝试使用[SKStoreReviewController requestReview]来获取评论。
  3. 检查窗口数量是否发生了变化,这表明已经显示了一个弹出窗口。不过,这里有个注意点,即某些其他事件也可能导致窗口数量发生变化,因此该方法并不完全可靠。
  4. 如果窗口的数量保持不变,使用深度链接将用户转到应用商店。 SKStoreReviewController文档建议在查询参数中使用action=write-review直接进入评论页面。

这里是一个简单的实现:

// make sure we the current iOS version supports in app reviews
if ([SKStoreReviewController class])
{
    NSUInteger windowCount = [UIApplication sharedApplication].windows.count;
    [SKStoreReviewController requestReview];

    // give the review controller some time to display the popup
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
        if (windowCount < [UIApplication sharedApplication].windows.count)
        {
            // assume review popup showed instead of some other system alert
            // for example show "thank you"
        }
        else
        {
            // open app store to leave review
            NSURL *reviewUrl = [NSURL URLWithString:@"{your-app-url}?action=write-review"];
            [[UIApplication sharedApplication] openURL:reviewUrl];
        }
    });
}

注意:我尚未将此代码提交到App Store,因此这只是理论上的。


2
所以如果我正确理解你的代码,你正在尝试显示新的苹果评论弹出窗口,但如果它失败了(因为已经显示了3次,或者用户已经关闭了它),那么你仍然会使用旧方法向他们显示评论页面?嗯,我不确定苹果公司是否会接受这种做法,因为这正是他们试图阻止的。 - Van Du Tran
什么是异常? - Tim Johnsen
从答案中@TimJohnsen的话来看:“...这并非百分之百可靠,因为其他某些事件可能会导致窗口数量发生变化。” 例如,另一个系统弹出。 - Nikola Lajic
自从iOS 11以后,"action=write-review"就不再起作用了。是的,这与苹果自己的文档相矛盾,但我想他们可能还没有更新这些文档。 - Jonny
1
@bauerMusic 它不会默默失败,如果弹出窗口未显示,它将打开App Store的评论页面。 - Nikola Lajic
显示剩余9条评论

8

嗯,你可以尝试发送请求并查看,但只要没有回调函数以及没有其他官方方法可以检测到在调用请求方法时是否显示了评级警告。

然而,有一种 解决方法 - 可以调用StoreKit类之一进行swizzling,这样就可以观察到何时打开评级对话框。

检查UIWindow的方式也可能有用,但是调用方法的swizzling可能更可靠。

您还可以使用一些评级管理器(如作为pod提供的AppRating),它们可以为您管理这些内容,但仅在一个朴素的水平上通过计算调用次数和记住它。


那么有什么解决办法呢?那个视图绝对超出了UIWindows的子视图。它甚至不会出现在视图层次结构3D调试视图中。 - diegotrevisan
我已经更新了原始答案,以涵盖我们目前使用的方式。享受吧! - Michi
@Michi的链接无效了,请问你能否编辑并提供正确的解决方案呢? - Tahan

4

基于之前回答的方法,可以"监测"窗口计数的变化。下面是一个适用于iOS 10.3到14.4,并在Swift 5.4上运行的版本:

func currentWindowCount() -> Int { UIApplication.shared.windows.count }

let initialWindowCount = currentWindowCount()

if #available(iOS 14.0, *) {
    if let scene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene {
        SKStoreReviewController.requestReview(in: scene)
    }
} else {
    SKStoreReviewController.requestReview()
}

DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    let actuallyShowedPrompt = initialWindowCount < currentWindowCount()
    if actuallyShowedPrompt {
        // do stuff
    }
}

actuallyShowedPrompt 只会在第一次为 true,之后每次都为 false。有人遇到同样的问题吗? - Kaushik Makwana
@Kaushik Makwana,这是在沙盒(测试)模式下的预期行为。在生产环境中,第一次应用程序尝试时可能不会显示提示。详情请参阅requestReview()文档 - s3cur3
我刚在模拟器中发现了这个“行为”,并且它可能在设备上也是如此。似乎当显示审查请求时添加的窗口不会随后被移除,因此 currentWindowCount / windowCount 不会返回最初看到的值,例如 1,即它可能保持在 4。因此,第一次之后 actuallyShowedPrompt 为 false。重新启动应用程序将解决此问题。请注意,延迟需要足够长,以使审查警报出现,否则可能会错过,“执行操作”永远不会执行。 - ghr

4

我正在生产代码中使用这个解决方案 - 目前苹果没有拒绝:

NSUInteger windowCount = [UIApplication sharedApplication].windows.count;
// SKStoreReviewController only available for >= 10.3, if needed check for class existence
[SKStoreReviewController requestReview];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
    BOOL shown = windowCount < [UIApplication sharedApplication].windows.count;
    if (shown) {
        //popup was shown
    }
};

1
一个带有完成块的功能,如果用户实际上提交了评论或点击了“暂不”按钮,将会非常有帮助。 - Henry Heleine
1
这在我们的经过苹果批准的生产代码中可行,谢谢。请注意,[SKStoreReviewController requestReview] 在 iOS 14 中已弃用,应使用 [SKStoreReviewController requestReviewInScene:] - Martijn
这在iOS 16.7设备上仍然有效。 请注意,在Xcode 14.3.1的模拟器中无法使用。 另外,请注意,自iOS 15.0起,[UIApplication sharedApplication].windows.count已被弃用,请改用self.view.window.windowScene.windows.count - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接