Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/99.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 应用程序中的应用程序内购买_Ios_Swift - Fatal编程技术网

Ios 应用程序中的应用程序内购买

Ios 应用程序中的应用程序内购买,ios,swift,Ios,Swift,我在应用程序中有几个应用程序内购买。我使用以下代码: @IBAction func purchaseFull(_ sender: Any) { purchase = "purchaseFull" product_id = "purchaseFull" print("About to fetch the product...") //self.loading.startAnimating() SKPaymen

我在应用程序中有几个应用程序内购买。我使用以下代码:

@IBAction func purchaseFull(_ sender: Any) {  

        purchase = "purchaseFull"

        product_id = "purchaseFull"

        print("About to fetch the product...")
        //self.loading.startAnimating()
        SKPaymentQueue.default().add(self)
        // Can make payments
        if (SKPaymentQueue.canMakePayments())
        {
            let productID:NSSet = NSSet(object: self.product_id!);
            let productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>);
            productsRequest.delegate = self;
            productsRequest.start();
            print("Fetching Products");
        }else{
            print("Can't make purchases");
        }
    }

@IBAction func purchase(_ sender: Any) {

        purchase = "purchase"

        product_id = "purchase\(index)"

        print("About to fetch the product...")
        //self.loading.startAnimating()
        SKPaymentQueue.default().add(self)
        // Can make payments
        if (SKPaymentQueue.canMakePayments())
        {
            let productID:NSSet = NSSet(object: self.product_id!);
            let productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>);
            productsRequest.delegate = self;
            productsRequest.start();
            print("Fetching Products");
        }else{
            print("Can't make purchases");
        }
    }

func productsRequest (_ request: SKProductsRequest, didReceive response: SKProductsResponse) {

        let count : Int = response.products.count
        if (count>0) {
            let validProduct: SKProduct = response.products[0] as SKProduct
            if (validProduct.productIdentifier == self.product_id) {
                print(validProduct.localizedTitle)
                print(validProduct.localizedDescription)
                print(validProduct.price)
                buyProduct(product: validProduct);

            } else {
                print(validProduct.productIdentifier)
            }
        } else {
            print("nothing")
        }
    }

    func buyProduct(product: SKProduct){
        print("Sending the Payment Request to Apple");
        let payment = SKPayment(product: product)
        SKPaymentQueue.default().add(payment);
        //self.loading.stopAnimating()
    }

    func request(_ request: SKRequest, didFailWithError error: Error) {
        print("Error Fetching product information");
        //self.loading.stopAnimating()
    }

    func paymentQueue(_ queue: SKPaymentQueue,
                      updatedTransactions transactions: [SKPaymentTransaction]) {
        print("Received Payment Transaction Response from Apple");

        for transaction:AnyObject in transactions {
            if let trans:SKPaymentTransaction = transaction as? SKPaymentTransaction{
                switch trans.transactionState {
                case .purchased:
                    print("Product Purchased");
                    SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
                    // Handle the purchase

                    if purchase == "purchase" {
                        UserDefaults.standard.set(true , forKey: "purchase\(index)")
                    }

                    if purchase == "purchaseFull" {
                        UserDefaults.standard.set(true , forKey: "purchaseFull")
                    }

                    viewDidLoad()
                    break;
                case .failed:
                    print("Purchased Failed");
                    SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
                    break;

                case .restored:
                    print("Already Purchased");
                    SKPaymentQueue.default().restoreCompletedTransactions()
                    // Handle the purchase
                    //UserDefaults.standard.set(true , forKey: "purchased")
                    viewDidLoad()
                    break;
                default:
                    break;
                }
            }
        }
    }

    @IBAction func restoreAction(_ sender: Any) {
        SKPaymentQueue.default().add(self)
        if (SKPaymentQueue.canMakePayments()) {
            SKPaymentQueue.default().restoreCompletedTransactions()
        }
    }

    func requestDidFinish(_ request: SKRequest) {

    }

    func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
        print("transactions restored")
        for transaction in queue.transactions {
            let t: SKPaymentTransaction = transaction
            let prodID = t.payment.productIdentifier as String

            if prodID == "purchaseFull" {
                print("action for restored")
                queue.finishTransaction(t)
                UserDefaults.standard.set(true , forKey: "purchaseFull")
            } else if prodID == "purchase0" {
                print("action0")
                queue.finishTransaction(t)
                UserDefaults.standard.set(true , forKey: "purchase0")
            } else if prodID == "purchase1" {
                print("action1")
                queue.finishTransaction(t)
                UserDefaults.standard.set(true , forKey: "purchase1")
            } else if prodID == "purchase2" {
                print("action2")
                queue.finishTransaction(t)
                UserDefaults.standard.set(true , forKey: "purchase2")
            } else if prodID == "purchase3" {
                print("action3")
                queue.finishTransaction(t)
                UserDefaults.standard.set(true , forKey: "purchase3")
            } else if prodID == "purchase4" {
                print("action4")
                queue.finishTransaction(t)
                UserDefaults.standard.set(true , forKey: "purchase4")
            } else if prodID == "purchase5" {
                print("action5")
                queue.finishTransaction(t)
                UserDefaults.standard.set(true , forKey: "purchase5")
            }
        }
        cancelAction((Any).self)
    }
@IBAction func purchaseFull(uu发送方:任意){
purchase=“purchaseFull”
product_id=“purchaseFull”
打印(“即将获取产品…”)
//self.loading.startAnimating()
SKPaymentQueue.default().add(self)
//我可以付款
if(SKPaymentQueue.canMakePayments())
{
让productID:NSSet=NSSet(对象:self.product_id!);
让productsRequest:SKProductsRequest=SKProductsRequest(产品标识符:productID为!集);
productsRequest.delegate=self;
productsRequest.start();
打印(“提取产品”);
}否则{
打印(“无法购买”);
}
}
@iAction func购买(\发送方:任何){
purchase=“purchase”
product_id=“购买\(索引)”
打印(“即将获取产品…”)
//self.loading.startAnimating()
SKPaymentQueue.default().add(self)
//我可以付款
if(SKPaymentQueue.canMakePayments())
{
让productID:NSSet=NSSet(对象:self.product_id!);
让productsRequest:SKProductsRequest=SKProductsRequest(产品标识符:productID为!集);
productsRequest.delegate=self;
productsRequest.start();
打印(“提取产品”);
}否则{
打印(“无法购买”);
}
}
func productsRequest(uRequest:SKProductsRequest,didReceive response:SKProductsResponse){
让计数:Int=response.products.count
如果(计数>0){
让validProduct:SKProduct=response.products[0]作为SKProduct
if(validProduct.productIdentifier==self.product\u id){
打印(validProduct.localizedTitle)
打印(validProduct.localizedDescription)
打印(有效产品价格)
buyProduct(产品:validProduct);
}否则{
打印(validProduct.productIdentifier)
}
}否则{
打印(“无”)
}
}
func buyProduct(产品:SKProduct){
打印(“向苹果发送付款请求”);
let payment=SKPayment(产品:产品)
SKPaymentQueue.default().add(付款);
//self.loading.stopAnimating()
}
func请求(请求:SKRequest,DIDFILEWERROR错误:error){
打印(“获取产品信息时出错”);
//self.loading.stopAnimating()
}
func paymentQueue(queue:SKPaymentQueue,
更新的交易记录:[SKPaymentTransaction]){
打印(“收到苹果公司的付款交易响应”);
对于事务:事务中的任何对象{
如果让交易:SKPaymentTransaction=交易为?SKPaymentTransaction{
开关trans.transactionState{
案例。购买:
印刷品(“购买的产品”);
SKPaymentQueue.default().finishTransaction(事务为!SKPaymentTransaction)
//处理购买事宜
如果购买==“购买”{
UserDefaults.standard.set(true,forKey:“购买\(索引)”)
}
如果购买=“purchaseFull”{
UserDefaults.standard.set(true,forKey:“purchaseFull”)
}
viewDidLoad()
打破
案例。失败:
打印(“购买失败”);
SKPaymentQueue.default().finishTransaction(事务为!SKPaymentTransaction)
打破
案件.恢复:
印刷品(“已购买”);
SKPaymentQueue.default().restoreCompletedTransactions()
//处理购买事宜
//UserDefaults.standard.set(true,forKey:“已购买”)
viewDidLoad()
打破
违约:
打破
}
}
}
}
@iAction func restoreAction(\发送方:任意){
SKPaymentQueue.default().add(self)
if(SKPaymentQueue.canMakePayments()){
SKPaymentQueue.default().restoreCompletedTransactions()
}
}
func requestdidfish(u请求:SKRequest){
}
func paymentQueueRestoreCompletedTransactionsFinished(队列:SKPaymentQueue){
打印(“恢复的交易”)
对于queue.transactions中的事务{
设t:SKPaymentTransaction=transaction
将prodID=t.payment.productIdentifier设为字符串
如果prodID==“purchaseFull”{
打印(“恢复的操作”)
queue.finishTransaction(t)
UserDefaults.standard.set(true,forKey:“purchaseFull”)
}如果prodID==“purchase0”,则为else{
打印(“action0”)
queue.finishTransaction(t)
UserDefaults.standard.set(true,forKey:“purchase0”)
}如果prodID==“purchase1”,则为else{
打印(“操作1”)
queue.finishTransaction(t)
UserDefaults.standard.set(true,forKey:“purchase1”)
}如果prodID==“purchase2”,则为else{
打印(“操作2”)
queue.finishTransaction(t)
UserDefaults.standard.set(true,forKey:“purchase2”)
}如果prodID==“purchase3”,则为else{
打印(“操作3”)
queue.finishTransaction(t)
UserDefaults.standard.set(true,forKey:“purchase3”)
}如果prodID==“purchase4”,则为else{
打印(“操作4”)
queue.finishTransaction(t)
UserDefaults.standard.set(true,forKey:“purchase4”)
}如果prodID==“purchase5”,则为else{
import StoreKit

/// Defines callbacks that will occur when products are being validated with the iTunes Store.
protocol iTunesProductStatusReceiver: class {
    func didValidateProducts(_ products: [SKProduct])
    func didReceiveInvalidProductIdentifiers(_ identifiers: [String])
}

/// Defines callbacks that occur during the purchase or restore process
protocol iTunesPurchaseStatusReceiver: class {
    func purchaseStatusDidUpdate(_ status: PurchaseStatus)
    func restoreStatusDidUpdate(_ status: PurchaseStatus)
}
import Foundation
import StoreKit

class iTunesStore: NSObject, SKProductsRequestDelegate {

    weak var delegate: (iTunesProductStatusReceiver & iTunesPurchaseStatusReceiver)?

    var transactionObserver: IAPObserver = IAPObserver()
    var availableProducts: [SKProduct] = []
    var invalidProductIDs: [String] = []

    deinit {
        SKPaymentQueue.default().remove(self.transactionObserver)
    }

    override init() {
        super.init()
        transactionObserver.delegate = self
    }

    func fetchStoreProducts(identifiers:Set<String>) {
        print("Sending products request to ITC")
        let request:SKProductsRequest = SKProductsRequest.init(productIdentifiers: identifiers)
        request.delegate = self
        request.start()
    }

    func purchaseProduct(identifier:String) {
        guard let product = self.product(identifier: identifier) else {
            print("No products found with identifier: \(identifier)")

            // fire purchase status: failed notification
            delegate?.purchaseStatusDidUpdate(PurchaseStatus.init(state: .failed, error: PurchaseError.productNotFound, transaction: nil, message:"An error occured"))
            return
        }

        guard SKPaymentQueue.canMakePayments() else {
            print("Unable to make purchases...")
            delegate?.purchaseStatusDidUpdate(PurchaseStatus.init(state: .failed, error: PurchaseError.unableToPurchase, transaction: nil, message:"An error occured"))
            return
        }

        // Fire purchase began notification
        delegate?.purchaseStatusDidUpdate(PurchaseStatus.init(state: .initiated, error: nil, transaction: nil, message:"Processing Purchase"))

        let payment = SKPayment.init(product: product)
        SKPaymentQueue.default().add(payment)

    }

    func restorePurchases() {
        // Fire purchase began notification
        delegate?.restoreStatusDidUpdate(PurchaseStatus.init(state: .initiated, error: nil, transaction: nil, message:"Restoring Purchases"))
        SKPaymentQueue.default().restoreCompletedTransactions()
    }


    // returns a product for a given identifier if it exists in our available products array
    func product(identifier:String) -> SKProduct? {
        for product in availableProducts {
            if product.productIdentifier == identifier {
                return product
            }
        }

        return nil
    }

}

// Receives purchase status notifications and forwards them to this classes delegate
extension iTunesStore: iTunesPurchaseStatusReceiver {
    func purchaseStatusDidUpdate(_ status: PurchaseStatus) {
        delegate?.purchaseStatusDidUpdate(status)
    }

    func restoreStatusDidUpdate(_ status: PurchaseStatus) {
        delegate?.restoreStatusDidUpdate(status)
    }
}

// MARK: SKProductsRequest Delegate Methods
extension iTunesStore {
    @objc(productsRequest:didReceiveResponse:) func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        // set new products
        availableProducts = response.products

        // set invalid product id's
        invalidProductIDs = response.invalidProductIdentifiers
        if invalidProductIDs.isEmpty == false {
            // call delegate if we received any invalid identifiers
            delegate?.didReceiveInvalidProductIdentifiers(invalidProductIDs)
        }
        print("iTunes Store: Invalid product IDs: \(response.invalidProductIdentifiers)")

        // call delegate with available products.
        delegate?.didValidateProducts(availableProducts)
    }
}
import Foundation
import StoreKit

enum PurchaseState {
    case initiated
    case complete
    case cancelled
    case failed
}


class PurchaseStatus {
    var state:PurchaseState
    var error:Error?
    var transaction:SKPaymentTransaction?
    var message:String

    init(state:PurchaseState, error:Error?, transaction:SKPaymentTransaction?, message:String) {
        self.state = state
        self.error = error
        self.transaction = transaction
        self.message = message
    }
}

public enum PurchaseError: Error {
    case productNotFound
    case unableToPurchase

    public var code: Int {
        switch self {
        case .productNotFound:
            return 100101
        case .unableToPurchase:
            return 100101
        }
    }

    public var description: String {
        switch self {
        case .productNotFound:
            return "No products found for the requested product ID."
        case .unableToPurchase:
            return "Unable to make purchases. Check to make sure you are signed into a valid itunes account and that you are allowed to make purchases."
        }
    }

    public var title: String {
        switch self {
        case .productNotFound:
            return "Product Not Found"
        case .unableToPurchase:
            return "Unable to Purchase"
        }
    }

    public var domain: String {
        return "com.myAppId.purchaseError"
    }

    public var recoverySuggestion: String {
        switch self {
        case .productNotFound:
            return "Try again later."
        case .unableToPurchase:
            return "Check to make sure you are signed into a valid itunes account and that you are allowed to make purchases."
        }
    }
}
import Foundation
import StoreKit


class IAPObserver: NSObject, SKPaymentTransactionObserver {

    // delegate to propagate status update up
    weak var delegate: iTunesPurchaseStatusReceiver?

    override init() {
        super.init()
        SKPaymentQueue.default().add(self)
    }

    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        for transaction in transactions {
            switch transaction.transactionState {
                case .purchasing:   // Transaction is being added to the server queue
                    break

                case .purchased:    // Transaction is in queue, user has been charged. Complete transaction now
                    // Notify purchase complete status
                    delegate?.purchaseStatusDidUpdate(PurchaseStatus.init(state: .complete, error: nil, transaction: transaction, message:"Purchase Complete."))
                    SKPaymentQueue.default().finishTransaction(transaction)

                case .failed:   // Transaction was cancelled or failed before being added to the server queue
                        // An error occured, notify
                    delegate?.purchaseStatusDidUpdate(PurchaseStatus.init(state: .failed, error: transaction.error, transaction: transaction, message:"An error occured."))
                    SKPaymentQueue.default().finishTransaction(transaction)

                case .restored: // transaction was rewtored from the users purchase history. Complete transaction now.
                    // notify purchase completed with status... success
                    delegate?.restoreStatusDidUpdate(PurchaseStatus.init(state: .complete, error: nil, transaction: transaction, message:"Restore Success!"))
                    SKPaymentQueue.default().finishTransaction(transaction)

                case .deferred: // transaction is in the queue, but it's final status is pending user/external action
                    break
            }
        }
    }

    func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
        guard queue.transactions.count > 0 else {
            // Queue does not include any transactions, so either user has not yet made a purchase
            // or the user's prior purchase is unavailable, so notify app (and user) accordingly.

            print("restore queue.transaction.count === 0")
            return
        }

        for transaction in queue.transactions {
            // TODO: provide content access here??
            print("Product restored with id: \(String(describing: transaction.original?.payment.productIdentifier))")
            SKPaymentQueue.default().finishTransaction(transaction)
        }
    }

    func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {
        // fire notification to dismiss spinner, restore error
        delegate?.restoreStatusDidUpdate(PurchaseStatus.init(state: .failed, error: error, transaction: nil, message:"Restore Failed."))
    }
}
enum ProductIdentifier: String {
    case one = "com.myprefix.id1"
    case two = "com.myprefix.id2"

    static func from(rawValue: String) -> ProductIdentifier? {
        switch rawValue {
        case one.rawValue: return .one
        case two.rawValue: return .two
        default: return nil
        }
    }
}

class Store {
    static let shared = Store()

    // purchase processor
    var paymentProcessor: iTunesStore = iTunesStore()

    init() {
        // register for purchase status update callbacks
        paymentProcessor.delegate = self

        validateProducts()
    }

    // validates products with the iTunesConnect store for faster purchase processing
    // when a user wants to buy
    internal func validateProducts() {

        // all products to validate
        let products = [
            ProductIdentifier.one.rawValue,
            ProductIdentifier.two.rawValue
        ]

        paymentProcessor.fetchStoreProducts(identifiers: Set.init(products))
    }

    /// Purchase a product by specifying the product identifier.
    ///
    /// - Parameter identifier: The product identifier for the product being purchased. This must belong to a valid product in the 'products' array, as this array is searched for a product with the specified identifier. If none are found this function bails.
    func purchaseProduct(identifier: ProductIdentifier) {
        print("purchase product: \(identifier)")

        self.paymentProcessor.purchaseProduct(identifier: identifier.rawValue)
    }

    /// Initiates restore purchases functionality.
    func restorePurchases() {
        self.paymentProcessor.restorePurchases()
    }

    /// This function is called during the purchase/restore purchase process with each status change in the flow. If the status is complete then access to the product should be granted at this point.
    ///
    /// - Parameter status: The current status of the transaction.
    internal func processPurchaseStatus(_ status: PurchaseStatus) {
        switch status.state {
        case .initiated:
            // TODO: show alert that purchase is in progress...
            break
        case .complete:
            if let productID = status.transaction?.payment.productIdentifier {
                // Store product id in UserDefaults or some other method of tracking purchases
                UserDefaults.standard.set(true , forKey: productID)
                UserDefaults.standard.synchronize()
            }
        case .cancelled:
            break
        case .failed:
            // TODO: notify user with alert...
            break
        }
    }
}

extension Store: iTunesPurchaseStatusReceiver, iTunesProductStatusReceiver {
    func purchaseStatusDidUpdate(_ status: PurchaseStatus) {
        // process based on received status
        processPurchaseStatus(status)
    }

    func restoreStatusDidUpdate(_ status: PurchaseStatus) {
        // pass this into the same flow as purchasing for unlocking products
        processPurchaseStatus(status)
    }

    func didValidateProducts(_ products: [SKProduct]) {
        print("Product identifier validation complete with products: \(products)")
        // TODO: if you have a local representation of your products you could
        // sync them up with the itc version here
    }

    func didReceiveInvalidProductIdentifiers(_ identifiers: [String]) {
        // TODO: filter out invalid products? maybe... by default isActive is false
    }
}
import UIKit

extension UIApplication {
    static func topViewController(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
        if let navigationController = controller as? UINavigationController {
            return topViewController(controller: navigationController.visibleViewController)
        }
        if let tabController = controller as? UITabBarController {
            if let selected = tabController.selectedViewController {
                return topViewController(controller: selected)
            }
        }
        if let presented = controller?.presentedViewController {
            return topViewController(controller: presented)
        }
        return controller
    }
}
internal func showAlert() {

    // do UI stuff on the main thread
    DispatchQueue.main.async { [weak self] in

        // load alert from storyboard, nib, or some method, get the topmost view controller in the controller hierarchy, only use it if it's not being dismissed
        guard let alertVC = MyAlertClass.fromNib(), let topVC = UIApplication.topViewController(), topVC.isBeingDismissed == false else {
            return
        }

        // set our local variable so we can update the message later and dismiss it more easily
        self.myAlertController = alertVC

        // Present the alert view controller
        topVC.present(alertVC, animated: true, completion: nil)
    }
}