feat: Added missing info to IAP transaction and product structures (#31739)

This commit is contained in:
Kevin 2022-01-25 03:55:18 +11:00 committed by GitHub
parent d26d337bb8
commit 2fe5d0e1e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 323 additions and 6 deletions

View file

@ -0,0 +1,7 @@
# PaymentDiscount Object
* `identifier` string - A string used to uniquely identify a discount offer for a product.
* `keyIdentifier` string - A string that identifies the key used to generate the signature.
* `nonce` string - A universally unique ID (UUID) value that you define.
* `signature` string - A UTF-8 string representing the properties of a specific discount offer, cryptographically signed.
* `timestamp` number - The date and time of the signature's creation in milliseconds, formatted in Unix epoch time.

View file

@ -0,0 +1,9 @@
# ProductDiscount Object
* `identifier` string - A string used to uniquely identify a discount offer for a product.
* `type` number - The type of discount offer.
* `price` number - The discount price of the product in the local currency.
* `priceLocale` string - The locale used to format the discount price of the product.
* `paymentMode` string - The payment mode for this product discount. Can be `payAsYouGo`, `payUpFront`, or `freeTrial`.
* `numberOfPeriods` number - An integer that indicates the number of periods the product discount is available.
* `subscriptionPeriod` [ProductSubscriptionPeriod](product-subscription-period.md) (optional) - An object that defines the period for the product discount.

View file

@ -0,0 +1,4 @@
# ProductSubscriptionPeriod Object
* `numberOfUnits` number - The number of units per subscription period.
* `unit` string - The increment of time that a subscription period is specified in. Can be `day`, `week`, `month`, `year`.

View file

@ -8,4 +8,11 @@
* `price` number - The cost of the product in the local currency.
* `formattedPrice` string - The locale formatted price of the product.
* `currencyCode` string - 3 character code presenting a product's currency based on the ISO 4217 standard.
* `introductoryPrice` [ProductDiscount](product-discount.md) (optional) - The object containing introductory price information for the product.
available for the product.
* `discounts` [ProductDiscount](product-discount.md)[] - An array of discount offers
* `subscriptionGroupIdentifier` string - The identifier of the subscription group to which the subscription belongs.
* `subscriptionPeriod` [ProductSubscriptionPeriod](product-subscription-period.md) (optional) - The period details for products that are subscriptions.
* `isDownloadable` boolean - A boolean value that indicates whether the App Store has downloadable content for this product. `true` if at least one file has been associated with the product.
* `downloadContentVersion` string - A string that identifies the version of the content.
* `downloadContentLengths` number[] - The total size of the content, in bytes.

View file

@ -9,3 +9,5 @@
* `payment` Object
* `productIdentifier` string - The identifier of the purchased product.
* `quantity` Integer - The quantity purchased.
* `applicationUsername` string - An opaque identifier for the users account on your system.
* `paymentDiscount` [PaymentDiscount](payment-discount.md) (optional) - The details of the discount offer to apply to the payment.

View file

@ -100,11 +100,14 @@ auto_filenames = {
"docs/api/structures/new-window-web-contents-event.md",
"docs/api/structures/notification-action.md",
"docs/api/structures/notification-response.md",
"docs/api/structures/payment-discount.md",
"docs/api/structures/point.md",
"docs/api/structures/post-body.md",
"docs/api/structures/printer-info.md",
"docs/api/structures/process-memory-info.md",
"docs/api/structures/process-metric.md",
"docs/api/structures/product-discount.md",
"docs/api/structures/product-subscription-period.md",
"docs/api/structures/product.md",
"docs/api/structures/protocol-request.md",
"docs/api/structures/protocol-response-upload-data.md",

View file

@ -15,6 +15,22 @@
namespace gin {
template <>
struct Converter<in_app_purchase::PaymentDiscount> {
static v8::Local<v8::Value> ToV8(
v8::Isolate* isolate,
const in_app_purchase::PaymentDiscount& paymentDiscount) {
gin_helper::Dictionary dict = gin::Dictionary::CreateEmpty(isolate);
dict.SetHidden("simple", true);
dict.Set("identifier", paymentDiscount.identifier);
dict.Set("keyIdentifier", paymentDiscount.keyIdentifier);
dict.Set("nonce", paymentDiscount.nonce);
dict.Set("signature", paymentDiscount.signature);
dict.Set("timestamp", paymentDiscount.timestamp);
return dict.GetHandle();
}
};
template <>
struct Converter<in_app_purchase::Payment> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
@ -23,6 +39,10 @@ struct Converter<in_app_purchase::Payment> {
dict.SetHidden("simple", true);
dict.Set("productIdentifier", payment.productIdentifier);
dict.Set("quantity", payment.quantity);
dict.Set("applicationUsername", payment.applicationUsername);
if (payment.paymentDiscount.has_value()) {
dict.Set("paymentDiscount", payment.paymentDiscount.value());
}
return dict.GetHandle();
}
};
@ -45,6 +65,41 @@ struct Converter<in_app_purchase::Transaction> {
}
};
template <>
struct Converter<in_app_purchase::ProductSubscriptionPeriod> {
static v8::Local<v8::Value> ToV8(
v8::Isolate* isolate,
const in_app_purchase::ProductSubscriptionPeriod&
productSubscriptionPeriod) {
gin_helper::Dictionary dict = gin::Dictionary::CreateEmpty(isolate);
dict.SetHidden("simple", true);
dict.Set("numberOfUnits", productSubscriptionPeriod.numberOfUnits);
dict.Set("unit", productSubscriptionPeriod.unit);
return dict.GetHandle();
}
};
template <>
struct Converter<in_app_purchase::ProductDiscount> {
static v8::Local<v8::Value> ToV8(
v8::Isolate* isolate,
const in_app_purchase::ProductDiscount& productDiscount) {
gin_helper::Dictionary dict = gin::Dictionary::CreateEmpty(isolate);
dict.SetHidden("simple", true);
dict.Set("identifier", productDiscount.identifier);
dict.Set("type", productDiscount.type);
dict.Set("price", productDiscount.price);
dict.Set("priceLocale", productDiscount.priceLocale);
dict.Set("paymentMode", productDiscount.paymentMode);
dict.Set("numberOfPeriods", productDiscount.numberOfPeriods);
if (productDiscount.subscriptionPeriod.has_value()) {
dict.Set("subscriptionPeriod",
productDiscount.subscriptionPeriod.value());
}
return dict.GetHandle();
}
};
template <>
struct Converter<in_app_purchase::Product> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
@ -54,18 +109,25 @@ struct Converter<in_app_purchase::Product> {
dict.Set("productIdentifier", val.productIdentifier);
dict.Set("localizedDescription", val.localizedDescription);
dict.Set("localizedTitle", val.localizedTitle);
dict.Set("contentVersion", val.localizedTitle);
dict.Set("contentVersion", val.contentVersion);
dict.Set("contentLengths", val.contentLengths);
// Pricing Information
dict.Set("price", val.price);
dict.Set("formattedPrice", val.formattedPrice);
// Currency Information
dict.Set("currencyCode", val.currencyCode);
if (val.introductoryPrice.has_value()) {
dict.Set("introductoryPrice", val.introductoryPrice.value());
}
dict.Set("discounts", val.discounts);
dict.Set("subscriptionGroupIdentifier", val.subscriptionGroupIdentifier);
if (val.subscriptionPeriod.has_value()) {
dict.Set("subscriptionPeriod", val.subscriptionPeriod.value());
}
// Downloadable Content Information
dict.Set("isDownloadable", val.isDownloadable);
dict.Set("downloadContentVersion", val.downloadContentVersion);
dict.Set("downloadContentLengths", val.downloadContentLengths);
return dict.GetHandle();
}

View file

@ -10,6 +10,7 @@
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#if defined(__OBJC__)
@class InAppTransactionObserver;
@ -21,9 +22,27 @@ namespace in_app_purchase {
// --------------------------- Structures ---------------------------
struct PaymentDiscount {
std::string identifier;
std::string keyIdentifier;
std::string nonce;
std::string signature;
int timestamp;
PaymentDiscount();
PaymentDiscount(const PaymentDiscount&);
~PaymentDiscount();
};
struct Payment {
std::string productIdentifier = "";
int quantity = 1;
std::string applicationUsername;
absl::optional<PaymentDiscount> paymentDiscount;
Payment();
Payment(const Payment&);
~Payment();
};
struct Transaction {

View file

@ -94,6 +94,25 @@ using InAppTransactionCallback = base::RepeatingCallback<void(
return [dateFormatter stringFromDate:date];
}
/**
* Convert a SKPaymentDiscount object to a PaymentDiscount structure.
*
* @param paymentDiscount - The SKPaymentDiscount object to convert.
*/
- (in_app_purchase::PaymentDiscount)skPaymentDiscountToStruct:
(SKPaymentDiscount*)paymentDiscount API_AVAILABLE(macosx(10.14.4)) {
in_app_purchase::PaymentDiscount paymentDiscountStruct;
paymentDiscountStruct.identifier = [paymentDiscount.identifier UTF8String];
paymentDiscountStruct.keyIdentifier =
[paymentDiscount.keyIdentifier UTF8String];
paymentDiscountStruct.nonce = [[paymentDiscount.nonce UUIDString] UTF8String];
paymentDiscountStruct.signature = [paymentDiscount.signature UTF8String];
paymentDiscountStruct.timestamp = [paymentDiscount.timestamp intValue];
return paymentDiscountStruct;
}
/**
* Convert a SKPayment object to a Payment structure.
*
@ -110,6 +129,18 @@ using InAppTransactionCallback = base::RepeatingCallback<void(
paymentStruct.quantity = (int)payment.quantity;
}
if (payment.applicationUsername != nil) {
paymentStruct.applicationUsername =
[payment.applicationUsername UTF8String];
}
if (@available(macOS 10.14.4, *)) {
if (payment.paymentDiscount != nil) {
paymentStruct.paymentDiscount =
[self skPaymentDiscountToStruct:payment.paymentDiscount];
}
}
return paymentStruct;
}
@ -178,6 +209,14 @@ using InAppTransactionCallback = base::RepeatingCallback<void(
namespace in_app_purchase {
PaymentDiscount::PaymentDiscount() = default;
PaymentDiscount::PaymentDiscount(const PaymentDiscount&) = default;
PaymentDiscount::~PaymentDiscount() = default;
Payment::Payment() = default;
Payment::Payment(const Payment&) = default;
Payment::~Payment() = default;
Transaction::Transaction() = default;
Transaction::Transaction(const Transaction&) = default;
Transaction::~Transaction() = default;

View file

@ -9,11 +9,35 @@
#include <vector>
#include "base/callback.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace in_app_purchase {
// --------------------------- Structures ---------------------------
struct ProductSubscriptionPeriod {
int numberOfUnits;
std::string unit;
ProductSubscriptionPeriod(const ProductSubscriptionPeriod&);
ProductSubscriptionPeriod();
~ProductSubscriptionPeriod();
};
struct ProductDiscount {
std::string identifier;
int type;
double price = 0.0;
std::string priceLocale;
std::string paymentMode;
int numberOfPeriods;
absl::optional<ProductSubscriptionPeriod> subscriptionPeriod;
ProductDiscount(const ProductDiscount&);
ProductDiscount();
~ProductDiscount();
};
struct Product {
// Product Identifier
std::string productIdentifier;
@ -27,12 +51,16 @@ struct Product {
// Pricing Information
double price = 0.0;
std::string formattedPrice;
// Currency Information
std::string currencyCode;
absl::optional<ProductDiscount> introductoryPrice;
std::vector<ProductDiscount> discounts;
std::string subscriptionGroupIdentifier;
absl::optional<ProductSubscriptionPeriod> subscriptionPeriod;
// Downloadable Content Information
bool isDownloadable = false;
std::string downloadContentVersion;
std::vector<uint32_t> downloadContentLengths;
Product(const Product&);
Product();

View file

@ -106,6 +106,79 @@
return [numberFormatter stringFromNumber:price];
}
/**
* Convert a SKProductSubscriptionPeriod object to a ProductSubscriptionPeriod
* structure.
*
* @param productProductSubscriptionPeriod - The SKProductSubscriptionPeriod
* object to convert.
*/
- (in_app_purchase::ProductSubscriptionPeriod)
skProductSubscriptionPeriodToStruct:
(SKProductSubscriptionPeriod*)productSubscriptionPeriod
API_AVAILABLE(macosx(10.13.2)) {
in_app_purchase::ProductSubscriptionPeriod productSubscriptionPeriodStruct;
productSubscriptionPeriodStruct.numberOfUnits =
(int)productSubscriptionPeriod.numberOfUnits;
if (productSubscriptionPeriod.unit == SKProductPeriodUnitDay) {
productSubscriptionPeriodStruct.unit = "day";
} else if (productSubscriptionPeriod.unit == SKProductPeriodUnitWeek) {
productSubscriptionPeriodStruct.unit = "week";
} else if (productSubscriptionPeriod.unit == SKProductPeriodUnitMonth) {
productSubscriptionPeriodStruct.unit = "month";
} else if (productSubscriptionPeriod.unit == SKProductPeriodUnitYear) {
productSubscriptionPeriodStruct.unit = "year";
}
return productSubscriptionPeriodStruct;
}
/**
* Convert a SKProductDiscount object to a ProductDiscount structure.
*
* @param productDiscount - The SKProductDiscount object to convert.
*/
- (in_app_purchase::ProductDiscount)skProductDiscountToStruct:
(SKProductDiscount*)productDiscount API_AVAILABLE(macosx(10.13.2)) {
in_app_purchase::ProductDiscount productDiscountStruct;
if (productDiscount.paymentMode == SKProductDiscountPaymentModePayAsYouGo) {
productDiscountStruct.paymentMode = "payAsYouGo";
} else if (productDiscount.paymentMode ==
SKProductDiscountPaymentModePayUpFront) {
productDiscountStruct.paymentMode = "payUpFront";
} else if (productDiscount.paymentMode ==
SKProductDiscountPaymentModeFreeTrial) {
productDiscountStruct.paymentMode = "freeTrial";
}
productDiscountStruct.numberOfPeriods = (int)productDiscount.numberOfPeriods;
if (productDiscount.priceLocale != nil) {
productDiscountStruct.priceLocale =
[[self formatPrice:productDiscount.price
withLocal:productDiscount.priceLocale] UTF8String];
}
if (productDiscount.subscriptionPeriod != nil) {
productDiscountStruct.subscriptionPeriod = [self
skProductSubscriptionPeriodToStruct:productDiscount.subscriptionPeriod];
}
if (@available(macOS 10.14.4, *)) {
productDiscountStruct.type = (int)productDiscount.type;
if (productDiscount.identifier != nil) {
productDiscountStruct.identifier =
[productDiscount.identifier UTF8String];
}
productDiscountStruct.price = [productDiscount.price doubleValue];
}
return productDiscountStruct;
}
/**
* Convert a skProduct object to Product structure.
*
@ -156,9 +229,64 @@
}
}
}
if (@available(macOS 10.13.2, *)) {
if (product.introductoryPrice != nil) {
productStruct.introductoryPrice =
[self skProductDiscountToStruct:product.introductoryPrice];
}
if (product.subscriptionPeriod != nil) {
productStruct.subscriptionPeriod =
[self skProductSubscriptionPeriodToStruct:product.subscriptionPeriod];
}
}
if (@available(macOS 10.14, *)) {
if (product.subscriptionGroupIdentifier != nil) {
productStruct.subscriptionGroupIdentifier =
[product.subscriptionGroupIdentifier UTF8String];
}
}
if (@available(macOS 10.14.4, *)) {
if (product.discounts != nil) {
productStruct.discounts.reserve([product.discounts count]);
for (SKProductDiscount* discount in product.discounts) {
productStruct.discounts.push_back(
[self skProductDiscountToStruct:discount]);
}
}
}
// Downloadable Content Information
productStruct.isDownloadable = [product downloadable];
if (@available(macOS 10.14, *)) {
if (product.downloadContentVersion != nil) {
productStruct.downloadContentVersion =
[product.downloadContentVersion UTF8String];
}
if (product.downloadContentLengths != nil) {
productStruct.downloadContentLengths.reserve(
[product.downloadContentLengths count]);
for (NSNumber* contentLength in product.downloadContentLengths) {
productStruct.downloadContentLengths.push_back(
[contentLength longLongValue]);
}
}
} else {
if (product.contentVersion != nil) {
productStruct.downloadContentVersion =
[product.contentVersion UTF8String];
}
if (product.contentLengths != nil) {
productStruct.downloadContentLengths.reserve(
[product.contentLengths count]);
for (NSNumber* contentLength in product.contentLengths) {
productStruct.downloadContentLengths.push_back(
[contentLength longLongValue]);
}
}
}
return productStruct;
}
@ -171,6 +299,15 @@
namespace in_app_purchase {
ProductSubscriptionPeriod::ProductSubscriptionPeriod(
const ProductSubscriptionPeriod&) = default;
ProductSubscriptionPeriod::ProductSubscriptionPeriod() = default;
ProductSubscriptionPeriod::~ProductSubscriptionPeriod() = default;
ProductDiscount::ProductDiscount(const ProductDiscount&) = default;
ProductDiscount::ProductDiscount() = default;
ProductDiscount::~ProductDiscount() = default;
Product::Product() = default;
Product::Product(const Product&) = default;
Product::~Product() = default;