SKStore Review Controller,如何以正确的方式使用它?

时间:2017-04-03 05:42:48

标签: ios objective-c iphone ios10.3 skstorereviewcontroller

我已经看到了一些答案,但对它们不满意并得到了一些想法,但不知道如何正确使用它,以便它将以正确的方式执行,尽管我认为它应该在App委托{{{ 1}},但我想确定在Live应用程序中实现它之前没有任何喧嚣。     didFinishLaunching仅适用于ios 10.3我所阅读的内容,任何人都可以用迅速和客观的c解释一点代码。

更新

实际上我对调用方法SKStore​Review​Controller很困惑,我需要在哪里调用这个方法?在request​Review()的{​​{1}}或rootViewController的{​​{1}}中?

感谢。

6 个答案:

答案 0 :(得分:68)

SKStoreReviewController在iOS 10.3及更高版本中可用。

根据APPLE的文件:

  

您可以要求用户在使用该应用时对其进行评分或评论,   无需将它们发送到App Store。您可以确定其中的点数   用户体验,调用API和系统是有意义的   照顾其他人。

为了在应用内显示评分/评论,您必须添加StoreKit框架。

请找到两种语言的示例代码:

目标C:

#import <StoreKit/StoreKit.h>

- (void)DisplayReviewController {
    if([SKStoreReviewController class]){
       [SKStoreReviewController requestReview] ;
    }
}

因为xCode 9你可以这样做:

#import <StoreKit/StoreKit.h>

- (void)DisplayReviewController {
    if (@available(iOS 10.3, *)) {
        [SKStoreReviewController requestReview];
    }
}

夫特:

import StoreKit

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

更新:Ask for a rating only after the user has demonstrated engagement with your app

答案 1 :(得分:8)

对于目标C,

1-)从 Link Binary With Library 添加了StoreKit框架 enter image description here

2-)添加了框架

#import <StoreKit/StoreKit.h>

3-)添加了以下代码,您可以在其中调用App-Review弹出窗口。在这种情况下,我添加了viewDidLoad。

  - (void)viewDidLoad {
        [super viewDidLoad];
        [SKStoreReviewController requestReview];
    }

4-)当您在调试模式下进行测试时,您应该了解Apple的以下解释

  

当您的应用仍处于开发模式时调用此方法时,将始终显示评级/评论请求视图,以便您可以测试用户界面和体验。但是,当您在使用TestFlight分发的应用程序中调用此方法时,此方法无效。

答案 2 :(得分:4)

我认为直接调用以下内容不是一个好主意

  

SKStoreReviewController.requestReview()

可以像用户打开你的应用程序10(10,20,30,... 100)的倍数那样你可以显示以供审查

所以首先你需要创建一个文件来负责所有事情,例如在userdefaults中保存你的应用程序打开计数,检索应用程序打开计数并显示requestReview() 请看下面的代码片段

    new ol.layer.Image({
      extent: [-13884991, 2870341, -7455066, 6338219],
      source: new ol.source.ImageWMS({
        url: 'https://ahocevar.com/geoserver/wms',
        params: {'LAYERS': 'topp:states,topp:population'}, // <---
        ratio: 1,
        serverType: 'geoserver'
      })
    })

}

答案 3 :(得分:3)

在上面添加了呵叻的好答案...

如果您支持旧版Objective-C应用程序,并且希望在几个应用程序打开后调用DisplayReviewController,请执行以下操作:

在您的类AppDelegate.m中添加以下内容:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  int count = [[NSUserDefaults standardUserDefaults] integerForKey:@"LaunchCount"];
  if(count < 0) count = 0;
  [[NSUserDefaults standardUserDefaults] setInteger:count+1 forKey:@"LaunchCount"];
}

//The application was in background and become active
- (void)applicationWillEnterForeground:(UIApplication *)application {
  int count = [[NSUserDefaults standardUserDefaults] integerForKey:@"LaunchCount"];
  if(count < 0) count = 0;
  [[NSUserDefaults standardUserDefaults] setInteger:count+1 forKey:@"LaunchCount"];
}

并在控制器中要调用该函数:

- (void)applicationDidBecomeActive {

  if ([[NSUserDefaults standardUserDefaults] integerForKey:@"LaunchCount"] == 5) {
     [self DisplayReviewController];
  }
}

答案 4 :(得分:1)

我认为你可以实现一个方法来计算他们运行应用程序并将其存储在UserDefaults中,然后调用requestReview(),如果计数数字是5或10或类似的东西(这取决于你),通过这种方式你有更多机会获得好评。

答案 5 :(得分:1)

这是我正在为自己的用例开发的实用程序函数,它可能会帮助很多其他人。 (随意烘烤和改进/更正我的代码:D)。我正在开发一个语音练习应用程序,我想在用户完成一些录音后要求评分。我将添加 main 函数,然后添加它下面使用的其他辅助函数。简单的逻辑是,您一年可以申请 3 次审核,因此如果 1 year has passed,我将询问计数重置为 0。此外,不会为每个询问显示审核请求。所以在我不允许应用程序再尝试审核请求之前,我有 30 个请求的上限。如果应用版本发生变化,则不会考虑这一点,因为您可以再次要求对新应用版本进行审核。

/// Requests review from user based on certain conditions.
/// 1. Should have recorderd at least 3 recordings (if you want to force attept a review ask don't pass any parameter)
/// 2. Has not already asked for a review today
/// 3. A probabitly of 50% if will ask today
/// 4. If review has not been asked more than 30 times in the same year for the current version
/// - Parameter numberOfRecordings: If the number of recordings is greater than 3 then a review will be asked.
func askForReview(numberOfRecordings: Int = 5) {
    let defaults = UserDefaults.standard
    let lastAskedReviewAt = defaults.double(forKey: lastAskedReviewAtKey)
    let dateStringForLastReviewAsk = getDateString(from: lastAskedReviewAt)
    let dateForLastReviewAsk = getDate(from: dateStringForLastReviewAsk) ?? Date(timeIntervalSince1970: 0)
    let askedReviewToday = Calendar.current.isDateInToday(dateForLastReviewAsk)
    var appReviewRequestsCount = defaults.integer(forKey: appReviewRequestsCountKey)
    
    if Date().localDate().years(from: dateForLastReviewAsk) >= 1 {
        defaults.setValue(0, forKey: appReviewRequestsCountKey)
        appReviewRequestsCount = 0
    }
    
    var isAskingReviewForSameVersion = false
    
    if let currentlyInstalledVersion = getInstalledVersionNumber(), let lastReviewAskedForVersion = defaults.string(forKey: lastReviewAskedForVersionKey) {
        if currentlyInstalledVersion == lastReviewAskedForVersion {
            isAskingReviewForSameVersion = true
        } else {
            appReviewRequestsCount = 0
            defaults.setValue(0, forKey: appReviewRequestsCountKey)
        }
    }
    
    let askingReviewTooManyTimes = appReviewRequestsCount >= 30 && isAskingReviewForSameVersion
    
    let totalRecordingsTillDateCount = defaults.integer(forKey: totalRecordingsTillDateCountKey)
    let localNumberOfRecordings = max(numberOfRecordings, totalRecordingsTillDateCount)
    
    if localNumberOfRecordings > 3 && Bool.random() && !askedReviewToday && !askingReviewTooManyTimes {
        SKStoreReviewController.requestReview()
        defaults.setValue(Date().timeIntervalSince1970, forKey: lastAskedReviewAtKey)
        if let versionNumber = getInstalledVersionNumber() {
            defaults.setValue(versionNumber, forKey: lastReviewAskedForVersionKey)
        }
        defaults.setValue(appReviewRequestsCount + 1, forKey: appReviewRequestsCountKey)
    }
}

字典键:

let lastAskedReviewAtKey = "LastAskedReviewAt"
let appReviewRequestsCountKey = "AppReviewRequestsCount"
let lastReviewAskedForVersionKey = "AskedReviewForVersion"
let appVersionNumberKey = "CFBundleShortVersionString"

辅助函数:

/// Get a string representation in current local time for a timestamp
/// - Parameter timestamp: Timestamp to be converted to date string
/// - Returns: A date string from passed timestamp in dd MMM yyy format
func getDateString(from timestamp: Double) -> String {
    let dateFormatter = getDateFormatter()
    let date = Date(timeIntervalSince1970: timestamp)
    let dateString = dateFormatter.string(from: date)
    return dateString
}

/// Get a date from a string of date format dd MMM yyyy.
/// - Parameter dateString: Date string formated as dd MMM yyyy
/// - Returns: A date object by parsing date in dd MMM yyy format
func getDate(from dateString: String) -> Date? {
    //        print("Date String: ", dateString)
    let dateFormatter = getDateFormatter()
    return dateFormatter.date(from: dateString) ?? nil
}


//Ref: https://stackoverflow.com/questions/27182023/getting-the-difference-between-two-dates-months-days-hours-minutes-seconds-in
extension Date {
    /// Returns the amount of years from another date
    func years(from date: Date) -> Int {
        return Calendar.current.dateComponents([.year], from: date, to: self).year ?? 0
    }
    /// Returns the amount of months from another date
    func months(from date: Date) -> Int {
        return Calendar.current.dateComponents([.month], from: date, to: self).month ?? 0
    }
    /// Returns the amount of weeks from another date
    func weeks(from date: Date) -> Int {
        return Calendar.current.dateComponents([.weekOfMonth], from: date, to: self).weekOfMonth ?? 0
    }
    /// Returns the amount of days from another date
    func days(from date: Date) -> Int {
        return Calendar.current.dateComponents([.day], from: date, to: self).day ?? 0
    }
    /// Returns the amount of hours from another date
    func hours(from date: Date) -> Int {
        return Calendar.current.dateComponents([.hour], from: date, to: self).hour ?? 0
    }
    /// Returns the amount of minutes from another date
    func minutes(from date: Date) -> Int {
        return Calendar.current.dateComponents([.minute], from: date, to: self).minute ?? 0
    }
    /// Returns the amount of seconds from another date
    func seconds(from date: Date) -> Int {
        return Calendar.current.dateComponents([.second], from: date, to: self).second ?? 0
    }
    /// Returns the a custom time interval description from another date
    func offset(from date: Date) -> String {
        if years(from: date)   > 0 { return "\(years(from: date))y"   }
        if months(from: date)  > 0 { return "\(months(from: date))M"  }
        if weeks(from: date)   > 0 { return "\(weeks(from: date))w"   }
        if days(from: date)    > 0 { return "\(days(from: date))d"    }
        if hours(from: date)   > 0 { return "\(hours(from: date))h"   }
        if minutes(from: date) > 0 { return "\(minutes(from: date))m" }
        if seconds(from: date) > 0 { return "\(seconds(from: date))s" }
        return ""
    }
}

//Ref: https://stackoverflow.com/questions/28404154/swift-get-local-date-and-time
extension Date {
    func localDate() -> Date {
        let nowUTC = Date()
        let timeZoneOffset = Double(TimeZone.current.secondsFromGMT(for: nowUTC))
        guard let localDate = Calendar.current.date(byAdding: .second, value: Int(timeZoneOffset), to: nowUTC) else {return Date()}

        return localDate
    }
}

func getInstalledVersionNumber() -> String? {
    guard let infoDictionary = Bundle.main.infoDictionary, let currentVersionNumber = infoDictionary[appVersionNumberKey] as? String else { return nil}
    return currentVersionNumber
}