Browse Source

feat: added username to IAP purchaseProduct method (#35902)

Michał Zarach 2 years ago
parent
commit
6a798b1c58

+ 5 - 3
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<boolean>` - Returns `true` if the product is valid and added to the payment queue.
 

+ 6 - 1
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<boolean>;
+  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();

+ 3 - 1
shell/browser/api/electron_api_in_app_purchase.cc

@@ -178,9 +178,11 @@ v8::Local<v8::Promise> 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<bool>::ResolvePromise,
                      std::move(promise)));
 

+ 1 - 0
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

+ 17 - 4
shell/browser/mac/in_app_purchase.mm

@@ -25,10 +25,12 @@
  @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 @@
  * 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 @@
   // when the transaction is finished).
   SKMutablePayment* payment = [SKMutablePayment paymentWithProduct:product];
   payment.quantity = quantity_;
+  payment.applicationUsername = username_;
 
   [[SKPaymentQueue defaultQueue] addPayment:payment];
 
@@ -128,6 +133,11 @@
   [self release];
 }
 
+- (void)dealloc {
+  [username_ release];
+  [super dealloc];
+}
+
 @end
 
 // ============================================================================
@@ -183,9 +193,12 @@ std::string GetReceiptURL() {
 
 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)];
 }

+ 7 - 2
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');
     });