ios - 应用程序在 IAP 后崩溃 - 仅在 podfiles 更新后

标签 ios xcode firebase cocoapods

我在一个应用程序中设置了一个 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)。以下是我采取的具体步骤:

  1. CD 到项目目录。
  2. 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/

相关文章:

ios - text becomeFirstResponder 抛出 EXC_BAD_ACCESS Code=1 Address=0x1

ios - Xcode 8.2 更新后无效的二进制文件

ios - XCode 使用不存在的 sqlite 数据库

ios - 自动布局以编程方式修改约束乘数

ios - Objective c 中的自动滚动 Uicollectionview

ios - 如何添加条件以区分虚线和实心正方形?

xcode - 部署目标冲突,环境中同时存在 'MACOSX_DEPLOYMENT_TARGET' 和 'IPHONEOS_DEPLOYMENT_TARGET'

javascript - Firebase:在 cookie 中存储匿名身份验证

javascript - 大型 firebase 函数请求似乎会导致连接错误

node.js - 为什么 Firebase 云数据库触发器无法提供用户信息?