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