Zip
Zip copied to clipboard
What's the connection between Zip and StoreKit?
I meet a problem really wired, the Zip module effects the In-App purchase, I don't know why. The problem is like this:
- At first, everything goes fine, both Zip function and Purchase function;
- Next morning, Zip suddenly not available. Xcode said: "Can't find module minizip" (something like this, maybe not exactly the same);
- I drag unzip.h into the framework folder of the project, it works fine;
- Next morning, the In-App purchase not working. As went to "SKPaymentQueue.default().add(SKPayment)", it crashed and said "EXC_BAD_ACCESS, code =1 etc.";
- I tried a lot to find the bug, at last I found something really wired. As I print object IAP product list, the output said:
"warning: Swift error in module Zip. Debug info from this module will be unavailable in the debugger."
- I just delete the unzip.h from project, everything is fine, again;
- Next morning, this problem occurred again. Whatever I do, it always crash when IAP triggered, and show this message:"warning: Swift error in module Zip." even I remove Zip framework!
My question is, why Zip module related StorKit module? Why these problems seems occurred randomly? Please help me, thank you!
Thanks @lvcloudgit, that's one strange issue. Zip doesn't have anything to do with StoreKit.
Can you share some code so I can investigate your issue further?
@marmelroy Thanks for your reply!
My code is a bit chaos and I don't know which part should be posted... But I found another possibility, still it's not work every time, but maybe it shows some tips?
The Build Settings of TARGETS has an Option "Always Embed Swift Standard Libraries", the value is "No" by default. I change it to "Yes", the error just disappeared!
But still... It's really bothered me, next morning, the error happened again! And I just change this option back to "No", the error disappeared!
So right now, seems the solution is just switch this option... would you take a guess where the problem could be?
This is the IAPHelper.swift code:
import Foundation
import StoreKit
public typealias bookId = String
public typealias BooksRequestCompleteHandler = (_ success: Bool, _ books:[SKProduct]?) -> ()
open class IAPHelper: NSObject {
static let IAPHelperPurchaseNotification = "IAPHelperPurchaseNotification"
var books: Set<bookId>
fileprivate var purchasedBookIds:Set<bookId> = Set()
var aRequest:SKProductsRequest?
var booksRequestFinishedHandler: BooksRequestCompleteHandler?
init(bookIds: Set<bookId>) {
books = bookIds
for id in bookIds {
let purchased = UserDefaults.standard.bool(forKey: id)
if purchased {
purchasedBookIds.insert(id)
} else {
}
}
super.init()
SKPaymentQueue.default().add(self)
}
}
// MARK: StoreKit API
extension IAPHelper {
public func requestProducts(_ completionHandler: @escaping BooksRequestCompleteHandler) {
aRequest?.cancel()
booksRequestFinishedHandler = completionHandler
aRequest = SKProductsRequest(productIdentifiers: books)
aRequest!.delegate = self
aRequest!.start()
}
public func buyProduct(_ product: SKProduct) {
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
}
public func isProductPurchased(_ productIdentifier: bookId) -> Bool {
return purchasedBookIds.contains(productIdentifier)
}
public class func canMakePayments() -> Bool {
return SKPaymentQueue.canMakePayments()
}
public func restorePurchases() {
SKPaymentQueue.default().restoreCompletedTransactions()
}
}
// MARK: SKProductsRequestDelegate
extension IAPHelper: SKProductsRequestDelegate {
public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
let booksGet = response.products
booksRequestFinishedHandler?(true, booksGet)
clearRequestANdHandler()
public func request(_ request: SKRequest, didFailWithError error: Error) {
booksRequestFinishedHandler?(false, nil)
clearRequestANdHandler()
}
public func clearRequestANdHandler() {
aRequest = nil
booksRequestFinishedHandler = nil
}
}
// MARK: SKPaymentTransactionObserver
extension IAPHelper: SKPaymentTransactionObserver {
public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch (transaction.transactionState) {
case .purchased:
completeTransaction(transaction)
break
case .failed:
failedTransaction(transaction)
break
case .restored:
restoreTransaction(transaction)
break
case .deferred:
break
case .purchasing:
break
}
}
}
fileprivate func completeTransaction(_ transaction: SKPaymentTransaction) {
UserDefaults.standard.set(true, forKey: transaction.payment.productIdentifier)
deliverPurchaseNotificatioForIdentifier(transaction.payment.productIdentifier)
SKPaymentQueue.default().finishTransaction(transaction)
}
fileprivate func restoreTransaction(_ transaction: SKPaymentTransaction) {
guard let productIdentifier = transaction.original?.payment.productIdentifier else { return }
deliverPurchaseNotificatioForIdentifier(productIdentifier)
SKPaymentQueue.default().finishTransaction(transaction)
}
fileprivate func failedTransaction(_ transaction: SKPaymentTransaction) {
if transaction.error!._code != SKError.paymentCancelled.rawValue {
print("Transaction Error: \(transaction.error?.localizedDescription)")
}
SKPaymentQueue.default().finishTransaction(transaction)
}
fileprivate func deliverPurchaseNotificatioForIdentifier(_ identifier: String?) {
guard let identifier = identifier else { return }
purchasedBookIds.insert(identifier)
UserDefaults.standard.set(true, forKey: identifier)
UserDefaults.standard.synchronize()
NotificationCenter.default.post(name: Notification.Name(rawValue: IAPHelper.IAPHelperPurchaseNotification), object: identifier)
}
}
/// get productIdentifiers
class PurchaseBooks {
var bookListArray:[String] {
didSet {
self.bookIds = Set(bookListArray)
self.store = IAPHelper(bookIds: self.bookIds)
}
}
var bookIds:Set<bookId> = []
var store:IAPHelper?
init() {
bookListArray = bookListData?.allKeys as! [String]
bookListArray = []
bookIds = Set(bookListArray)
store = IAPHelper(bookIds: self.bookIds)
}
}
var bookPurchase = PurchaseBooks()
** This is the
The part of Unzip:
func resetDefaultBookOffline() {
let defaultZip = Bundle.main.path(forResource: "defaultResource", ofType: "zip")
let booklistFile = "\(documentPath)/BookList.plist"
let fileMgr = FileManager.default
if fileMgr.fileExists(atPath: booklistFile) == false {
do {
try _ = Zip.unzipFile(URL(string: defaultZip!)!, destination: URL(string:documentPath)!, overwrite: false, password: nil, progress: {
(progress: Double) -> () in
// print("Unzip progress: \(progress)\n")
})
try? fileMgr.removeItem(atPath: documentPath + "/__MACOSX")
try? fileMgr.removeItem(atPath: documentPath + "/default.zip")
print("Unzip complete, path:\(documentPath)")
} catch let error {
print("Unzip error:\(error.localizedDescription)")
}
}
}
I'm sorry, it still can't work well. The error is:
It's not always happened, but sometimes. What's this mean? Why is that? Sometimes it just happened in running Profile mode.
I just use unzip once all over the project, as the code I just posted, pretty simple. I think it's not caused by any specific code, maybe it caused by some build settings options?