App is crashing after an IAP - only after podfiles were updated


App is crashing after an IAP - only after podfiles were updated



I have an IAP setup in an app, along with a few 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 and all of the above frameworks are working perfect! No problems at all.



Once I do a pod update, things start to go south.



After a pod update, here are the updated versions:



PODS:


- 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)



After this pod update - my IAP crashes on a successful purchase 100% of the time. Absolutely nothing changed in code. Just a pod update to the newest frameworks listed above.



I am getting the following crash once the IAP completes (and the "You're all set!" success alert pops up):


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



Here is a screenshot of the debug panel: https://i.stack.imgur.com/exmsO.png


[![Debug panel][1]][1]



Here is what Firebase crash reporting is logging:


-[__NSCFBoolean timeIntervalSince1970]: unrecognized selector sent to instance 0x1b6f8a878



Some items to note:



What is causing this crash since I only updated pods?



Bounty update:



I have added a Bounty to this question because I am now experiencing it on other projects. I had an old project that i wanted to update the Pods (Firebase / Firebase Crash / Google Ads). Here are the exact steps I took:



Within Xcode, I run the project whose Podfile I updated... I go through purchasing an IAP and it crashes as soon as it's complete. Again, this does not happen before the pod file was updated! The IAP works fine until I run pod update.



With the newly offended broken project, I removed Podfile, Podfile.lock, and Pods directory. I dragged the same files and directory in from an older project. Works perfect without any crashing.



This problem is persisting ONLY after pod update. I'm lost..



IAP Helper file


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 ==============================

}



}





you may changed a firebase key (remoteConfigs) from date to bool , check that
– Sh_Khan
Mar 16 at 16:33





@Sh_Khan - I have not. Once the IAP completes, a userdefault gets changed. But that configuration worked perfect before the pod update. Before the update, I tested on multiple devices with successful results each time. Crash is happening only after doing a pod update (and nothing else was changed).
– Joe
Mar 16 at 16:42





Can you share your code ?
– GIJOW
Mar 16 at 16:45





@GIJOW - I could.. however it would take some time to obfuscate personal/sensitive information. Is there a particular section that you'd want to analyze? (example - the IAPHelper file). I didn't think I would need to post any code - because everything works flawless with the original pod file versions i posted - which leads me to believe this is a cocoapods or firebase conflict.
– Joe
Mar 16 at 17:03






@Joe can you please share IAP file
– MAhipal Singh
Jul 3 at 6:24




2 Answers
2



To find where is this call for the TimeInterval being made I would add a public extension for Bool so you can add a breakpoint to it and modify accordingly.



Something like this:


public extension Bool {
public var timeIntervalSince1970:TimeInterval {
get {
// Add breakpoint here
return 0
}
}
}



I've temporarily fixed this issue by going back to the pod versions before I ran the update.



Here are the exact steps I took:


pod install


pod deintegrate


Podfile.lock


Workspace



I re-opened the Podfile, uncommented out the 3 pods, and then explicitly specified the dependency versions that I used before the pod update that was causing the crash. See below:



pod 'Firebase/Core', '4.8.0'



pod 'Google-Mobile-Ads-SDK', '7.27.0'



pod 'Firebase/Crash', '4.8.0'



The project works as intended now. The App completes the IAP with no exceptions.



Why is this occurring? I am led to believe it's NOT a code issue, because this issue only occurs when I update my pods.






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

api-platform.com Unable to generate an IRI for the item of type

How to set up datasource with Spring for HikariCP?

PHP contact form sending but not receiving emails