在 iOS 15.6 beta5 和 iOS 16.0 beta 中:
发布 UISceneDidDisconnectNotification 时,任何活动的 SKStoreProductViewController 实例都会因无法识别的名为 sceneDisconnected 的选择器而崩溃。
-[SKStoreProductViewController sceneDisconnected:]: 无法识别的选择器发送到实例 0x115161a00
此崩溃仅发生在最新的iOS15.6和iOS16测试版中。但是我在任何官方文档中都找不到选择器名称……
有什么解决办法吗?或者有什么我没做对的吗?
看起来这已在今天发布的 iOS 15.6 候选版本中修复。
2022 年 9 月 14 日更新: Apple 在官方 15.7 版本中重新引入了此崩溃。它似乎只在应用程序被强制退出时才会发生,因此它不应该影响用户。我已经在 feedbackassistant.apple.com 上向 Apple 提交了一张罚单,并会鼓励其他人也这样做。
不是解决方案,而是明确表明这是 Apple 需要修复的错误。从一个干净的示例项目开始,您需要做的就是提供一个 SKStoreProductViewController,然后强制退出您的应用程序:
import StoreKit
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let storeKitViewController = SKStoreProductViewController()
storeKitViewController.loadProduct(withParameters: [
SKStoreProductParameterITunesItemIdentifier: NSNumber(integerLiteral: 364709193)
])
present(storeKitViewController, animated: true)
// Force quit after presentation to trigger crash
// -[SKStoreProductViewController sceneDisconnected:]: unrecognized selector sent to instance
}
}
我已经通过反馈助手向 Apple 提交了这个。
以下是Apple Framework Engineer的解释
此崩溃发生在 iOS/iPadOS 15.7 的公开版本和种子 4 [1] 之前的 iOS/iPadOS 16 的种子版本中。它不会出现在 iOS 16 的公开发布中。 崩溃主要发生在应用程序处于后台并且即将被操作系统终止时。因此,预计大多数最终用户不会看到这些崩溃。 (一个例外是在 iPad 上有一个支持多场景的应用程序,用户手动终止了一个场景。) 您的分析将显示崩溃率增加,但您的客户不应受到此问题的影响。 我们正在积极努力解决崩溃问题。 [1] 在这种情况下,您应该更新到最新版本。
来源:https://developer.apple.com/forums/thread/714464?answerId=729646022#729646022
能够在本地使用相同的堆栈符号重现崩溃,下面的代码可以阻止崩溃的发生。该代码正在创建空函数来处理无法识别的选择器消息并将此扩展限制为 iOS 15.7:
@available(iOS, introduced: 15.7, obsoleted: 16.0)
@objc extension SKStoreProductViewController {
func sceneDisconnected(_ arg: AnyObject) {}
func appWillTerminate() {}
}
在
application(_:didFinishLaunchingWithOptions:)
中添加此代码(至少在应用程序终止之前)。如果它们不存在,它会在运行时添加方法。
if #available(iOS 15.7, *) {
if #unavailable(iOS 16.0) {
class_addMethod(
SKStoreProductViewController.self,
Selector(("appWillTerminate")),
unsafeBitCast({ _, _ in } as @convention(c) (SKStoreProductViewController, Selector) -> Void, to: IMP.self),
"v@:"
)
class_addMethod(
SKStoreProductViewController.self,
Selector(("sceneDisconnected:")),
unsafeBitCast({ _, _, _ in } as @convention(c) (SKStoreProductViewController, Selector, NSNotification) -> Void, to: IMP.self),
"v@:@"
)
}
}
他们似乎在 iOS 15.7 中删除了
appWillTerminate
和 sceneDisconnected(_:)
方法,但忘记删除将 UIApplication.willTerminateNotification
和 UIScene.didDisconnectNotification
观察者添加到 NotificationCenter 的代码。
编辑:他们似乎在iOS 15.7.1中重新添加了
appWillTerminate
和sceneDisconnected(_:)
方法。所以我更新了代码以仅在 iOS 15.7 中添加方法。
编辑:他们再次删除了 iOS 15.7.2 中的方法,崩溃再次发生。我已经恢复了代码。
这实际上是一个不准确的报告,因为它实际上并没有导致崩溃。
我重现了被举报的场景:点击你应用中的app-download广告,弹出应用内App Store下载页面,然后回到后台,此时产生了crash message -- 但实际上并没有crash发生了,当我回到前台时没有任何改变。一切正常。下次启动应用程序时,会报告崩溃信息。
所以现在什么都不用做,就等苹果修复吧
自版本 15.7.1 发布以来,我们发现 Firebase Crashlytics 的崩溃率有所下降。此外,在过滤 iOS 版本的崩溃时,列表中不存在版本 15.7.1。
这似乎很好地表明苹果终于在 15.7.1 中解决了这个问题。
请分享您对自己的崩溃报告的观察,以验证我的假设是否正确。
Objective C 版本,通过
NSObject
上的类别。 ✌🏻
@interface NSObject (crashPrevent)
@end
@implementation NSObject (crashPrevent)
-(void) sceneDisconnected:(id) item {
return;
}
-(void) appWillTerminate {
return;
}
@end