我在一个应用程序中设置了一个 IAP,还有一些 Cocoapods:
- Firebase/AdMob (4.8.0):
- Firebase/Core
- Google-Mobile-Ads-SDK (= 7.27.0)
- Firebase/Core (4.8.0):
- FirebaseAnalytics (= 4.0.5)
- FirebaseCore (= 4.0.13)
- Firebase/Crash (4.8.0):
- Firebase/Core
- FirebaseCrash (= 2.0.2)
- FirebaseAnalytics (4.0.5):
- FirebaseCore (~> 4.0)
- FirebaseInstanceID (~> 2.0)
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- nanopb (~> 0.3)
- FirebaseCore (4.0.13):
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- FirebaseCrash (2.0.2):
- FirebaseAnalytics (~> 4.0)
- FirebaseInstanceID (~> 2.0)
- GoogleToolboxForMac/Logger (~> 2.1)
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- Protobuf (~> 3.1)
IAP 和上述所有框架都运行完美!完全没有问题。
一旦我进行了 pod 更新,事情就开始变糟了。
pod 更新后,更新后的版本如下:
pod :
- Firebase/AdMob (4.10.1):
- Firebase/Core
- Google-Mobile-Ads-SDK (= 7.29.0)
- Firebase/Core (4.10.1):
- FirebaseAnalytics (= 4.1.0)
- FirebaseCore (= 4.0.17)
- Firebase/Crash (4.10.1):
- Firebase/Core
- FirebaseCrash (= 2.0.2)
- FirebaseAnalytics (4.1.0):
- FirebaseCore (~> 4.0)
- FirebaseInstanceID (~> 2.0)
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- nanopb (~> 0.3)
- FirebaseCore (4.0.17):
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- FirebaseCrash (2.0.2):
- FirebaseAnalytics (~> 4.0)
- FirebaseInstanceID (~> 2.0)
- GoogleToolboxForMac/Logger (~> 2.1)
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- Protobuf (~> 3.1)
此 pod 更新后 - 我的 IAP 在 100% 的时间内因成功购买而崩溃。代码绝对没有任何变化。只是对上面列出的最新框架的 pod 更新。
一旦 IAP 完成(并弹出“您已准备就绪!”成功警报),我会遇到以下崩溃:
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
libsystem_kernel.dylib`__pthread_kill:
0x1859bc2e0 <+0>: mov x16, #0x148
0x1859bc2e4 <+4>: svc #0x80
-> 0x1859bc2e8 <+8>: b.lo 0x1859bc300 ; <+32>
0x1859bc2ec <+12>: stp x29, x30, [sp, #-0x10]!
0x1859bc2f0 <+16>: mov x29, sp
0x1859bc2f4 <+20>: bl 0x18599cbdc ; cerror_nocancel
0x1859bc2f8 <+24>: mov sp, x29
0x1859bc2fc <+28>: ldp x29, x30, [sp], #0x10
0x1859bc300 <+32>: ret
这是调试面板的屏幕截图:/image/exmsO.png
[![Debug panel][1]][1]
这是 Firebase 崩溃报告记录的内容:
-[__NSCFBoolean timeIntervalSince1970]: unrecognized selector sent to instance 0x1b6f8a878
一些注意事项:
- 代码没有任何变化。
- Cocoapods 已在终端中更新。步骤:1. CD 到目录,2. $ pod update
- 我在更新 Cocoapods 之前测试了 IAP - 一切正常;应用没有崩溃。
- 我在 Cocoapod 更新后测试 IAP 之前清理了一个项目。
- 在多个设备上崩溃 -(iOS 11.2.6 和 11.2.1)。
由于我只更新了 pod,导致此崩溃的原因是什么?
赏金更新:
我已经为这个问题添加了赏金,因为我现在正在其他项目中体验它。我有一个旧项目,我想更新 Pod(Firebase/Firebase Crash/Google Ads)。以下是我采取的具体步骤:
- CD 到项目目录。
- Pod 更新。 Cocoapods 根本没有给我任何错误。
在 Xcode 中,我运行了我更新了 Podfile 的项目...我购买了一个 IAP,它在完成后立即崩溃。同样,这不会在 pod 文件更新之前发生!在我运行 pod update 之前,IAP 工作正常。
对于新冒犯的损坏项目,我删除了 Podfile、Podfile.lock 和 Pods 目录。我从一个旧项目中拖入了相同的文件和目录。完美运行,没有任何崩溃。
此问题仅在 pod 更新后仍然存在。我迷路了..
IAP 帮助文件
import StoreKit
import Firebase
public typealias MYProductIdentifier = String
public typealias MYProductRequestCompletionHandler = (_ success: Bool, _ products: [SKProduct]?) -> ()
// MARK: - Class
public class IAPHelper: NSObject {
// Define properties!
fileprivate let myProductIdentifiers: Set<MYProductIdentifier>
fileprivate var myPurchasedProductIdentifiers = Set<MYProductIdentifier>()
// Optional properties
fileprivate var myProductsRequest: SKProductsRequest?
fileprivate var myProductsRequestCompletionHandler: MYProductRequestCompletionHandler?
// NOTIFICATION
static let IAPTransactionInProgress = "IAPTransactionInProgress"
static let IAPTransactionFailed = "IAPTransactionFailed"
static let myIAPHelperPurchaseNotification = "IAPHelperPurchaseNotification" // Whenever a purchase takes place!
static let myRestorePurchaseNotification = "myRestorePurchaseNotification" // Whenever a restore takes place!
static let myPurchaseMadeThankYou = "myPurchaseMadeThankYou" // Whenever a first purchase takes place!
// init!
public init(productIDs: Set<MYProductIdentifier>) {
myProductIdentifiers = productIDs
// CHECK IF USER ALREADY BOUGHT! (to set the correct Defaults)
for productIdentifier in productIDs {
let purchased = MYConstants.nsDefaults.bool(forKey: productIdentifier)
if purchased {
myPurchasedProductIdentifiers.insert(productIdentifier)
print("Already purchased! \(productIdentifier)")
}
else {
print("Not yet purchased! \(productIdentifier)")
}
}
super.init()
SKPaymentQueue.default().add(self)
}
public func requestProducts(completionHandler: @escaping MYProductRequestCompletionHandler) {
myProductsRequest?.cancel()
myProductsRequestCompletionHandler = completionHandler
myProductsRequest = SKProductsRequest(productIdentifiers: myProductIdentifiers)
myProductsRequest?.delegate = self
myProductsRequest?.start()
}
public func buyProduct(product: SKProduct) {
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
}
public func isProductPurchased(productIdentifier: MYProductIdentifier) -> Bool {
return myPurchasedProductIdentifiers.contains(productIdentifier)
}
public class func canMakePayment() -> Bool {
return SKPaymentQueue.canMakePayments()
}
public func restorePurchases() {
SKPaymentQueue.default().restoreCompletedTransactions()
}
}
// MARK: - SKProductRequestsDelegate
extension IAPHelper: SKProductsRequestDelegate {
public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
let products = response.products
myProductsRequestCompletionHandler?(true, products)
reset()
}
public func request(_ request: SKRequest, didFailWithError error: Error) {
// Called wheneever there is an ERROR or NO PRODUCTS!
myProductsRequestCompletionHandler?(false, nil)
reset()
print("ERROR \(error.localizedDescription)")
}
private func reset() {
myProductsRequest = nil
myProductsRequestCompletionHandler = nil
}
}
// MARK: - SKPaymentTransactionObserver
extension IAPHelper: SKPaymentTransactionObserver {
// Tells us if the payment from the user was successful. Then react accordingly!
public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
// Check outstanding transactions and react to them.
for transaction in transactions {
// check what kind of transaction is happening!
switch transaction.transactionState {
case .purchased :
completeTransaction(transaction: transaction)
case .failed :
failedTransaction(transaction: transaction)
case .restored :
restoreTransaction(transaction: transaction)
case .deferred :
showTransactionAsInProgress(deferred: true)
case .purchasing :
showTransactionAsInProgress(deferred: false)
}
}
}
//MARK: Payment transaction related methods
private func showTransactionAsInProgress(deferred: Bool) {
NotificationCenter.default.post(name: Notification.Name(IAPHelper.IAPTransactionInProgress), object: deferred)
}
private func completeTransaction(transaction: SKPaymentTransaction) {
postPurchaseNotificationForIdentifier(identifier: transaction.payment.productIdentifier)
NotificationCenter.default.post(name: NSNotification.Name(IAPHelper.myPurchaseMadeThankYou), object: nil)
SKPaymentQueue.default().finishTransaction(transaction)
}
private func failedTransaction(transaction: SKPaymentTransaction) {
// User aborts payment!!
if transaction.error!._code != SKError.Code.paymentCancelled.rawValue {
print("Error: \(transaction.error!.localizedDescription)")
}
NotificationCenter.default.post(name: Notification.Name(IAPHelper.IAPTransactionFailed), object: transaction.error)
SKPaymentQueue.default().finishTransaction(transaction)
}
private func restoreTransaction(transaction: SKPaymentTransaction) {
guard let productIdentifier = transaction.original?.payment.productIdentifier else {
return
}
postRestoreNotificationForIdentifier(identifier: productIdentifier)
SKPaymentQueue.default().finishTransaction(transaction)
}
private func postPurchaseNotificationForIdentifier(identifier: String?) {
// TELL VC THAT PURCHASE WAS OR WAS NOT success.
guard let identifier = identifier else {
return
}
Analytics.logEvent("IAP_Purchase_Made", parameters: nil)
// I believe it crashes right here.
// NEW ==================================
myPurchasedProductIdentifiers.insert(identifier)
MYConstants.nsDefaults.set(true, forKey: identifier)
MYConstants.unlockLogic(restoring: false)
NotificationCenter.default.post(name: Notification.Name(IAPHelper.myIAPHelperPurchaseNotification), object: identifier)
// END NEW ==============================
}
private func postRestoreNotificationForIdentifier(identifier: String?) {
// TELL VC THAT PURCHASE WAS OR WAS NOT success.
guard let identifier = identifier else {
return
}
Analytics.logEvent("IAP_Restore_Made", parameters: nil)
// NEW ==================================
myPurchasedProductIdentifiers.insert(identifier)
MYConstants.nsDefaults.set(true, forKey: identifier)
print("NEW RESTORE Identifier: \(identifier)")
MYConstants.unlockLogic(restoring: true)
NotificationCenter.default.post(name: NSNotification.Name(IAPHelper.myRestorePurchaseNotification), object: nil)
// END NEW ==============================
}
}
最佳答案
要找到调用 TimeInterval 的位置,我会为 Bool 添加一个公共(public)扩展,这样您就可以向它添加一个断点并进行相应的修改。
像这样:
public extension Bool {
public var timeIntervalSince1970:TimeInterval {
get {
// Add breakpoint here
return 0
}
}
}
更新:
我没能认出你的崩溃提到了 NSCFBoolean 而不是 Bool。 据我了解,NSCFBoolean 是桥接 CFBoolean 的私有(private)类,因此您不能扩展它,但也许它可以通过扩展 CFBoolean 来工作。有关 NSCFBoolean 的更多信息:https://nshipster.com/bool/
请尝试添加此扩展和断点:
public extension CFBoolean {
var timeIntervalSince1970: TimeInterval {
get {
// Add breakpoint here
return 0
}
}
}
关于ios - 应用程序在 IAP 后崩溃 - 仅在 podfiles 更新后,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49325501/