在 Swift 应用中,SKStoreReviewController 提供了 requestReview(in:) 方法,用于在 App 内部请求用户为应用评分。此功能通常在特定的用户行为或使用场景下触发。例如,在完成订单、解锁成就或达到特定使用时间后请求用户进行评分。
特殊环境键 requestReview
在 SwiftUI 中,可以通过 Environment(\.requestReview) 来访问 requestReview 环境键。该键与 SKStoreReviewController.requestReview(in:) 方法相连,使得在 SwiftUI 的视图中也能轻松触发评分请求。
使用方法
1、确保项目已导入 StoreKit 框架。
import StoreKit
2、在 SwiftUI 视图中使用 Environment(\.requestReview) 键。
@Environment(\.requestReview) var requestReview
3、通过按钮调取requestReview
Button("Leave a review") {
requestReview()
}
代码示例
import SwiftUI
import StoreKit
struct ContentView: View {
@Environment(\.requestReview) private var requestReview // 引入 requestReview 环境键
var body: some View {
VStack {
Text("Welcome to our app!")
.font(.title)
.padding()
Button("Rate Our App") {
// 触发评分请求
requestReview()
}
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(8)
}
}
}
#Preview {
ContentView()
}
功能说明
1、@Environment(\.requestReview):
将评分请求的触发方法绑定到视图环境。
按需调用 requestReview() 即可触发评分弹窗。
2、限制:
苹果对评分弹窗的频率有严格限制。调用 requestReview() 不一定会每次显示评分弹窗。
苹果会根据用户行为和应用历史评分决定是否显示。
3、用户体验:
应避免频繁调用评分弹窗。最佳实践是根据特定的用户交互,例如完成某项任务后,调用评分请求。
注意事项
调用频率限制:苹果强烈建议只在适当时机调用 requestReview(),并保证不会打扰用户。
测试时的行为:在开发环境中,requestReview() 不会每次都显示评分弹窗。可以在 TestFlight 或实际发布后测试。
替代方法:如果需要更灵活的评分策略,可以通过跳转到 App Store 的页面完成评分:
if let url = URL(string: "itms-apps://itunes.apple.com/app/id<YOUR_APP_ID>?action=write-review") {
UIApplication.shared.open(url)
}
代码示例:
Button("Rate Our App") {
// 触发评分请求
if let url = URL(string: "itms-apps://itunes.apple.com/app/id6503047096?action=write-review") {
UIApplication.shared.open(url)
}
}
通过将评分请求嵌入到用户操作的自然流中,可以提升用户参与感,同时不会打扰他们的体验。
运行在主线程
@Environment(\.requestReview) 是一个与主线程(主Actor)关联的环境值。在实际应用中,调用 requestReview() 时,它需要在主线程上执行。
如果调用的方法并没有被标记为运行在主线程(主Actor)上,编译器会提示该调用是从非主线程上下文发出的。
例如:
func setFilter(_ filter: CIFilter) {
currentFilter = filter
loadImage()
filterCount += 1
if filterCount >= 5 {
requestReview() // 报错
}
}
在上面的方法中,因为该方法没有运行在主线程上,Xcode会报错:
Call to main actor-isolated instance method 'callAsFunction()' in a synchronous nonisolated context
解决方案
为了确保 requestReview() 在主线程上运行,可以将 setFilter 方法标记为在主Actor上运行,方法是使用 @MainActor 属性修饰。
@MainActor
func setFilter(_ filter: CIFilter) {
currentFilter = filter
loadImage()
filterCount += 1
if filterCount >= 20 {
requestReview()
}
}
1、@MainActor 的作用:
主Actor是用来保证UI更新和与系统UI相关的操作(如请求评论窗口、动画、导航等)在主线程上执行的。
标记方法为 @MainActor 会告诉Swift运行时,确保此方法的调用在主线程上进行。
2、为什么需要主线程?
requestReview() 是与UI交互相关的操作,必须在主线程上调用。
Swift 通过静态检查保证这种调用的安全性,因此给出了这个错误提示。
3、添加 @MainActor 的影响:
修饰了 setFilter 方法后,所有调用它的代码都会自动切换到主线程,即使它们原本可能运行在后台线程。