关于SKStoreReviewController.requestReview()的回调
About the callback of SKStoreReviewController.requestReview()
如果显示从视图控制器启动的审查弹出窗口,由于缺少 window 的回调函数,当弹出窗口被关闭时,无法将 window 焦点切换回视图控制器=11=].
我想在评论弹出窗口关闭时打电话给 becomeFirstResponder()
。有什么想法吗?
有没有办法扩展 SKStoreReviewController 并以某种方式添加回调?
警告这可能会在某个时候中断。
第 1 步:将此代码添加到您的 didFinishLaunchingWithOptions
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let windowClass: AnyClass = UIWindow.self
let originalSelector: Selector = #selector(setter: UIWindow.windowLevel)
let swizzledSelector: Selector = #selector(UIWindow.setWindowLevel_startMonitor(_:))
let originalMethod = class_getInstanceMethod(windowClass, originalSelector)
let swizzledMethod = class_getInstanceMethod(windowClass, swizzledSelector)
let didAddMethod = class_addMethod(windowClass, originalSelector, method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!))
if didAddMethod {
class_replaceMethod(windowClass, swizzledSelector, method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!))
} else {
method_exchangeImplementations(originalMethod!, swizzledMethod!)
}
return true
}
第 2 步:添加这个 class
class MonitorObject: NSObject {
weak var owner: UIWindow?
init(_ owner: UIWindow?) {
super.init()
self.owner = owner
NotificationCenter.default.post(name: UIWindow.didBecomeVisibleNotification, object: self)
}
deinit {
NotificationCenter.default.post(name: UIWindow.didBecomeHiddenNotification, object: self)
}
}
第 3 步:添加此 UIWindow 扩展
private var monitorObjectKey = "monitorKey"
private var partialDescForStoreReviewWindow = "SKStore"
extension UIWindow {
// MARK: - Method Swizzling
@objc func setWindowLevel_startMonitor(_ level: Int) {
setWindowLevel_startMonitor(level)
if description.contains(partialDescForStoreReviewWindow) {
let monObj = MonitorObject(self)
objc_setAssociatedObject(self, &monitorObjectKey, monObj, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
第 4 步:将其添加到控制器的 ViewDidLoad 中您想要的地方
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
NotificationCenter.default.addObserver(self, selector: #selector(windowDidBecomeHiddenNotification(_:)), name: UIWindow.didBecomeHiddenNotification, object: nil)
}
第 5 步:为通知添加回调并检查关联对象是否匹配
@objc func windowDidBecomeHiddenNotification(_ notification: Notification?) {
if notification?.object is MonitorObject {
print("hello")
}
}
现在,当审查对话框关闭时,将触发通知并调用 'print("hello")。
有时 iOS 应用会丢失响应链,如上面显示 StoreKit 提示的示例。我们能做的是检测 UIApplication.sendAction
中的此类事件并通过 becomeFirstResponder
重新激活第一响应者链。 UIKit 将重新建立第一响应者链,我们可以重新发送相同的事件。
class MyApplication: UIApplication {
func reactivateResponderChainWhenFirstResponderEventWasNotHandled() {
becomeFirstResponder()
}
override func sendAction(_ action: Selector, to target: Any?, from sender: Any?, for event: UIEvent?) -> Bool {
let wasHandled = super.sendAction(action, to: target, from: sender, for: event)
if wasHandled == false, target == nil {
reactivateResponderChainWhenFirstResponderEventWasNotHandled()
return super.sendAction(action, to: target, from: sender, for: event)
}
return wasHandled
}
}
这对我来说适用于 iOS 13,不需要任何私人 API 访问权限。
如果显示从视图控制器启动的审查弹出窗口,由于缺少 window 的回调函数,当弹出窗口被关闭时,无法将 window 焦点切换回视图控制器=11=].
我想在评论弹出窗口关闭时打电话给 becomeFirstResponder()
。有什么想法吗?
有没有办法扩展 SKStoreReviewController 并以某种方式添加回调?
警告这可能会在某个时候中断。
第 1 步:将此代码添加到您的 didFinishLaunchingWithOptions
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let windowClass: AnyClass = UIWindow.self
let originalSelector: Selector = #selector(setter: UIWindow.windowLevel)
let swizzledSelector: Selector = #selector(UIWindow.setWindowLevel_startMonitor(_:))
let originalMethod = class_getInstanceMethod(windowClass, originalSelector)
let swizzledMethod = class_getInstanceMethod(windowClass, swizzledSelector)
let didAddMethod = class_addMethod(windowClass, originalSelector, method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!))
if didAddMethod {
class_replaceMethod(windowClass, swizzledSelector, method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!))
} else {
method_exchangeImplementations(originalMethod!, swizzledMethod!)
}
return true
}
第 2 步:添加这个 class
class MonitorObject: NSObject {
weak var owner: UIWindow?
init(_ owner: UIWindow?) {
super.init()
self.owner = owner
NotificationCenter.default.post(name: UIWindow.didBecomeVisibleNotification, object: self)
}
deinit {
NotificationCenter.default.post(name: UIWindow.didBecomeHiddenNotification, object: self)
}
}
第 3 步:添加此 UIWindow 扩展
private var monitorObjectKey = "monitorKey"
private var partialDescForStoreReviewWindow = "SKStore"
extension UIWindow {
// MARK: - Method Swizzling
@objc func setWindowLevel_startMonitor(_ level: Int) {
setWindowLevel_startMonitor(level)
if description.contains(partialDescForStoreReviewWindow) {
let monObj = MonitorObject(self)
objc_setAssociatedObject(self, &monitorObjectKey, monObj, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
第 4 步:将其添加到控制器的 ViewDidLoad 中您想要的地方
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
NotificationCenter.default.addObserver(self, selector: #selector(windowDidBecomeHiddenNotification(_:)), name: UIWindow.didBecomeHiddenNotification, object: nil)
}
第 5 步:为通知添加回调并检查关联对象是否匹配
@objc func windowDidBecomeHiddenNotification(_ notification: Notification?) {
if notification?.object is MonitorObject {
print("hello")
}
}
现在,当审查对话框关闭时,将触发通知并调用 'print("hello")。
有时 iOS 应用会丢失响应链,如上面显示 StoreKit 提示的示例。我们能做的是检测 UIApplication.sendAction
中的此类事件并通过 becomeFirstResponder
重新激活第一响应者链。 UIKit 将重新建立第一响应者链,我们可以重新发送相同的事件。
class MyApplication: UIApplication {
func reactivateResponderChainWhenFirstResponderEventWasNotHandled() {
becomeFirstResponder()
}
override func sendAction(_ action: Selector, to target: Any?, from sender: Any?, for event: UIEvent?) -> Bool {
let wasHandled = super.sendAction(action, to: target, from: sender, for: event)
if wasHandled == false, target == nil {
reactivateResponderChainWhenFirstResponderEventWasNotHandled()
return super.sendAction(action, to: target, from: sender, for: event)
}
return wasHandled
}
}
这对我来说适用于 iOS 13,不需要任何私人 API 访问权限。