diff --git a/docs/api/in-app-purchase.md b/docs/api/in-app-purchase.md index 1520a0ce3a927..38078ecf29dd7 100644 --- a/docs/api/in-app-purchase.md +++ b/docs/api/in-app-purchase.md @@ -21,10 +21,12 @@ Returns: The `inAppPurchase` module has the following methods: -### `inAppPurchase.purchaseProduct(productID[, quantity])` +### `inAppPurchase.purchaseProduct(productID[, opts])` -* `productID` string - The identifiers of the product to purchase. (The identifier of `com.example.app.product1` is `product1`). -* `quantity` Integer (optional) - The number of items the user wants to purchase. +* `productID` string +* `opts` Integer | Object (optional) - If specified as an integer, defines the quantity. + * `quantity` Integer (optional) - The number of items the user wants to purchase. + * `username` string (optional) - The string that associates the transaction with a user account on your service (applicationUsername). Returns `Promise` - Returns `true` if the product is valid and added to the payment queue. diff --git a/lib/browser/api/in-app-purchase.ts b/lib/browser/api/in-app-purchase.ts index e67fd44bf39ce..bb5f733710855 100644 --- a/lib/browser/api/in-app-purchase.ts +++ b/lib/browser/api/in-app-purchase.ts @@ -4,7 +4,12 @@ let _inAppPurchase; if (process.platform === 'darwin') { const { inAppPurchase } = process._linkedBinding('electron_browser_in_app_purchase'); - + const _purchase = inAppPurchase.purchaseProduct as (productID: string, quantity?: number, username?: string) => Promise; + inAppPurchase.purchaseProduct = (productID: string, opts?: number | { quantity?: number, username?: string }) => { + const quantity = typeof opts === 'object' ? opts.quantity : opts; + const username = typeof opts === 'object' ? opts.username : undefined; + return _purchase.apply(inAppPurchase, [productID, quantity, username]); + }; _inAppPurchase = inAppPurchase; } else { _inAppPurchase = new EventEmitter(); diff --git a/shell/browser/api/electron_api_in_app_purchase.cc b/shell/browser/api/electron_api_in_app_purchase.cc index 8162688bc8b30..43d1ca646ef40 100644 --- a/shell/browser/api/electron_api_in_app_purchase.cc +++ b/shell/browser/api/electron_api_in_app_purchase.cc @@ -178,9 +178,11 @@ v8::Local InAppPurchase::PurchaseProduct( int quantity = 1; args->GetNext(&quantity); + std::string username = ""; + args->GetNext(&username); in_app_purchase::PurchaseProduct( - product_id, quantity, + product_id, quantity, username, base::BindOnce(gin_helper::Promise::ResolvePromise, std::move(promise))); diff --git a/shell/browser/mac/in_app_purchase.h b/shell/browser/mac/in_app_purchase.h index 645c5e3be8151..6599e59ca6702 100644 --- a/shell/browser/mac/in_app_purchase.h +++ b/shell/browser/mac/in_app_purchase.h @@ -29,6 +29,7 @@ std::string GetReceiptURL(); void PurchaseProduct(const std::string& productID, int quantity, + const std::string& username, InAppPurchaseCallback callback); } // namespace in_app_purchase diff --git a/shell/browser/mac/in_app_purchase.mm b/shell/browser/mac/in_app_purchase.mm index 10194f49a7987..8586a25869c7f 100644 --- a/shell/browser/mac/in_app_purchase.mm +++ b/shell/browser/mac/in_app_purchase.mm @@ -25,10 +25,12 @@ @interface InAppPurchase : NSObject { @private in_app_purchase::InAppPurchaseCallback callback_; NSInteger quantity_; + NSString* username_; } - (id)initWithCallback:(in_app_purchase::InAppPurchaseCallback)callback - quantity:(NSInteger)quantity; + quantity:(NSInteger)quantity + username:(NSString*)username; - (void)purchaseProduct:(NSString*)productID; @@ -45,10 +47,12 @@ @implementation InAppPurchase * to the queue. */ - (id)initWithCallback:(in_app_purchase::InAppPurchaseCallback)callback - quantity:(NSInteger)quantity { + quantity:(NSInteger)quantity + username:(NSString*)username { if ((self = [super init])) { callback_ = std::move(callback); quantity_ = quantity; + username_ = [username copy]; } return self; @@ -107,6 +111,7 @@ - (void)checkout:(SKProduct*)product { // when the transaction is finished). SKMutablePayment* payment = [SKMutablePayment paymentWithProduct:product]; payment.quantity = quantity_; + payment.applicationUsername = username_; [[SKPaymentQueue defaultQueue] addPayment:payment]; @@ -128,6 +133,11 @@ - (void)runCallback:(bool)isProductValid { [self release]; } +- (void)dealloc { + [username_ release]; + [super dealloc]; +} + @end // ============================================================================ @@ -183,9 +193,12 @@ void FinishTransactionByDate(const std::string& date) { void PurchaseProduct(const std::string& productID, int quantity, + const std::string& username, InAppPurchaseCallback callback) { - auto* iap = [[InAppPurchase alloc] initWithCallback:std::move(callback) - quantity:quantity]; + auto* iap = [[InAppPurchase alloc] + initWithCallback:std::move(callback) + quantity:quantity + username:base::SysUTF8ToNSString(username)]; [iap purchaseProduct:base::SysUTF8ToNSString(productID)]; } diff --git a/spec/api-in-app-purchase-spec.ts b/spec/api-in-app-purchase-spec.ts index e75046051f47b..67c8d66f4f3be 100644 --- a/spec/api-in-app-purchase-spec.ts +++ b/spec/api-in-app-purchase-spec.ts @@ -39,12 +39,17 @@ describe('inAppPurchase module', function () { // without relying on a remote service. xdescribe('handles product purchases', () => { it('purchaseProduct() fails when buying invalid product', async () => { + const success = await inAppPurchase.purchaseProduct('non-exist'); + expect(success).to.be.false('failed to purchase non-existent product'); + }); + + it('purchaseProduct() accepts optional (Integer) argument', async () => { const success = await inAppPurchase.purchaseProduct('non-exist', 1); expect(success).to.be.false('failed to purchase non-existent product'); }); - it('purchaseProduct() accepts optional arguments', async () => { - const success = await inAppPurchase.purchaseProduct('non-exist'); + it('purchaseProduct() accepts optional (Object) argument', async () => { + const success = await inAppPurchase.purchaseProduct('non-exist', { quantity: 1, username: 'username' }); expect(success).to.be.false('failed to purchase non-existent product'); });