Turn InAppPurchase into an EventEmitter
This commit is contained in:
parent
400bfb3c5a
commit
ac6f895f64
8 changed files with 123 additions and 90 deletions
|
@ -15,47 +15,92 @@
|
|||
|
||||
namespace mate {
|
||||
|
||||
v8::Local<v8::Value> Converter<in_app_purchase::Payment>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const in_app_purchase::Payment& payment) {
|
||||
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||
dict.SetHidden("simple", true);
|
||||
dict.Set("productIdentifier", payment.productIdentifier);
|
||||
dict.Set("quantity", payment.quantity);
|
||||
return dict.GetHandle();
|
||||
}
|
||||
template <>
|
||||
struct Converter<in_app_purchase::Payment> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const in_app_purchase::Payment& payment) {
|
||||
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||
dict.SetHidden("simple", true);
|
||||
dict.Set("productIdentifier", payment.productIdentifier);
|
||||
dict.Set("quantity", payment.quantity);
|
||||
return dict.GetHandle();
|
||||
}
|
||||
};
|
||||
|
||||
v8::Local<v8::Value> Converter<in_app_purchase::Transaction>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const in_app_purchase::Transaction& transaction) {
|
||||
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||
dict.SetHidden("simple", true);
|
||||
dict.Set("transactionIdentifier", transaction.transactionIdentifier);
|
||||
dict.Set("transactionDate", transaction.transactionDate);
|
||||
dict.Set("originalTransactionIdentifier",
|
||||
transaction.originalTransactionIdentifier);
|
||||
dict.Set("transactionState", transaction.transactionState);
|
||||
template <>
|
||||
struct Converter<in_app_purchase::Transaction> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const in_app_purchase::Transaction& val) {
|
||||
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||
dict.SetHidden("simple", true);
|
||||
dict.Set("transactionIdentifier", val.transactionIdentifier);
|
||||
dict.Set("transactionDate", val.transactionDate);
|
||||
dict.Set("originalTransactionIdentifier",
|
||||
val.originalTransactionIdentifier);
|
||||
dict.Set("transactionState", val.transactionState);
|
||||
dict.Set("errorCode", val.errorCode);
|
||||
dict.Set("errorMessage", val.errorMessage);
|
||||
return dict.GetHandle();
|
||||
}
|
||||
};
|
||||
|
||||
dict.Set("errorCode", transaction.errorCode);
|
||||
dict.Set("errorMessage", transaction.errorMessage);
|
||||
|
||||
return dict.GetHandle();
|
||||
}
|
||||
} // namespace mate
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
// static
|
||||
mate::Handle<InAppPurchase> InAppPurchase::Create(v8::Isolate* isolate) {
|
||||
return mate::CreateHandle(isolate, new InAppPurchase(isolate));
|
||||
}
|
||||
|
||||
// static
|
||||
void InAppPurchase::BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::FunctionTemplate> prototype) {
|
||||
prototype->SetClassName(mate::StringToV8(isolate, "InAppPurchase"));
|
||||
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
|
||||
.SetMethod("canMakePayments", &in_app_purchase::CanMakePayments)
|
||||
.SetMethod("getReceiptURL", &in_app_purchase::GetReceiptURL)
|
||||
.SetMethod("purchaseProduct", &InAppPurchase::PurchaseProduct)
|
||||
.SetMethod("addTransactionListener",
|
||||
&in_app_purchase::AddTransactionObserver);
|
||||
}
|
||||
|
||||
InAppPurchase::InAppPurchase(v8::Isolate* isolate) {
|
||||
Init(isolate);
|
||||
}
|
||||
|
||||
InAppPurchase::~InAppPurchase() {
|
||||
}
|
||||
|
||||
void InAppPurchase::PurchaseProduct(const std::string& product_id,
|
||||
mate::Arguments* args) {
|
||||
int quantity = 1;
|
||||
in_app_purchase::InAppPurchaseCallback callback;
|
||||
args->GetNext(&quantity);
|
||||
args->GetNext(&callback);
|
||||
in_app_purchase::PurchaseProduct(product_id, quantity, callback);
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
namespace {
|
||||
|
||||
using atom::api::InAppPurchase;
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports,
|
||||
v8::Local<v8::Value> unused,
|
||||
v8::Local<v8::Context> context,
|
||||
void* priv) {
|
||||
mate::Dictionary dict(context->GetIsolate(), exports);
|
||||
#if defined(OS_MACOSX)
|
||||
dict.SetMethod("canMakePayments", &in_app_purchase::CanMakePayments);
|
||||
dict.SetMethod("getReceiptURL", &in_app_purchase::GetReceiptURL);
|
||||
dict.SetMethod("purchaseProduct", &in_app_purchase::PurchaseProduct);
|
||||
dict.SetMethod("addTransactionListener",
|
||||
&in_app_purchase::AddTransactionObserver);
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
dict.Set("inAppPurchase", InAppPurchase::Create(isolate));
|
||||
dict.Set("InAppPurchase",
|
||||
InAppPurchase::GetConstructor(isolate)->GetFunction());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -7,30 +7,34 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/api/event_emitter.h"
|
||||
#include "atom/browser/mac/in_app_purchase.h"
|
||||
#include "atom/browser/mac/in_app_purchase_observer.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/handle.h"
|
||||
|
||||
namespace mate {
|
||||
namespace atom {
|
||||
|
||||
template <>
|
||||
struct Converter<in_app_purchase::Payment> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const in_app_purchase::Payment& val);
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
in_app_purchase::Payment* out);
|
||||
namespace api {
|
||||
|
||||
class InAppPurchase: public mate::EventEmitter<InAppPurchase> {
|
||||
public:
|
||||
static mate::Handle<InAppPurchase> Create(v8::Isolate* isolate);
|
||||
|
||||
static void BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::FunctionTemplate> prototype);
|
||||
|
||||
protected:
|
||||
explicit InAppPurchase(v8::Isolate* isolate);
|
||||
~InAppPurchase() override;
|
||||
|
||||
void PurchaseProduct(const std::string& product_id, mate::Arguments* args);
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(InAppPurchase);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<in_app_purchase::Transaction> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const in_app_purchase::Transaction& val);
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
in_app_purchase::Transaction* out);
|
||||
};
|
||||
} // namespace api
|
||||
|
||||
} // namespace mate
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_API_ATOM_API_IN_APP_PURCHASE_H_
|
||||
|
|
|
@ -22,7 +22,7 @@ bool CanMakePayments(void);
|
|||
std::string GetReceiptURL(void);
|
||||
|
||||
void PurchaseProduct(const std::string& productID,
|
||||
const int quantity,
|
||||
int quantity,
|
||||
const InAppPurchaseCallback& callback);
|
||||
|
||||
} // namespace in_app_purchase
|
||||
|
|
|
@ -146,9 +146,9 @@ std::string GetReceiptURL() {
|
|||
}
|
||||
|
||||
void PurchaseProduct(const std::string& productID,
|
||||
const int quantity,
|
||||
int quantity,
|
||||
const InAppPurchaseCallback& callback) {
|
||||
auto iap =
|
||||
auto* iap =
|
||||
[[InAppPurchase alloc] initWithCallback:callback quantity:quantity];
|
||||
|
||||
[iap purchaseProduct:base::SysUTF8ToNSString(productID)];
|
||||
|
|
|
@ -177,6 +177,8 @@
|
|||
namespace in_app_purchase {
|
||||
|
||||
void AddTransactionObserver(const InAppTransactionCallback& callback) {
|
||||
// This is leaked, but we should be fine since we don't have a way to remove
|
||||
// callback and the inAppPurchase module is never unloaded.
|
||||
[[InAppTransactionObserver alloc] initWithCallback:callback];
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
# inAppPurchase _macOS_
|
||||
|
||||
> In-App Purchase on Mac App Store.
|
||||
|
||||
Your application should add a listener before to purchase a product. If there are no listener attached to the queue, the payment queue does not synchronize its list of pending transactions with the Apple App Store.
|
||||
|
||||
## Methods
|
||||
## Methods
|
||||
|
||||
The `inAppPurchase` module has the following methods:
|
||||
|
||||
### `inAppPurchase.addTransactionListener(listener)`
|
||||
|
||||
* `listener` Function - Called when transactions are updated by the payment queue.
|
||||
* `listener` Function - Called when transactions are updated by the payment queue.
|
||||
* `payment` Object
|
||||
* `productIdentifier` String
|
||||
* `quantity` Integer
|
||||
|
@ -19,9 +21,11 @@ The `inAppPurchase` module has the following methods:
|
|||
* `transactionState` String - The transaction sate (`"SKPaymentTransactionStatePurchasing"`, `"SKPaymentTransactionStatePurchased"`, `"SKPaymentTransactionStateFailed"`, `"SKPaymentTransactionStateRestored"`, or `"SKPaymentTransactionStateDeferred"`)
|
||||
* `errorCode` Integer
|
||||
* `errorMessage` String
|
||||
|
||||
|
||||
Add a listener to transactions.
|
||||
|
||||
### `inAppPurchase.purchaseProduct(productID, quantity, callback)`
|
||||
|
||||
* `productID` String - The id of the product to purchase. (the id of `com.example.app.product1` is `product1`).
|
||||
* `quantity` Integer (optional) - The number of items the user wants to purchase.
|
||||
* `callback` Function (optional) - The callback called when the payment is added to the PaymentQueue. (You should add a listener with `inAppPurchase.addTransactionsListener` to get the transaction status).
|
||||
|
@ -33,4 +37,4 @@ Returns `true` if the user can make a payment and `false` otherwise.
|
|||
|
||||
### `inAppPurchase.getReceiptURL()`
|
||||
|
||||
Returns `String`, the path to the receipt.
|
||||
Returns `String`, the path to the receipt.
|
||||
|
|
|
@ -1,39 +1,10 @@
|
|||
'use strict'
|
||||
|
||||
const binding = process.atomBinding('in_app_purchase')
|
||||
const v8Util = process.atomBinding('v8_util')
|
||||
const {EventEmitter} = require('events')
|
||||
const {inAppPurchase, InAppPurchase} = process.atomBinding('in_app_purchase')
|
||||
|
||||
module.exports = {
|
||||
// inAppPurchase is an EventEmitter.
|
||||
Object.setPrototypeOf(InAppPurchase.prototype, EventEmitter.prototype)
|
||||
EventEmitter.call(inAppPurchase)
|
||||
|
||||
canMakePayments: function () {
|
||||
return binding.canMakePayments()
|
||||
},
|
||||
|
||||
getReceiptURL: function () {
|
||||
return binding.getReceiptURL()
|
||||
},
|
||||
|
||||
purchaseProduct: function (productID, quantity = 1, callback) {
|
||||
if (typeof productID !== 'string') {
|
||||
throw new TypeError('productID must be a string')
|
||||
}
|
||||
if (typeof quantity === 'function') {
|
||||
quantity = 1
|
||||
callback = quantity
|
||||
}
|
||||
return binding.purchaseProduct(productID, quantity, callback)
|
||||
},
|
||||
|
||||
addTransactionListener: function (callback) {
|
||||
if (typeof callback !== 'function') {
|
||||
throw new TypeError('callback must be a function')
|
||||
}
|
||||
return binding.addTransactionListener(callback)
|
||||
}
|
||||
}
|
||||
|
||||
// Mark standard asynchronous functions.
|
||||
v8Util.setHiddenValue(
|
||||
module.exports.purchaseProduct, 'asynchronous', true)
|
||||
v8Util.setHiddenValue(
|
||||
module.exports.addTransactionListener, 'asynchronous', true)
|
||||
module.exports = inAppPurchase
|
||||
|
|
|
@ -22,4 +22,11 @@ describe('inAppPurchase module', () => {
|
|||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('purchaseProduct() accepts optional arguments', (done) => {
|
||||
inAppPurchase.purchaseProduct('non-exist', () => {
|
||||
inAppPurchase.purchaseProduct('non-exist', 1)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue