summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2016-10-28 06:59:28 +0200
committerLiang Qi <liang.qi@qt.io>2016-10-28 06:59:36 +0200
commit68ca35302901a5b9e52b3dd068aa8d34ccea4f42 (patch)
treeb11be19fee497b24f5ed774baee133e187aec243
parent2adefcb818a33a51a1639f37b907ee67dfbe6077 (diff)
parentcdbf96e2442285562d7e55e4e7072f44a72200c0 (diff)
Merge remote-tracking branch 'origin/5.8' into dev
-rw-r--r--src/imports/purchasing/inapppurchase.cpp2
-rw-r--r--src/purchasing/inapppurchase/winrt/qwinrtinapppurchasebackend.cpp112
-rw-r--r--src/purchasing/inapppurchase/winrt/qwinrtinapppurchasebackend_p.h32
-rw-r--r--src/purchasing/inapppurchase/winrt/qwinrtinapptransaction.cpp12
-rw-r--r--src/purchasing/inapppurchase/winrt/qwinrtinapptransaction_p.h3
-rw-r--r--tests/auto/purchasing/qinappstore/tst_qinappstore.cpp7
6 files changed, 139 insertions, 29 deletions
diff --git a/src/imports/purchasing/inapppurchase.cpp b/src/imports/purchasing/inapppurchase.cpp
index f20fff9..b0b3e3a 100644
--- a/src/imports/purchasing/inapppurchase.cpp
+++ b/src/imports/purchasing/inapppurchase.cpp
@@ -39,7 +39,7 @@ QT_BEGIN_NAMESPACE
class QInAppPurchaseModule : public QQmlExtensionPlugin
{
Q_OBJECT
- Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0")
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
void registerTypes(const char *uri)
{
diff --git a/src/purchasing/inapppurchase/winrt/qwinrtinapppurchasebackend.cpp b/src/purchasing/inapppurchase/winrt/qwinrtinapppurchasebackend.cpp
index 396123d..37ed8a9 100644
--- a/src/purchasing/inapppurchase/winrt/qwinrtinapppurchasebackend.cpp
+++ b/src/purchasing/inapppurchase/winrt/qwinrtinapppurchasebackend.cpp
@@ -61,6 +61,13 @@ Q_LOGGING_CATEGORY(lcPurchasingBackend, "qt.purchasing.backend")
const QString qt_win_app_identifier = QLatin1String("app");
+inline QString hStringToQString(const HString &h)
+{
+ unsigned int length;
+ const wchar_t* raw = h.GetRawBuffer(&length);
+ return QString::fromWCharArray(raw, length);
+}
+
class QWinRTAppBridge {
public:
HRESULT activate();
@@ -253,15 +260,13 @@ inline bool compareProductTypes(QInAppProduct::ProductType qtType, ProductType n
return false;
}
-QWinRTInAppTransaction* createTransaction(AsyncStatus status,
- QWinRTInAppProduct *product,
- QWinRTInAppPurchaseBackend *backend)
+void QWinRTInAppPurchaseBackend::createTransactionDelayed(qt_WinRTTransactionData data)
{
- QInAppTransaction::TransactionStatus qStatus = (status == AsyncStatus::Completed) ?
+ QInAppTransaction::TransactionStatus qStatus = (data.status == AsyncStatus::Completed) ?
QInAppTransaction::PurchaseApproved : QInAppTransaction::PurchaseFailed;
QInAppTransaction::FailureReason reason;
- switch (status) {
+ switch (data.status) {
case AsyncStatus::Completed:
reason = QInAppTransaction::NoFailure;
break;
@@ -274,8 +279,11 @@ QWinRTInAppTransaction* createTransaction(AsyncStatus status,
break;
}
- auto transaction = new QWinRTInAppTransaction(qStatus, product, reason, backend);
- return transaction;
+ auto transaction = new QWinRTInAppTransaction(qStatus, data.product, reason, data.receipt, this);
+ transaction->m_purchaseResults = data.purchaseResults;
+ emit transactionReady(transaction);
+
+ return;
}
class QWinRTInAppPurchaseBackendPrivate
@@ -302,6 +310,9 @@ QWinRTInAppPurchaseBackend::QWinRTInAppPurchaseBackend(QObject *parent)
: QInAppPurchaseBackend(parent)
{
d_ptr.reset(new QWinRTInAppPurchaseBackendPrivate(this));
+
+ qRegisterMetaType<qt_WinRTTransactionData>("TransactionData");
+
qCDebug(lcPurchasingBackend) << __FUNCTION__;
}
@@ -341,6 +352,16 @@ bool QWinRTInAppPurchaseBackend::isReady() const
return !d->m_waitingForList && !d->nativeProducts.isEmpty();
}
+inline QString createStringForSubReceipt(const QXmlStreamReader &reader)
+{
+ QString result;
+ QXmlStreamWriter writer(&result);
+ writer.writeStartDocument();
+ writer.writeCurrentToken(reader);
+ writer.writeEndDocument();
+ return result;
+}
+
void QWinRTInAppPurchaseBackend::restorePurchases()
{
qCDebug(lcPurchasingBackend) << __FUNCTION__;
@@ -363,8 +384,7 @@ void QWinRTInAppPurchaseBackend::restorePurchases()
return;
}
- quint32 length;
- QString parse = QString::fromWCharArray(receipt.GetRawBuffer(&length));
+ const QString parse = hStringToQString(receipt);
QXmlStreamReader reader(parse);
while (reader.readNextStartElement()) {
@@ -382,6 +402,8 @@ void QWinRTInAppPurchaseBackend::restorePurchases()
return;
}
+ const QString appReceipt = createStringForSubReceipt(reader);
+
while (!reader.atEnd()) {
reader.readNext();
if (reader.attributes().hasAttribute(QLatin1String("ProductId"))) {
@@ -395,9 +417,13 @@ void QWinRTInAppPurchaseBackend::restorePurchases()
continue;
}
+
+ const QString receipt = createStringForSubReceipt(reader);
+
auto transaction = new QWinRTInAppTransaction(QInAppTransaction::PurchaseRestored,
product,
QInAppTransaction::NoFailure,
+ receipt,
this);
emit transactionReady(transaction);
@@ -418,10 +444,16 @@ void QWinRTInAppPurchaseBackend::restorePurchases()
qCDebug(lcPurchasingBackend) << "Restoring app product";
QInAppProduct *product = store()->registeredProduct(qt_win_app_identifier);
+ // App is special and needs explicit registration
+ if (!product) {
+ queryProduct(QInAppProduct::Unlockable, qt_win_app_identifier);
+ product = store()->registeredProduct(qt_win_app_identifier);
+ }
auto transaction = new QWinRTInAppTransaction(QInAppTransaction::PurchaseRestored,
product,
QInAppTransaction::NoFailure,
+ appReceipt,
this);
emit transactionReady(transaction);
}
@@ -455,7 +487,7 @@ void QWinRTInAppPurchaseBackend::restorePurchases()
}
quint32 length;
- QString receipt = QString::fromWCharArray(receiptString.GetRawBuffer(&length));
+ const QString receipt = hStringToQString(receiptString);
qDebug() << "Received receipt:" << receipt;
// Create new transaction with status == Restored and emit
@@ -496,10 +528,9 @@ void QWinRTInAppPurchaseBackend::queryProduct(QInAppProduct::ProductType product
return;
}
- quint32 length;
NativeProductInfo *cachedInfo = d->nativeProducts.value(identifier);
- QString price = QString::fromWCharArray(cachedInfo->formatPrice.GetRawBuffer(&length));
- QString name = QString::fromWCharArray(cachedInfo->productName.GetRawBuffer(&length));
+ const QString price = hStringToQString(cachedInfo->formatPrice);
+ const QString name = hStringToQString(cachedInfo->productName);
QWinRTInAppProduct *appProduct = new QWinRTInAppProduct(this,
price,
name,
@@ -527,12 +558,23 @@ void QWinRTInAppPurchaseBackend::purchaseProduct(QWinRTInAppProduct *product)
hr = QEventDispatcherWinRT::runOnXamlThread([d, product, this]() {
HRESULT hr;
ComPtr<IAsyncOperation<HSTRING>> appOp;
- hr = d->m_bridge.RequestAppPurchaseAsync(false, appOp);
+ hr = d->m_bridge.RequestAppPurchaseAsync(true, appOp);
Q_ASSERT_SUCCEEDED(hr);
- auto purchaseCallback = Callback<IAsyncOperationCompletedHandler<HSTRING>>([d, product, this](IAsyncOperation<HSTRING> *, AsyncStatus status)
+ auto purchaseCallback = Callback<IAsyncOperationCompletedHandler<HSTRING>>([d, product, this](IAsyncOperation<HSTRING> *op, AsyncStatus status)
{
- auto transaction = createTransaction(status, product, this);
- emit transactionReady(transaction);
+ HString receiptH;
+ QString receiptQ;
+ HRESULT hr;
+ hr = op->GetResults(receiptH.GetAddressOf());
+ if (SUCCEEDED(hr))
+ receiptQ = hStringToQString(receiptH);
+ else
+ qWarning("Could not receive transaction receipt.");
+
+ qt_WinRTTransactionData tData(status, product, receiptQ);
+ QMetaObject::invokeMethod(this, "createTransactionDelayed", Qt::QueuedConnection,
+ Q_ARG(qt_WinRTTransactionData, tData));
+
return S_OK;
});
hr = appOp->put_Completed(purchaseCallback.Get());
@@ -543,12 +585,23 @@ void QWinRTInAppPurchaseBackend::purchaseProduct(QWinRTInAppProduct *product)
hr = QEventDispatcherWinRT::runOnXamlThread([d, product, &productId, this]() {
ComPtr<IAsyncOperation<HSTRING>> purchaseOp;
HRESULT hr;
- hr = d->m_bridge.RequestProductPurchaseAsync(productId.Get(), false, purchaseOp);
+ hr = d->m_bridge.RequestProductPurchaseAsync(productId.Get(), true, purchaseOp);
Q_ASSERT_SUCCEEDED(hr);
- auto purchaseCallback = Callback<IAsyncOperationCompletedHandler<HSTRING>>([d, product, this](IAsyncOperation<HSTRING> *, AsyncStatus status)
+ auto purchaseCallback = Callback<IAsyncOperationCompletedHandler<HSTRING>>([d, product, this](IAsyncOperation<HSTRING> *op, AsyncStatus status)
{
- auto transaction = createTransaction(status, product, this);
- emit transactionReady(transaction);
+ HString receiptH;
+ QString receiptQ;
+ HRESULT hr;
+ hr = op->GetResults(receiptH.GetAddressOf());
+ if (SUCCEEDED(hr))
+ receiptQ = hStringToQString(receiptH);
+ else
+ qWarning("Could not receive transaction receipt.");
+
+ qt_WinRTTransactionData tData(status, product, receiptQ);
+ QMetaObject::invokeMethod(this, "createTransactionDelayed", Qt::QueuedConnection,
+ Q_ARG(qt_WinRTTransactionData, tData));
+
return S_OK;
});
hr = purchaseOp->put_Completed(purchaseCallback.Get());
@@ -565,14 +618,23 @@ void QWinRTInAppPurchaseBackend::purchaseProduct(QWinRTInAppProduct *product)
auto purchaseCallback = Callback<IAsyncOperationCompletedHandler<PurchaseResults*>>([d, product, this](IAsyncOperation<PurchaseResults*> *op, AsyncStatus status)
{
- auto transaction = createTransaction(status, product, this);
+ ComPtr<IPurchaseResults> purchaseResults;
+ QString receiptQ;
if (status == AsyncStatus::Completed) {
HRESULT hr;
- hr = op->GetResults(&transaction->m_purchaseResults);
+ hr = op->GetResults(&purchaseResults);
+ Q_ASSERT_SUCCEEDED(hr);
+ HString receiptH;
+ hr = purchaseResults->get_ReceiptXml(receiptH.GetAddressOf());
Q_ASSERT_SUCCEEDED(hr);
+ receiptQ = hStringToQString(receiptH);
}
- emit transactionReady(transaction);
+
+ qt_WinRTTransactionData tData(status, product, receiptQ, purchaseResults);
+ QMetaObject::invokeMethod(this, "createTransactionDelayed", Qt::QueuedConnection,
+ Q_ARG(qt_WinRTTransactionData, tData));
+
return S_OK;
});
@@ -661,7 +723,7 @@ HRESULT QWinRTInAppPurchaseBackendPrivate::onListingInformation(IAsyncOperation<
ComPtr<IProductListing> value;
hr = currentItem->get_Key(nativeKey.GetAddressOf());
Q_ASSERT_SUCCEEDED(hr);
- productKey = QString::fromWCharArray(nativeKey.GetRawBuffer(nullptr));
+ productKey = hStringToQString(nativeKey);
qCDebug(lcPurchasingBackend) << "ProductKey:" << productKey;
hr = currentItem->get_Value(&value);
Q_ASSERT_SUCCEEDED(hr);
diff --git a/src/purchasing/inapppurchase/winrt/qwinrtinapppurchasebackend_p.h b/src/purchasing/inapppurchase/winrt/qwinrtinapppurchasebackend_p.h
index ce83b79..af48908 100644
--- a/src/purchasing/inapppurchase/winrt/qwinrtinapppurchasebackend_p.h
+++ b/src/purchasing/inapppurchase/winrt/qwinrtinapppurchasebackend_p.h
@@ -44,11 +44,41 @@
#include "qinappproduct.h"
#include "qinapptransaction.h"
+#include <Windows.ApplicationModel.store.h>
+#include <wrl.h>
+
+namespace ABI {
+ namespace Windows {
+ namespace Foundation {
+ enum class AsyncStatus;
+ }
+ }
+}
+
QT_BEGIN_NAMESPACE
class QWinRTInAppProduct;
class QWinRTInAppPurchaseBackendPrivate;
class QWinRTInAppTransaction;
+class QWinRTInAppPurchaseBackend;
+
+struct qt_WinRTTransactionData
+{
+ qt_WinRTTransactionData() { }
+ explicit qt_WinRTTransactionData(ABI::Windows::Foundation::AsyncStatus s,
+ QWinRTInAppProduct *p,
+ const QString &r,
+ Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::Store::IPurchaseResults> pRes = Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::Store::IPurchaseResults>())
+ : status(s)
+ , product(p)
+ , receipt(r)
+ , purchaseResults(pRes)
+ { }
+ ABI::Windows::Foundation::AsyncStatus status;
+ QWinRTInAppProduct *product;
+ QString receipt;
+ Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::Store::IPurchaseResults> purchaseResults;
+};
class QWinRTInAppPurchaseBackend : public QInAppPurchaseBackend
{
@@ -68,6 +98,8 @@ public:
void purchaseProduct(QWinRTInAppProduct *product);
void fulfillConsumable(QWinRTInAppTransaction *transaction);
+public slots:
+ void createTransactionDelayed(qt_WinRTTransactionData data);
private:
QScopedPointer<QWinRTInAppPurchaseBackendPrivate> d_ptr;
Q_DECLARE_PRIVATE(QWinRTInAppPurchaseBackend)
diff --git a/src/purchasing/inapppurchase/winrt/qwinrtinapptransaction.cpp b/src/purchasing/inapppurchase/winrt/qwinrtinapptransaction.cpp
index 5e83530..212837a 100644
--- a/src/purchasing/inapppurchase/winrt/qwinrtinapptransaction.cpp
+++ b/src/purchasing/inapppurchase/winrt/qwinrtinapptransaction.cpp
@@ -38,8 +38,9 @@ Q_LOGGING_CATEGORY(lcPurchasingTransaction, "qt.purchasing.transaction")
QWinRTInAppTransaction::QWinRTInAppTransaction(TransactionStatus status,
QInAppProduct *product, FailureReason reason,
- QObject *parent)
+ const QString &receipt, QObject *parent)
: QInAppTransaction(status, product, parent)
+ , m_receipt(receipt)
, m_failureReason(reason)
{
qCDebug(lcPurchasingTransaction) << __FUNCTION__;
@@ -56,4 +57,13 @@ void QWinRTInAppTransaction::finalize()
deleteLater();
}
+QString QWinRTInAppTransaction::platformProperty(const QString &propertyName) const
+{
+ qCDebug(lcPurchasingTransaction) << __FUNCTION__ << propertyName;
+
+ if (propertyName == QLatin1String("receipt"))
+ return m_receipt;
+ return QString();
+}
+
QT_END_NAMESPACE
diff --git a/src/purchasing/inapppurchase/winrt/qwinrtinapptransaction_p.h b/src/purchasing/inapppurchase/winrt/qwinrtinapptransaction_p.h
index 4a1a752..34cc3b9 100644
--- a/src/purchasing/inapppurchase/winrt/qwinrtinapptransaction_p.h
+++ b/src/purchasing/inapppurchase/winrt/qwinrtinapptransaction_p.h
@@ -58,13 +58,16 @@ public:
explicit QWinRTInAppTransaction(TransactionStatus status,
QInAppProduct *product,
FailureReason reason,
+ const QString &receipt,
QObject *parent = Q_NULLPTR);
FailureReason failureReason() const override { return m_failureReason; }
void finalize() override;
+ QString platformProperty(const QString &propertyName) const override;
Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::Store::IPurchaseResults> m_purchaseResults;
+ QString m_receipt;
private:
QWinRTInAppPurchaseBackend *m_backend;
FailureReason m_failureReason;
diff --git a/tests/auto/purchasing/qinappstore/tst_qinappstore.cpp b/tests/auto/purchasing/qinappstore/tst_qinappstore.cpp
index d2efd0d..6411fed 100644
--- a/tests/auto/purchasing/qinappstore/tst_qinappstore.cpp
+++ b/tests/auto/purchasing/qinappstore/tst_qinappstore.cpp
@@ -73,11 +73,14 @@ void tst_QInAppStore::registerUnknownProduct()
store.registerProduct(QInAppProduct::Consumable, QStringLiteral("unknownConsumable"));
store.registerProduct(QInAppProduct::Unlockable, QStringLiteral("unknownUnlockable"));
-#if !defined(Q_OS_MAC) && !defined(Q_OS_ANDROID)
+//The backend is implemented on iOS, macOS, WinRT and Android, for others we expect failure.
+#if !(defined(Q_OS_DARWIN) && !defined(Q_OS_WATCHOS)) && !defined(Q_OS_ANDROID) && !defined(Q_OS_WINRT)
QEXPECT_FAIL("", "Qt Purchasing not implemented on this platform.", Abort);
#endif
- QTRY_COMPARE(receiver.unknownProducts.size(), 2);
+ //Due to network overload or connectivity issues QTRY_COMPARE sometimes fails with timeout,
+ //that's why we need to increase the value, since it's better to wait than to fail.
+ QTRY_COMPARE_WITH_TIMEOUT(receiver.unknownProducts.size(), 2, 10000);
QCOMPARE(receiver.registeredProducts.size(), 0);
QCOMPARE(receiver.readyTransactions.size(), 0);