feat: Added missing info to IAP transaction and product structures (#31739)
This commit is contained in:
parent
d26d337bb8
commit
2fe5d0e1e8
11 changed files with 323 additions and 6 deletions
7
docs/api/structures/payment-discount.md
Normal file
7
docs/api/structures/payment-discount.md
Normal 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.
|
9
docs/api/structures/product-discount.md
Normal file
9
docs/api/structures/product-discount.md
Normal 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.
|
4
docs/api/structures/product-subscription-period.md
Normal file
4
docs/api/structures/product-subscription-period.md
Normal 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`.
|
|
@ -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.
|
||||
|
|
|
@ -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 user’s account on your system.
|
||||
* `paymentDiscount` [PaymentDiscount](payment-discount.md) (optional) - The details of the discount offer to apply to the payment.
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue