Ios 应用程序在IAP后崩溃-仅在更新POD文件后
我在一个应用程序中设置了IAP,还有一些CoCoapod:Ios 应用程序在IAP后崩溃-仅在更新POD文件后,ios,xcode,firebase,cocoapods,Ios,Xcode,Firebase,Cocoapods,我在一个应用程序中设置了IAP,还有一些CoCoapod: - 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
- 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更新之后-我的IAP在成功购买时100%崩溃。代码完全没有改变。只是上面列出的最新框架的pod更新
一旦IAP完成(并弹出“您都准备好了!”成功警报),我将遇到以下崩溃:
以下是Firebase崩溃报告记录的内容:
-[__NSCFBoolean timeIntervalSince1970]: unrecognized selector sent to instance 0x1b6f8a878
需要注意的一些事项:
- 代码中没有任何更改
- Cocoapod在终端中更新。步骤:1。CD到目录,2美元吊舱更新
- 在更新Cocoapods之前,我测试了IAP——一切工作都完美无缺;应用程序没有崩溃
- 在Cocoapod更新后测试IAP之前,我做了一个项目清理
- 在多个设备上崩溃-(iOS 11.2.6和11.2.1)
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 ==============================
}
}
导入存储套件
进口火基
公共类型别名MYProductIdentifier=字符串
公共类型别名MYProductRequestCompletionHandler=(\uSuccess:Bool,\uProducts:[SKProduct]?)->()
//马克:班级
公共类IAPHelper:NSObject{
//定义属性!
fileprivate让myProductIdentifiers:设置
fileprivate var myPurchasedProductIdentifiers=Set()
//可选属性
fileprivate var myProductsRequest:SKProductsRequest?
fileprivate变量myProductsRequestCompletionHandler:MYProductRequestCompletionHandler?
//通知
静态let IAPTransactionInProgress=“IAPTransactionInProgress”
静态let IAPTransactionFailed=“IAPTransactionFailed”
每次购买时,静态让myIAPHelperPurchaseNotification=“IAPHelperPurchaseNotification”/!
静态让myRestorePurchaseNotification=“myRestorePurchaseNotification”/!
静态让myPurchaseMadeThankYou=“myPurchaseMadeThankYou”//无论何时首次购买!
//初始化!
公共初始化(productid:Set){
myProductIdentifiers=ProductID
//检查用户是否已购买!(设置正确的默认值)
对于ProductID中的productIdentifier{
let purchased=MYConstants.nsDefaults.bool(forKey:productIdentifier)
如果购买{
MyPurchasedProductIdentifier.insert(productIdentifier)
打印(“已购买!\(productIdentifier)”)
}
否则{
打印(“尚未购买!\(productIdentifier)”)
}
}
super.init()
SKPaymentQueue.default().add(self)
}
public func requestProducts(completionHandler:@escaping MYProductRequestCompletionHandler){
myProductsRequest?.cancel()
myProductsRequestCompletionHandler=completionHandler
myProductsRequest=SKProductsRequest(产品标识符:myProductIdentifiers)
myProductsRequest?.delegate=self
myProductsRequest?.start()
}
公共func buyProduct(产品:SKProduct){
let payment=SKPayment(产品:产品)
SKPaymentQueue.default().add(付款)
}
公共函数isProductPurchased(productIdentifier:MYProductIdentifier)->Bool{
返回MyPurchasedProductIdentifier.contains(productIdentifier)
}
公共类func canMakePayment()->Bool{
返回SKPaymentQueue.canMakePayments()
}
公共职能恢复采购(){
SKPaymentQueue.default().restoreCompletedTransactions()
}
}
//标记:-SKProductRequestsDelegate
扩展IAPHelper:SKProductsRequestDelegate{
public func productsRequest(u请求:SKProductsRequest,didReceive响应:SKProductsResponse){
让产品=响应.products
myProductsRequestCompletionHandler?(true,产品)
重置()
}
公共函数请求(请求:SKRequest,错误:error){
//无论何时出现错误或没有产品,都会调用!
myProductsRequestCompletionHandler?(false,nil)
重置()
打印(“错误\(ERROR.localizedDescription)”)
}
私有函数重置(){
myProductsRequest=nil
myProductsRequestCompletionHandler=nil
}
}
//MARK:-SKPaymentTransactionObserver
扩展IAPHelper:SKPaymentTransactionObserver{
//告诉我们用户付款是否成功。然后做出相应的反应!
public func paymentQueue(queue:SKPaymentQueue,updatedTransactions事务:[SKPaymentTransaction]){
//检查未完成的交易并对其作出反应。
交易中的交易{
//检查正在发生的交易类型!
切换事务.transactionState{
案例。购买:
completeTransaction(事务:事务)
[![Debug panel][1]][1]
-[__NSCFBoolean timeIntervalSince1970]: unrecognized selector sent to instance 0x1b6f8a878
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 ==============================
}
}
public extension Bool {
public var timeIntervalSince1970:TimeInterval {
get {
// Add breakpoint here
return 0
}
}
}
public extension CFBoolean {
var timeIntervalSince1970: TimeInterval {
get {
// Add breakpoint here
return 0
}
}
}
#define kTipPurchasedIAPProductIdKey @"tipAdditional99Cents"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
if (YES) {
//Firebase initialization
[FIRApp configure];
[[FIRConfiguration sharedInstance] setLoggerLevel:FIRLoggerLevelMin];
}
//Register user defaults
[[NSUserDefaults standardUserDefaults] registerDefaults:@{
kTipPurchasedIAPProductIdKey: @NO
}];
}