SKStore Review Controller, как правильно его использовать?
Я видел какой-то ответ, но не удовлетворен им и получил некоторое представление, но не знаю, как правильно его использовать, чтобы он работал правильно, хотя я думаю, что его следует использовать в делегатах приложения didFinishLaunching
, но я хотел быть уверен, прежде чем внедрить его в приложение Live без каких-либо суеты. SKStoreReviewController
Это только работа для IOS 10.3, что я прочитал, кто-нибудь может объяснить с небольшим количеством кода в быстрой и объективной c.
ОБНОВИТЬ:
На самом деле я запутался в вызове метода requestReview()
Где мне нужно вызвать этот метод? в rootViewController
"s viewDidLoad
или в appDelegate
"s didFinishlaunching
?
Благодарю.
6 ответов
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];
}
}
Swift:
import StoreKit
func DisplayReviewController {
if #available( iOS 10.3,*){
SKStoreReviewController.requestReview()
}
}
Для цели C,
1-) Добавлен фреймворк StoreKit из Link Binary With Library
2-) Добавлены рамки
#import <StoreKit/StoreKit.h>
3-) Добавлен код ниже, где вы хотите вызвать всплывающее окно App-Review. В этом случае я добавил в viewDidLoad.
- (void)viewDidLoad {
[super viewDidLoad];
[SKStoreReviewController requestReview];
}
4-) Вы должны знать ниже объяснить от Apple, когда вы тестируете в режиме отладки
Когда вы вызываете этот метод, когда ваше приложение все еще находится в режиме разработки, всегда отображается представление запроса оценки / обзора, чтобы вы могли протестировать пользовательский интерфейс и опыт. Однако этот метод не действует, когда вы вызываете его в приложении, которое вы распространяете с помощью TestFlight.
Я думаю, что прямой вызов ниже не очень хорошая идея
SKStoreReviewController.requestReview()
Это можно сделать так, как если бы пользователь открывал ваше приложение, кратное 10(10,20,30,...100), тогда вы можете показать его для просмотра.
поэтому прежде всего вам нужно создать файл, который будет отвечать за все, например, сохранение счета открытия вашего приложения в userdefaults, извлечение счета открытия приложения и отображение requestReview (). Пожалуйста, взгляните на следующий фрагмент кода
import Foundation
import StoreKit
class SpsRateManager {
private static let instance = SpsRateManager()
var shareinstance: SpsRateManager{
return .instance
}
static func incrementAppOpenedCount() { // called from appdelegate didfinishLaunchingWithOptions:
let userdefault = UserDefaults.standard
let savedvalue = userdefault.integer(forKey: Configuration.APPLICATIONOPENCOUNTSTATUS)
if savedvalue == 0 {
print("Not saved ")
userdefault.set(1, forKey: Configuration.APPLICATIONOPENCOUNTSTATUS)
}
else{
userdefault.set(savedvalue+1, forKey: Configuration.APPLICATIONOPENCOUNTSTATUS)
}
}
static func checkAppopencountandProvideReview(){
let userdefault = UserDefaults.standard
let appopencountvalue = userdefault.integer(forKey: Configuration.APPLICATIONOPENCOUNTSTATUS)
if appopencountvalue % 10 == 0 {
print("its been 10 times so ask for review ")
SpsRateManager().requestReview()
}
else{
print("not enough open count dont show ")
}
}
fileprivate func requestReview() {
if #available(iOS 10.3, *) {
SKStoreReviewController.requestReview()
} else {
// Fallback on earlier versions
// Try any other 3rd party or manual method here.
}
}
}
Добавление на великий ответ Кората выше...
Если вы поддерживаете устаревшее приложение 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];
}
}
Я думаю, что вы можете реализовать метод подсчета, когда они запускают приложение, и сохранить его в UserDefaults, а затем вызвать requestReview(), если число отсчетов равно 5 или 10 или что-то в этом роде (это зависит от вас), таким образом, у вас есть больше шанс получить хороший обзор.
Вот служебная функция, которую я разрабатываю для своего собственного варианта использования, которая может помочь многим другим людям. (Не стесняйтесь жарить и улучшать / исправлять мой код:D). Я работаю над приложением для речевой практики и хочу попросить оценку после того, как пользователь сделал несколько записей. Я добавлю основную функцию, а затем другие вспомогательные функции, используемые под ней. Краткая логика заключается в том, что вы можете запрашивать проверку 3 раза в год, поэтому, если прошел 1 год , я сбрасываю счетчик запросов на 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
}