From 7810fd6bf0c5a749e1ab59c6805217afdb48a722 Mon Sep 17 00:00:00 2001 From: Jake Petroules Date: Wed, 5 Aug 2015 02:11:20 -0700 Subject: Adapt iOS backend to work on OS X as well. Change-Id: Ieec9c7d02225697bfaeaaa3ca1a87fbcf77327ea Reviewed-by: Jake Petroules Reviewed-by: Andy Nichols --- examples/purchasing/qthangman/qthangman.pro | 4 +- src/purchasing/doc/src/qtpurchasing-overview.qdoc | 2 +- src/purchasing/inapppurchase/inapppurchase.pri | 4 +- src/purchasing/inapppurchase/ios/ios.pri | 11 - .../inapppurchase/ios/qiosinapppurchasebackend.mm | 258 ------------------- .../inapppurchase/ios/qiosinapppurchasebackend_p.h | 82 ------- .../inapppurchase/ios/qiosinapppurchaseproduct.mm | 79 ------ .../inapppurchase/ios/qiosinapppurchaseproduct_p.h | 68 ------ .../ios/qiosinapppurchasetransaction.mm | 99 -------- .../ios/qiosinapppurchasetransaction_p.h | 77 ------ src/purchasing/inapppurchase/mac/mac.pri | 11 + .../inapppurchase/mac/qmacinapppurchasebackend.mm | 272 +++++++++++++++++++++ .../inapppurchase/mac/qmacinapppurchasebackend_p.h | 84 +++++++ .../inapppurchase/mac/qmacinapppurchaseproduct.mm | 79 ++++++ .../inapppurchase/mac/qmacinapppurchaseproduct_p.h | 68 ++++++ .../mac/qmacinapppurchasetransaction.mm | 101 ++++++++ .../mac/qmacinapppurchasetransaction_p.h | 77 ++++++ .../inapppurchase/qinapppurchasebackendfactory.cpp | 8 +- src/purchasing/inapppurchase/qinappstore.cpp | 2 +- .../purchasing/qinappstore/tst_qinappstore.cpp | 2 +- 20 files changed, 703 insertions(+), 685 deletions(-) delete mode 100644 src/purchasing/inapppurchase/ios/ios.pri delete mode 100644 src/purchasing/inapppurchase/ios/qiosinapppurchasebackend.mm delete mode 100644 src/purchasing/inapppurchase/ios/qiosinapppurchasebackend_p.h delete mode 100644 src/purchasing/inapppurchase/ios/qiosinapppurchaseproduct.mm delete mode 100644 src/purchasing/inapppurchase/ios/qiosinapppurchaseproduct_p.h delete mode 100644 src/purchasing/inapppurchase/ios/qiosinapppurchasetransaction.mm delete mode 100644 src/purchasing/inapppurchase/ios/qiosinapppurchasetransaction_p.h create mode 100644 src/purchasing/inapppurchase/mac/mac.pri create mode 100644 src/purchasing/inapppurchase/mac/qmacinapppurchasebackend.mm create mode 100644 src/purchasing/inapppurchase/mac/qmacinapppurchasebackend_p.h create mode 100644 src/purchasing/inapppurchase/mac/qmacinapppurchaseproduct.mm create mode 100644 src/purchasing/inapppurchase/mac/qmacinapppurchaseproduct_p.h create mode 100644 src/purchasing/inapppurchase/mac/qmacinapppurchasetransaction.mm create mode 100644 src/purchasing/inapppurchase/mac/qmacinapppurchasetransaction_p.h diff --git a/examples/purchasing/qthangman/qthangman.pro b/examples/purchasing/qthangman/qthangman.pro index d1bea15..96b87e9 100644 --- a/examples/purchasing/qthangman/qthangman.pro +++ b/examples/purchasing/qthangman/qthangman.pro @@ -31,9 +31,9 @@ OTHER_FILES += \ qml/qthangman/Word.qml \ enable2.txt -ios { +mac { #Change the following lines to match your unique App ID - #to enable in-app purchases on iOS + #to enable in-app purchases on OS X and iOS #For example if your App ID is org.qtproject.qt.iosteam.qthangman" #QMAKE_TARGET_BUNDLE_PREFIX = "org.qtproject.qt.iosteam" #TARGET = qthangman diff --git a/src/purchasing/doc/src/qtpurchasing-overview.qdoc b/src/purchasing/doc/src/qtpurchasing-overview.qdoc index e72ba7e..71760d5 100644 --- a/src/purchasing/doc/src/qtpurchasing-overview.qdoc +++ b/src/purchasing/doc/src/qtpurchasing-overview.qdoc @@ -32,7 +32,7 @@ Qt Purchasing is an add-on library that enables Qt applications to support in-app purchases. It is a cross-platform library that currently supports - purchases made to the App Store on iOS, and Google Play on Android. + purchases made to the Mac App Store on OS X, App Store on iOS, and Google Play on Android. \section1 In-App Purchases diff --git a/src/purchasing/inapppurchase/inapppurchase.pri b/src/purchasing/inapppurchase/inapppurchase.pri index 2f2acc3..85bab80 100644 --- a/src/purchasing/inapppurchase/inapppurchase.pri +++ b/src/purchasing/inapppurchase/inapppurchase.pri @@ -23,6 +23,6 @@ android { include ($$PWD/android/android.pri) } -ios { - include ($$PWD/ios/ios.pri) +mac { + include ($$PWD/mac/mac.pri) } diff --git a/src/purchasing/inapppurchase/ios/ios.pri b/src/purchasing/inapppurchase/ios/ios.pri deleted file mode 100644 index b0b1b55..0000000 --- a/src/purchasing/inapppurchase/ios/ios.pri +++ /dev/null @@ -1,11 +0,0 @@ -LIBS += -framework StoreKit -framework Foundation -INCLUDEPATH += $$PWD -HEADERS += \ - inapppurchase/ios/qiosinapppurchaseproduct_p.h \ - inapppurchase/ios/qiosinapppurchasebackend_p.h \ - inapppurchase/ios/qiosinapppurchasetransaction_p.h - -OBJECTIVE_SOURCES += \ - inapppurchase/ios/qiosinapppurchasebackend.mm \ - inapppurchase/ios/qiosinapppurchaseproduct.mm \ - inapppurchase/ios/qiosinapppurchasetransaction.mm diff --git a/src/purchasing/inapppurchase/ios/qiosinapppurchasebackend.mm b/src/purchasing/inapppurchase/ios/qiosinapppurchasebackend.mm deleted file mode 100644 index 92f3bb0..0000000 --- a/src/purchasing/inapppurchase/ios/qiosinapppurchasebackend.mm +++ /dev/null @@ -1,258 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Purchasing module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3-COMM$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qiosinapppurchasebackend_p.h" -#include "qiosinapppurchaseproduct_p.h" -#include "qiosinapppurchasetransaction_p.h" - -#include - -#import - -@interface InAppPurchaseManager : NSObject -{ - QIosInAppPurchaseBackend *backend; - NSMutableArray *pendingTransactions; -} - --(void)requestProductData:(NSString *)identifier; --(void)processPendingTransactions; - -@end - -@implementation InAppPurchaseManager - --(id)initWithBackend:(QIosInAppPurchaseBackend *)iapBackend { - if (self = [super init]) { - backend = iapBackend; - pendingTransactions = [[NSMutableArray alloc] init]; - [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; - } - return self; -} - --(void)dealloc -{ - [[SKPaymentQueue defaultQueue] removeTransactionObserver:self]; - [pendingTransactions release]; - [super dealloc]; -} - --(void)requestProductData:(NSString *)identifier -{ - NSSet *productId = [NSSet setWithObject:identifier]; - SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productId]; - productsRequest.delegate = self; - [productsRequest start]; -} - --(void)processPendingTransactions -{ - NSMutableArray *registeredTransactions = [NSMutableArray array]; - - for (SKPaymentTransaction *transaction in pendingTransactions) { - QInAppTransaction::TransactionStatus status = [InAppPurchaseManager statusFromTransaction:transaction]; - - QIosInAppPurchaseProduct *product = backend->registeredProductForProductId(QString::fromNSString(transaction.payment.productIdentifier)); - - if (product) { - //It is possible that the product doesn't exist yet (because of previous restores). - QIosInAppPurchaseTransaction *qtTransaction = new QIosInAppPurchaseTransaction(transaction, status, product, backend); - [registeredTransactions addObject:transaction]; - QMetaObject::invokeMethod(backend, "registerTransaction", Qt::AutoConnection, Q_ARG(QIosInAppPurchaseTransaction*, qtTransaction)); - } - } - - //Remove registeredTransactions from pendingTransactions - [pendingTransactions removeObjectsInArray:registeredTransactions]; -} - - -//SKProductsRequestDelegate --(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response -{ - NSArray *products = response.products; - SKProduct *product = [products count] == 1 ? [[products firstObject] retain] : nil; - - if (product == nil) { - //Invalid product ID - NSString *invalidId = [response.invalidProductIdentifiers firstObject]; - QMetaObject::invokeMethod(backend, "registerQueryFailure", Qt::AutoConnection, Q_ARG(QString, QString::fromNSString(invalidId))); - } else { - //Valid product query - //Create a QIosInAppPurchaseProduct - QIosInAppPurchaseProduct *validProduct = new QIosInAppPurchaseProduct(product, backend->productTypeForProductId(QString::fromNSString([product productIdentifier])), backend); - QMetaObject::invokeMethod(backend, "registerProduct", Qt::AutoConnection, Q_ARG(QIosInAppPurchaseProduct*, validProduct)); - } - - [request release]; -} - -+(QInAppTransaction::TransactionStatus)statusFromTransaction:(SKPaymentTransaction *)transaction -{ - QInAppTransaction::TransactionStatus status; - switch (transaction.transactionState) { - case SKPaymentTransactionStatePurchasing: - //Ignore the purchasing state as it's not really a transaction - //And its important that it doesn't need to be finalized as - //Calling finishTransaction: on a transaction that is - //in the SKPaymentTransactionStatePurchasing state throws an exception - status = QInAppTransaction::Unknown; - break; - case SKPaymentTransactionStatePurchased: - status = QInAppTransaction::PurchaseApproved; - break; - case SKPaymentTransactionStateFailed: - status = QInAppTransaction::PurchaseFailed; - break; - case SKPaymentTransactionStateRestored: - status = QInAppTransaction::PurchaseRestored; - break; - default: - status = QInAppTransaction::Unknown; - break; - } - return status; -} - -//SKPaymentTransactionObserver -- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions -{ - Q_UNUSED(queue); - for (SKPaymentTransaction *transaction in transactions) { - //Create QIosInAppPurchaseTransaction - QInAppTransaction::TransactionStatus status = [InAppPurchaseManager statusFromTransaction:transaction]; - - if (status == QInAppTransaction::Unknown) - continue; - - QIosInAppPurchaseProduct *product = backend->registeredProductForProductId(QString::fromNSString(transaction.payment.productIdentifier)); - - if (product) { - //It is possible that the product doesn't exist yet (because of previous restores). - QIosInAppPurchaseTransaction *qtTransaction = new QIosInAppPurchaseTransaction(transaction, status, product, backend); - QMetaObject::invokeMethod(backend, "registerTransaction", Qt::AutoConnection, Q_ARG(QIosInAppPurchaseTransaction*, qtTransaction)); - } else { - //Add the transaction to the pending transactions list - [pendingTransactions addObject:transaction]; - } - } -} - -@end - - -QT_BEGIN_NAMESPACE - -QIosInAppPurchaseBackend::QIosInAppPurchaseBackend(QObject *parent) - : QInAppPurchaseBackend(parent) - , m_iapManager(0) -{ -} - -QIosInAppPurchaseBackend::~QIosInAppPurchaseBackend() -{ - [(InAppPurchaseManager*)m_iapManager release]; -} - -void QIosInAppPurchaseBackend::initialize() -{ - m_iapManager = [[InAppPurchaseManager alloc] initWithBackend:this]; - emit QInAppPurchaseBackend::ready(); -} - -bool QIosInAppPurchaseBackend::isReady() const -{ - if (m_iapManager) - return true; - return false; -} - -void QIosInAppPurchaseBackend::queryProduct(QInAppProduct::ProductType productType, const QString &identifier) -{ - Q_UNUSED(productType) - - if (m_productTypeForPendingId.contains(identifier)) { - qWarning("Product query already pending for %s", qPrintable(identifier)); - return; - } - - m_productTypeForPendingId[identifier] = productType; - - [(InAppPurchaseManager*)m_iapManager requestProductData:(identifier.toNSString())]; -} - -void QIosInAppPurchaseBackend::restorePurchases() -{ - [[SKPaymentQueue defaultQueue] restoreCompletedTransactions]; -} - -void QIosInAppPurchaseBackend::setPlatformProperty(const QString &propertyName, const QString &value) -{ - Q_UNUSED(propertyName); - Q_UNUSED(value); -} - -void QIosInAppPurchaseBackend::registerProduct(QIosInAppPurchaseProduct *product) -{ - QHash::iterator it = m_productTypeForPendingId.find(product->identifier()); - Q_ASSERT(it != m_productTypeForPendingId.end()); - - m_registeredProductForId[product->identifier()] = product; - emit productQueryDone(product); - m_productTypeForPendingId.erase(it); - [m_iapManager processPendingTransactions]; -} - -void QIosInAppPurchaseBackend::registerQueryFailure(const QString &productId) -{ - QHash::iterator it = m_productTypeForPendingId.find(productId); - Q_ASSERT(it != m_productTypeForPendingId.end()); - - emit QInAppPurchaseBackend::productQueryFailed(it.value(), it.key()); - m_productTypeForPendingId.erase(it); -} - -void QIosInAppPurchaseBackend::registerTransaction(QIosInAppPurchaseTransaction *transaction) -{ - emit QInAppPurchaseBackend::transactionReady(transaction); -} - -QInAppProduct::ProductType QIosInAppPurchaseBackend::productTypeForProductId(const QString &productId) -{ - return m_productTypeForPendingId[productId]; -} - -QIosInAppPurchaseProduct *QIosInAppPurchaseBackend::registeredProductForProductId(const QString &productId) -{ - return m_registeredProductForId[productId]; -} - -QT_END_NAMESPACE - -#include "moc_qiosinapppurchasebackend_p.cpp" diff --git a/src/purchasing/inapppurchase/ios/qiosinapppurchasebackend_p.h b/src/purchasing/inapppurchase/ios/qiosinapppurchasebackend_p.h deleted file mode 100644 index 83febbe..0000000 --- a/src/purchasing/inapppurchase/ios/qiosinapppurchasebackend_p.h +++ /dev/null @@ -1,82 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Purchasing module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3-COMM$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QIOSINAPPPURCHASEBACKEND_P_H -#define QIOSINAPPPURCHASEBACKEND_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qinapppurchasebackend_p.h" -#include "qinappproduct.h" -#include "qinapptransaction.h" - -#include - -QT_BEGIN_NAMESPACE - -class QIosInAppPurchaseProduct; -class QIosInAppPurchaseTransaction; - -class QIosInAppPurchaseBackend : public QInAppPurchaseBackend -{ - Q_OBJECT -public: - QIosInAppPurchaseBackend(QObject *parent = 0); - ~QIosInAppPurchaseBackend(); - - void initialize(); - bool isReady() const; - void queryProduct(QInAppProduct::ProductType productType, const QString &identifier); - void restorePurchases(); - void setPlatformProperty(const QString &propertyName, const QString &value); - - //Called by InAppPurchaseManager - Q_INVOKABLE void registerProduct(QIosInAppPurchaseProduct *product); - Q_INVOKABLE void registerQueryFailure(const QString &productId); - Q_INVOKABLE void registerTransaction(QIosInAppPurchaseTransaction *transaction); - QInAppProduct::ProductType productTypeForProductId(const QString &productId); - QIosInAppPurchaseProduct *registeredProductForProductId(const QString &productId); - -private: - void *m_iapManager; - QHash m_productTypeForPendingId; - QHash m_registeredProductForId; -}; - -#endif // QIOSINAPPPURCHASEBACKEND_P_H - -QT_END_NAMESPACE diff --git a/src/purchasing/inapppurchase/ios/qiosinapppurchaseproduct.mm b/src/purchasing/inapppurchase/ios/qiosinapppurchaseproduct.mm deleted file mode 100644 index 903e5f5..0000000 --- a/src/purchasing/inapppurchase/ios/qiosinapppurchaseproduct.mm +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Purchasing module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3-COMM$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qiosinapppurchaseproduct_p.h" -#include "qiosinapppurchasebackend_p.h" - -#import - -//Use a Catagory to add a localizedPrice method to SKProduct -@interface SKProduct (LocalizedPrice) - -@property (nonatomic, readonly) NSString *localizedPrice; - -@end - -@implementation SKProduct (LocalizedPrice) - -- (NSString *)localizedPrice -{ - NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; - [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4]; - [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; - [numberFormatter setLocale:self.priceLocale]; - NSString *formattedString = [numberFormatter stringFromNumber:self.price]; - [numberFormatter release]; - return formattedString; -} - -@end - -QT_BEGIN_NAMESPACE - -QIosInAppPurchaseProduct::QIosInAppPurchaseProduct(SKProduct *product, - ProductType productType, - QIosInAppPurchaseBackend *backend) - : QInAppProduct(QString::fromNSString([product localizedPrice]), - QString::fromNSString([product localizedTitle]), - QString::fromNSString([product localizedDescription]), - productType, - QString::fromNSString([product productIdentifier]), - backend) - , m_nativeProduct(product) -{ -} - -void QIosInAppPurchaseProduct::purchase() -{ - SKPayment *payment = [SKPayment paymentWithProduct:m_nativeProduct]; - [[SKPaymentQueue defaultQueue] addPayment:payment]; -} - -QT_END_NAMESPACE - -#include "moc_qiosinapppurchaseproduct_p.cpp" diff --git a/src/purchasing/inapppurchase/ios/qiosinapppurchaseproduct_p.h b/src/purchasing/inapppurchase/ios/qiosinapppurchaseproduct_p.h deleted file mode 100644 index ff51f87..0000000 --- a/src/purchasing/inapppurchase/ios/qiosinapppurchaseproduct_p.h +++ /dev/null @@ -1,68 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Purchasing module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3-COMM$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QIOSINAPPPURCHASEPRODUCT_P_H -#define QIOSINAPPPURCHASEPRODUCT_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qinappproduct.h" - -@class SKProduct; - -QT_BEGIN_NAMESPACE - -class QIosInAppPurchaseBackend; - -class QIosInAppPurchaseProduct : public QInAppProduct -{ - Q_OBJECT -public: - explicit QIosInAppPurchaseProduct(SKProduct *product, - ProductType productType, - QIosInAppPurchaseBackend *backend); - void purchase(); - -private: - SKProduct *m_nativeProduct; -}; - -Q_DECLARE_METATYPE(QIosInAppPurchaseProduct*); - -QT_END_NAMESPACE - -#endif // QIOSINAPPPURCHASEPRODUCT_P_H diff --git a/src/purchasing/inapppurchase/ios/qiosinapppurchasetransaction.mm b/src/purchasing/inapppurchase/ios/qiosinapppurchasetransaction.mm deleted file mode 100644 index fccb74c..0000000 --- a/src/purchasing/inapppurchase/ios/qiosinapppurchasetransaction.mm +++ /dev/null @@ -1,99 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Purchasing module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3-COMM$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qiosinapppurchasetransaction_p.h" -#include "qiosinapppurchasebackend_p.h" - -#import - -QT_BEGIN_NAMESPACE - -QIosInAppPurchaseTransaction::QIosInAppPurchaseTransaction(SKPaymentTransaction *transaction, - const TransactionStatus status, - QInAppProduct *product, - QIosInAppPurchaseBackend *backend) - : QInAppTransaction(status, product, backend) - , m_nativeTransaction(transaction) - , m_failureReason(NoFailure) -{ - if (status == PurchaseFailed) { - m_failureReason = ErrorOccurred; - switch (m_nativeTransaction.error.code) { - case SKErrorClientInvalid: - m_errorString = QStringLiteral("Client Invalid"); - break; - case SKErrorPaymentCancelled: - m_errorString = QStringLiteral("Payment Cancelled"); - m_failureReason = CanceledByUser; - break; - case SKErrorPaymentInvalid: - m_errorString = QStringLiteral("Payment Invalid"); - break; - case SKErrorPaymentNotAllowed: - m_errorString = QStringLiteral("Payment Not Allowed"); - break; - case SKErrorStoreProductNotAvailable: - m_errorString = QStringLiteral("Store Product Not Available"); - break; - case SKErrorUnknown: - default: - m_errorString = QStringLiteral("Unknown"); - } - } -} - -void QIosInAppPurchaseTransaction::finalize() -{ - [[SKPaymentQueue defaultQueue] finishTransaction:m_nativeTransaction]; -} - -QString QIosInAppPurchaseTransaction::orderId() const -{ - return QString::fromNSString(m_nativeTransaction.transactionIdentifier); -} - -QInAppTransaction::FailureReason QIosInAppPurchaseTransaction::failureReason() const -{ - return m_failureReason; -} - -QString QIosInAppPurchaseTransaction::errorString() const -{ - return m_errorString; -} - -QDateTime QIosInAppPurchaseTransaction::timestamp() const -{ - //Get time in seconds since 1970 - double timeInterval = [[m_nativeTransaction transactionDate] timeIntervalSince1970]; - return QDateTime::fromMSecsSinceEpoch(qint64(timeInterval * 1000)); -} - -QT_END_NAMESPACE - -#include "moc_qiosinapppurchasetransaction_p.cpp" diff --git a/src/purchasing/inapppurchase/ios/qiosinapppurchasetransaction_p.h b/src/purchasing/inapppurchase/ios/qiosinapppurchasetransaction_p.h deleted file mode 100644 index fe9d4df..0000000 --- a/src/purchasing/inapppurchase/ios/qiosinapppurchasetransaction_p.h +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Purchasing module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3-COMM$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QIOSINAPPTRANSACTION_P_H -#define QIOSINAPPTRANSACTION_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qinapptransaction.h" -#include - -@class SKPaymentTransaction; - -QT_BEGIN_NAMESPACE - -class QIosInAppPurchaseBackend; - -class QIosInAppPurchaseTransaction : public QInAppTransaction -{ - Q_OBJECT -public: - QIosInAppPurchaseTransaction(SKPaymentTransaction *transaction, - const TransactionStatus status, - QInAppProduct *product, - QIosInAppPurchaseBackend *backend); - - void finalize(); - QString orderId() const; - FailureReason failureReason() const; - QString errorString() const; - QDateTime timestamp() const; - -private: - SKPaymentTransaction *m_nativeTransaction; - QString m_errorString; - FailureReason m_failureReason; -}; - -Q_DECLARE_METATYPE(QIosInAppPurchaseTransaction*); - -QT_END_NAMESPACE - -#endif // QIOSINAPPTRANSACTION_P_H diff --git a/src/purchasing/inapppurchase/mac/mac.pri b/src/purchasing/inapppurchase/mac/mac.pri new file mode 100644 index 0000000..10672eb --- /dev/null +++ b/src/purchasing/inapppurchase/mac/mac.pri @@ -0,0 +1,11 @@ +LIBS += -framework StoreKit -framework Foundation +INCLUDEPATH += $$PWD +HEADERS += \ + $$PWD/qmacinapppurchasebackend_p.h \ + $$PWD/qmacinapppurchasetransaction_p.h \ + $$PWD/qmacinapppurchaseproduct_p.h + +OBJECTIVE_SOURCES += \ + $$PWD/qmacinapppurchasebackend.mm \ + $$PWD/qmacinapppurchaseproduct.mm \ + $$PWD/qmacinapppurchasetransaction.mm diff --git a/src/purchasing/inapppurchase/mac/qmacinapppurchasebackend.mm b/src/purchasing/inapppurchase/mac/qmacinapppurchasebackend.mm new file mode 100644 index 0000000..a820211 --- /dev/null +++ b/src/purchasing/inapppurchase/mac/qmacinapppurchasebackend.mm @@ -0,0 +1,272 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Purchasing module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3-COMM$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmacinapppurchasebackend_p.h" +#include "qmacinapppurchaseproduct_p.h" +#include "qmacinapppurchasetransaction_p.h" + +#include + +#import + +@interface QT_MANGLE_NAMESPACE(InAppPurchaseManager) : NSObject +{ + QMacInAppPurchaseBackend *backend; + NSMutableArray *pendingTransactions; +} + +-(void)requestProductData:(NSString *)identifier; +-(void)processPendingTransactions; + +@end + +@implementation QT_MANGLE_NAMESPACE(InAppPurchaseManager) + +-(id)initWithBackend:(QMacInAppPurchaseBackend *)iapBackend { + if (self = [super init]) { + backend = iapBackend; + pendingTransactions = [[NSMutableArray alloc] init]; + [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; + qRegisterMetaType("QMacInAppPurchaseProduct*"); + qRegisterMetaType("QMacInAppPurchaseTransaction*"); + } + return self; +} + +-(void)dealloc +{ + [[SKPaymentQueue defaultQueue] removeTransactionObserver:self]; + [pendingTransactions release]; + [super dealloc]; +} + +-(void)requestProductData:(NSString *)identifier +{ + NSSet *productId = [NSSet setWithObject:identifier]; + SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productId]; + productsRequest.delegate = self; + [productsRequest start]; +} + +-(void)processPendingTransactions +{ + NSMutableArray *registeredTransactions = [NSMutableArray array]; + + for (SKPaymentTransaction *transaction in pendingTransactions) { + QInAppTransaction::TransactionStatus status = [InAppPurchaseManager statusFromTransaction:transaction]; + + QMacInAppPurchaseProduct *product = backend->registeredProductForProductId(QString::fromNSString(transaction.payment.productIdentifier)); + + if (product) { + //It is possible that the product doesn't exist yet (because of previous restores). + QMacInAppPurchaseTransaction *qtTransaction = new QMacInAppPurchaseTransaction(transaction, status, product); + if (qtTransaction->thread() != backend->thread()) { + qtTransaction->moveToThread(backend->thread()); + qtTransaction->setParent(backend); + } + [registeredTransactions addObject:transaction]; + QMetaObject::invokeMethod(backend, "registerTransaction", Qt::AutoConnection, Q_ARG(QMacInAppPurchaseTransaction*, qtTransaction)); + } + } + + //Remove registeredTransactions from pendingTransactions + [pendingTransactions removeObjectsInArray:registeredTransactions]; +} + + +//SKProductsRequestDelegate +-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response +{ + NSArray *products = response.products; + SKProduct *product = [products count] == 1 ? [[products firstObject] retain] : nil; + + if (product == nil) { + //Invalid product ID + NSString *invalidId = [response.invalidProductIdentifiers firstObject]; + QMetaObject::invokeMethod(backend, "registerQueryFailure", Qt::AutoConnection, Q_ARG(QString, QString::fromNSString(invalidId))); + } else { + //Valid product query + //Create a QMacInAppPurchaseProduct + QMacInAppPurchaseProduct *validProduct = new QMacInAppPurchaseProduct(product, backend->productTypeForProductId(QString::fromNSString([product productIdentifier]))); + if (validProduct->thread() != backend->thread()) { + validProduct->moveToThread(backend->thread()); + validProduct->setParent(backend); + } + QMetaObject::invokeMethod(backend, "registerProduct", Qt::AutoConnection, Q_ARG(QMacInAppPurchaseProduct*, validProduct)); + } + + [request release]; +} + ++(QInAppTransaction::TransactionStatus)statusFromTransaction:(SKPaymentTransaction *)transaction +{ + QInAppTransaction::TransactionStatus status; + switch (transaction.transactionState) { + case SKPaymentTransactionStatePurchasing: + //Ignore the purchasing state as it's not really a transaction + //And its important that it doesn't need to be finalized as + //Calling finishTransaction: on a transaction that is + //in the SKPaymentTransactionStatePurchasing state throws an exception + status = QInAppTransaction::Unknown; + break; + case SKPaymentTransactionStatePurchased: + status = QInAppTransaction::PurchaseApproved; + break; + case SKPaymentTransactionStateFailed: + status = QInAppTransaction::PurchaseFailed; + break; + case SKPaymentTransactionStateRestored: + status = QInAppTransaction::PurchaseRestored; + break; + default: + status = QInAppTransaction::Unknown; + break; + } + return status; +} + +//SKPaymentTransactionObserver +- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions +{ + Q_UNUSED(queue); + for (SKPaymentTransaction *transaction in transactions) { + //Create QMacInAppPurchaseTransaction + QInAppTransaction::TransactionStatus status = [InAppPurchaseManager statusFromTransaction:transaction]; + + if (status == QInAppTransaction::Unknown) + continue; + + QMacInAppPurchaseProduct *product = backend->registeredProductForProductId(QString::fromNSString(transaction.payment.productIdentifier)); + + if (product) { + //It is possible that the product doesn't exist yet (because of previous restores). + QMacInAppPurchaseTransaction *qtTransaction = new QMacInAppPurchaseTransaction(transaction, status, product); + if (qtTransaction->thread() != backend->thread()) { + qtTransaction->moveToThread(backend->thread()); + qtTransaction->setParent(backend); + } + QMetaObject::invokeMethod(backend, "registerTransaction", Qt::AutoConnection, Q_ARG(QMacInAppPurchaseTransaction*, qtTransaction)); + } else { + //Add the transaction to the pending transactions list + [pendingTransactions addObject:transaction]; + } + } +} + +@end + + +QT_BEGIN_NAMESPACE + +QMacInAppPurchaseBackend::QMacInAppPurchaseBackend(QObject *parent) + : QInAppPurchaseBackend(parent) + , m_iapManager(0) +{ +} + +QMacInAppPurchaseBackend::~QMacInAppPurchaseBackend() +{ + [m_iapManager release]; +} + +void QMacInAppPurchaseBackend::initialize() +{ + m_iapManager = [[InAppPurchaseManager alloc] initWithBackend:this]; + emit QInAppPurchaseBackend::ready(); +} + +bool QMacInAppPurchaseBackend::isReady() const +{ + if (m_iapManager) + return true; + return false; +} + +void QMacInAppPurchaseBackend::queryProduct(QInAppProduct::ProductType productType, const QString &identifier) +{ + Q_UNUSED(productType) + + if (m_productTypeForPendingId.contains(identifier)) { + qWarning("Product query already pending for %s", qPrintable(identifier)); + return; + } + + m_productTypeForPendingId[identifier] = productType; + + [m_iapManager requestProductData:(identifier.toNSString())]; +} + +void QMacInAppPurchaseBackend::restorePurchases() +{ + [[SKPaymentQueue defaultQueue] restoreCompletedTransactions]; +} + +void QMacInAppPurchaseBackend::setPlatformProperty(const QString &propertyName, const QString &value) +{ + Q_UNUSED(propertyName); + Q_UNUSED(value); +} + +void QMacInAppPurchaseBackend::registerProduct(QMacInAppPurchaseProduct *product) +{ + QHash::iterator it = m_productTypeForPendingId.find(product->identifier()); + Q_ASSERT(it != m_productTypeForPendingId.end()); + + m_registeredProductForId[product->identifier()] = product; + emit productQueryDone(product); + m_productTypeForPendingId.erase(it); + [m_iapManager processPendingTransactions]; +} + +void QMacInAppPurchaseBackend::registerQueryFailure(const QString &productId) +{ + QHash::iterator it = m_productTypeForPendingId.find(productId); + Q_ASSERT(it != m_productTypeForPendingId.end()); + + emit QInAppPurchaseBackend::productQueryFailed(it.value(), it.key()); + m_productTypeForPendingId.erase(it); +} + +void QMacInAppPurchaseBackend::registerTransaction(QMacInAppPurchaseTransaction *transaction) +{ + emit QInAppPurchaseBackend::transactionReady(transaction); +} + +QInAppProduct::ProductType QMacInAppPurchaseBackend::productTypeForProductId(const QString &productId) +{ + return m_productTypeForPendingId[productId]; +} + +QMacInAppPurchaseProduct *QMacInAppPurchaseBackend::registeredProductForProductId(const QString &productId) +{ + return m_registeredProductForId[productId]; +} + +QT_END_NAMESPACE + +#include "moc_qmacinapppurchasebackend_p.cpp" diff --git a/src/purchasing/inapppurchase/mac/qmacinapppurchasebackend_p.h b/src/purchasing/inapppurchase/mac/qmacinapppurchasebackend_p.h new file mode 100644 index 0000000..474b35a --- /dev/null +++ b/src/purchasing/inapppurchase/mac/qmacinapppurchasebackend_p.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Purchasing module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3-COMM$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMACINAPPPURCHASEBACKEND_P_H +#define QMACINAPPPURCHASEBACKEND_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qinapppurchasebackend_p.h" +#include "qinappproduct.h" +#include "qinapptransaction.h" + +#include + +Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(InAppPurchaseManager)); + +QT_BEGIN_NAMESPACE + +class QMacInAppPurchaseProduct; +class QMacInAppPurchaseTransaction; + +class QMacInAppPurchaseBackend : public QInAppPurchaseBackend +{ + Q_OBJECT +public: + QMacInAppPurchaseBackend(QObject *parent = 0); + ~QMacInAppPurchaseBackend(); + + void initialize(); + bool isReady() const; + void queryProduct(QInAppProduct::ProductType productType, const QString &identifier); + void restorePurchases(); + void setPlatformProperty(const QString &propertyName, const QString &value); + + //Called by InAppPurchaseManager + Q_INVOKABLE void registerProduct(QMacInAppPurchaseProduct *product); + Q_INVOKABLE void registerQueryFailure(const QString &productId); + Q_INVOKABLE void registerTransaction(QMacInAppPurchaseTransaction *transaction); + QInAppProduct::ProductType productTypeForProductId(const QString &productId); + QMacInAppPurchaseProduct *registeredProductForProductId(const QString &productId); + +private: + QT_MANGLE_NAMESPACE(InAppPurchaseManager) *m_iapManager; + QHash m_productTypeForPendingId; + QHash m_registeredProductForId; +}; + +#endif // QMACINAPPPURCHASEBACKEND_P_H + +QT_END_NAMESPACE diff --git a/src/purchasing/inapppurchase/mac/qmacinapppurchaseproduct.mm b/src/purchasing/inapppurchase/mac/qmacinapppurchaseproduct.mm new file mode 100644 index 0000000..170305d --- /dev/null +++ b/src/purchasing/inapppurchase/mac/qmacinapppurchaseproduct.mm @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Purchasing module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3-COMM$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmacinapppurchaseproduct_p.h" +#include "qmacinapppurchasebackend_p.h" + +#import + +//Use a Catagory to add a localizedPrice method to SKProduct +@interface SKProduct (QT_MANGLE_NAMESPACE(LocalizedPrice)) + +@property (nonatomic, readonly) NSString *localizedPrice; + +@end + +@implementation SKProduct (QT_MANGLE_NAMESPACE(LocalizedPrice)) + +- (NSString *)localizedPrice +{ + NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; + [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4]; + [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; + [numberFormatter setLocale:self.priceLocale]; + NSString *formattedString = [numberFormatter stringFromNumber:self.price]; + [numberFormatter release]; + return formattedString; +} + +@end + +QT_BEGIN_NAMESPACE + +QMacInAppPurchaseProduct::QMacInAppPurchaseProduct(SKProduct *product, + ProductType productType, + QMacInAppPurchaseBackend *backend) + : QInAppProduct(QString::fromNSString([product localizedPrice]), + QString::fromNSString([product localizedTitle]), + QString::fromNSString([product localizedDescription]), + productType, + QString::fromNSString([product productIdentifier]), + backend) + , m_nativeProduct(product) +{ +} + +void QMacInAppPurchaseProduct::purchase() +{ + SKPayment *payment = [SKPayment paymentWithProduct:m_nativeProduct]; + [[SKPaymentQueue defaultQueue] addPayment:payment]; +} + +QT_END_NAMESPACE + +#include "moc_qmacinapppurchaseproduct_p.cpp" diff --git a/src/purchasing/inapppurchase/mac/qmacinapppurchaseproduct_p.h b/src/purchasing/inapppurchase/mac/qmacinapppurchaseproduct_p.h new file mode 100644 index 0000000..3d838f0 --- /dev/null +++ b/src/purchasing/inapppurchase/mac/qmacinapppurchaseproduct_p.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Purchasing module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3-COMM$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMACINAPPPURCHASEPRODUCT_P_H +#define QMACINAPPPURCHASEPRODUCT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qinappproduct.h" + +@class SKProduct; + +QT_BEGIN_NAMESPACE + +class QMacInAppPurchaseBackend; + +class QMacInAppPurchaseProduct : public QInAppProduct +{ + Q_OBJECT +public: + explicit QMacInAppPurchaseProduct(SKProduct *product, + ProductType productType, + QMacInAppPurchaseBackend *backend = 0); + void purchase(); + +private: + SKProduct *m_nativeProduct; +}; + +Q_DECLARE_METATYPE(QMacInAppPurchaseProduct*) + +QT_END_NAMESPACE + +#endif // QMACINAPPPURCHASEPRODUCT_P_H diff --git a/src/purchasing/inapppurchase/mac/qmacinapppurchasetransaction.mm b/src/purchasing/inapppurchase/mac/qmacinapppurchasetransaction.mm new file mode 100644 index 0000000..04b7fee --- /dev/null +++ b/src/purchasing/inapppurchase/mac/qmacinapppurchasetransaction.mm @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Purchasing module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3-COMM$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmacinapppurchasetransaction_p.h" +#include "qmacinapppurchasebackend_p.h" + +#import + +QT_BEGIN_NAMESPACE + +QMacInAppPurchaseTransaction::QMacInAppPurchaseTransaction(SKPaymentTransaction *transaction, + const TransactionStatus status, + QInAppProduct *product, + QMacInAppPurchaseBackend *backend) + : QInAppTransaction(status, product, backend) + , m_nativeTransaction(transaction) + , m_failureReason(NoFailure) +{ + if (status == PurchaseFailed) { + m_failureReason = ErrorOccurred; + switch (m_nativeTransaction.error.code) { + case SKErrorClientInvalid: + m_errorString = QStringLiteral("Client Invalid"); + break; + case SKErrorPaymentCancelled: + m_errorString = QStringLiteral("Payment Cancelled"); + m_failureReason = CanceledByUser; + break; + case SKErrorPaymentInvalid: + m_errorString = QStringLiteral("Payment Invalid"); + break; + case SKErrorPaymentNotAllowed: + m_errorString = QStringLiteral("Payment Not Allowed"); + break; +#ifdef Q_OS_IOS + case SKErrorStoreProductNotAvailable: + m_errorString = QStringLiteral("Store Product Not Available"); + break; +#endif + case SKErrorUnknown: + default: + m_errorString = QStringLiteral("Unknown"); + } + } +} + +void QMacInAppPurchaseTransaction::finalize() +{ + [[SKPaymentQueue defaultQueue] finishTransaction:m_nativeTransaction]; +} + +QString QMacInAppPurchaseTransaction::orderId() const +{ + return QString::fromNSString(m_nativeTransaction.transactionIdentifier); +} + +QInAppTransaction::FailureReason QMacInAppPurchaseTransaction::failureReason() const +{ + return m_failureReason; +} + +QString QMacInAppPurchaseTransaction::errorString() const +{ + return m_errorString; +} + +QDateTime QMacInAppPurchaseTransaction::timestamp() const +{ + //Get time in seconds since 1970 + double timeInterval = [[m_nativeTransaction transactionDate] timeIntervalSince1970]; + return QDateTime::fromMSecsSinceEpoch(qint64(timeInterval * 1000)); +} + +QT_END_NAMESPACE + +#include "moc_qmacinapppurchasetransaction_p.cpp" diff --git a/src/purchasing/inapppurchase/mac/qmacinapppurchasetransaction_p.h b/src/purchasing/inapppurchase/mac/qmacinapppurchasetransaction_p.h new file mode 100644 index 0000000..6e905e9 --- /dev/null +++ b/src/purchasing/inapppurchase/mac/qmacinapppurchasetransaction_p.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Purchasing module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3-COMM$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMACINAPPTRANSACTION_P_H +#define QMACINAPPTRANSACTION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qinapptransaction.h" +#include + +@class SKPaymentTransaction; + +QT_BEGIN_NAMESPACE + +class QMacInAppPurchaseBackend; + +class QMacInAppPurchaseTransaction : public QInAppTransaction +{ + Q_OBJECT +public: + QMacInAppPurchaseTransaction(SKPaymentTransaction *transaction, + const TransactionStatus status, + QInAppProduct *product, + QMacInAppPurchaseBackend *backend = 0); + + void finalize(); + QString orderId() const; + FailureReason failureReason() const; + QString errorString() const; + QDateTime timestamp() const; + +private: + SKPaymentTransaction *m_nativeTransaction; + QString m_errorString; + FailureReason m_failureReason; +}; + +Q_DECLARE_METATYPE(QMacInAppPurchaseTransaction*) + +QT_END_NAMESPACE + +#endif // QMACINAPPTRANSACTION_P_H diff --git a/src/purchasing/inapppurchase/qinapppurchasebackendfactory.cpp b/src/purchasing/inapppurchase/qinapppurchasebackendfactory.cpp index be2ad60..757b78a 100644 --- a/src/purchasing/inapppurchase/qinapppurchasebackendfactory.cpp +++ b/src/purchasing/inapppurchase/qinapppurchasebackendfactory.cpp @@ -30,8 +30,8 @@ #if defined(Q_OS_ANDROID) # include "qandroidinapppurchasebackend_p.h" -#elif defined(Q_OS_IOS) -# include "qiosinapppurchasebackend_p.h" +#elif defined(Q_OS_MAC) +# include "qmacinapppurchasebackend_p.h" #else # include "qinapppurchasebackend_p.h" #endif @@ -42,8 +42,8 @@ QInAppPurchaseBackend *QInAppPurchaseBackendFactory::create() { #if defined(Q_OS_ANDROID) return new QAndroidInAppPurchaseBackend; -#elif defined (Q_OS_IOS) - return new QIosInAppPurchaseBackend; +#elif defined (Q_OS_MAC) + return new QMacInAppPurchaseBackend; #else return new QInAppPurchaseBackend; #endif diff --git a/src/purchasing/inapppurchase/qinappstore.cpp b/src/purchasing/inapppurchase/qinappstore.cpp index 3ee797e..36ae021 100644 --- a/src/purchasing/inapppurchase/qinappstore.cpp +++ b/src/purchasing/inapppurchase/qinappstore.cpp @@ -136,7 +136,7 @@ QT_BEGIN_NAMESPACE \note This depends on support for this functionality in the remote store. If the remote store does not save the purchase state of unlockable products for you, the call will yield no transactionReady() signals, as if no products have - been purchased. Both the Android and iOS backends support restoring unlockable + been purchased. Both the Android and OS X / iOS backends support restoring unlockable products. */ diff --git a/tests/auto/purchasing/qinappstore/tst_qinappstore.cpp b/tests/auto/purchasing/qinappstore/tst_qinappstore.cpp index e0398ad..d2efd0d 100644 --- a/tests/auto/purchasing/qinappstore/tst_qinappstore.cpp +++ b/tests/auto/purchasing/qinappstore/tst_qinappstore.cpp @@ -73,7 +73,7 @@ void tst_QInAppStore::registerUnknownProduct() store.registerProduct(QInAppProduct::Consumable, QStringLiteral("unknownConsumable")); store.registerProduct(QInAppProduct::Unlockable, QStringLiteral("unknownUnlockable")); -#if !defined(Q_OS_IOS) && !defined(Q_OS_ANDROID) +#if !defined(Q_OS_MAC) && !defined(Q_OS_ANDROID) QEXPECT_FAIL("", "Qt Purchasing not implemented on this platform.", Abort); #endif -- cgit v1.2.3