Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Conversation

@cyanglaz
Copy link
Contributor

@cyanglaz cyanglaz commented Feb 6, 2019

This is a very basic first draft for combining android and iOS get product list.
Would like this to be solid before working into more details.

@cyanglaz cyanglaz requested a review from mklim February 6, 2019 21:58
///
/// Returns a List of [Product] that each [Product] uniquely matches one valid identifier in [identifiers].
/// Any item in the `identifiers` that is not specified in App Store Connect or Google Play Console will be ignored.
Future<List<Product>> queryProductDetails(List<String> identifiers);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An alternative could be returning a custom 'Response' class something like ProductResponse which contains the list of the product and some errors if any. Any thoughts on this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that idea but I don't know what information we would be setting as the response code.

BillingClient returns an error code sometimes, and StoreKit returns a list of invalidProductIdentifiers. How would we combine that in a way that makes sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's also what blocking me to introduce the response class.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed offline, going to add a response with a list of the not found product IDs.

Copy link
Contributor

@mklim mklim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some API feedback but the underlying code is solid.

I also think now would be a good time to update the example app to query the products and list them. Proof of concept here.

subscriptionPeriod: json['subscriptionPeriod'] as String,
title: json['title'] as String,
type: const SkuTypeConverter().fromJson(json['type'] as String),
type: _$enumDecode(_$SkuTypeEnumMap, json['type']),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason this generated with extra enum boilerplate and it shouldn't have.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh yeah I didn't know why this piece of code got changed, I'll discuss with you offline.

///
/// Returns a List of [Product] that each [Product] uniquely matches one valid identifier in [identifiers].
/// Any item in the `identifiers` that is not specified in App Store Connect or Google Play Console will be ignored.
Future<List<Product>> queryProductDetails(List<String> identifiers);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that idea but I don't know what information we would be setting as the response code.

BillingClient returns an error code sometimes, and StoreKit returns a list of invalidProductIdentifiers. How would we combine that in a way that makes sense?

@cyanglaz
Copy link
Contributor Author

@mklim Updated with example app. Please take another look.

'gas',
'premium',
'upgrade',
'somethingNotValid'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally the example app should just be demoing the right way to use the API. I don't think it's worth deliberately checking for invalid product IDs here. All we're asking people to set up in the README so far is consumable, upgrade, and subscription.

}

/// The response returned by [InAppPurchaseConnection.queryProductDetails]
class QueryProductDetailsResponse {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think it would be a little clearer and more concise to name this ProductDetailsResponse. The "Query" part is already implied by "Response" (it's a response to a query).

QueryProductDetailsResponse(
{@required this.productDetails, @required this.notFoundIDs});

///Each [ProductDetails] uniquely matches one valid identifier in [identifiers] of [InAppPurchaseConnection.queryProductDetails].
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Extra whitespace before each sentence in the dartdoc here and below.


///The list of identifiers that are in the `identifiers` of [InAppPurchaseConnection.queryProductDetails] but failed to be fetched.
///
///These are the identifiers not matching the `productIdentifer` or `sku` in any product on the App Store Connect or Google Play Console.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd also avoid mentioning the underlying platforms here. "failed to be fetched" is about as specific as we can safely get at this layer without going into a bunch of platform specific details I think. For example I know in the App Store case invalidIdentifiers will be full of "valid" products in a lot of cases where the IDs do match whatever is in App Store connect and the problem is really in some other configuration in either the app or its store listing.

Maybe we could broadly point the users to look into the underlying platforms if they're seeing this failing? Like, "There's multiple platform specific reasons that product information could fail to be fetched, ranging from products not being correctly configured in the storefront to the queried IDs not existing." That's unfortunately not very helpful on its own, but I think that's really all the information we have at this level.


/// Query the product detail list.
///
/// This method only returns [QueryProductDetailsResponse].
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI I don't think this or GooglePlayConnection really need dart doc, since we're not exposing either of them as public API classes and they're overriding the documented public interface. You also don't need to delete documentation you've already written though.

Future<QueryProductDetailsResponse> queryProductDetails(
Set<String> identifiers) async {
SkuDetailsResponseWrapper inappResponse =
await _billingClient.querySkuDetails(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: It would be a little faster if these two queries happened in parallel and we blocked on them both completing in general, instead of blocking on both of them sequentially.

I think you can use Future.wait to block on multiple futures resolving.

skuType: SkuType.inapp, skusList: identifiers.toList());
SkuDetailsResponseWrapper subResponse = await _billingClient
.querySkuDetails(skuType: SkuType.subs, skusList: identifiers.toList());
List<ProductDetails> inappProducts = inappResponse.skuDetailsList
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, subjective: instead of writing this conversion twice what about combining these lists first?

Something like:

List<ProductDetails> products = (inappResponse.skuDetailsList + subResponse.skuDetailsList)
    .map((SkuDetailsWrapper wrapper) => //etc

/// Returns true if the payment platform is ready and available.
Future<bool> isAvailable();

/// Query the product details list.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I don't think we're really querying from a pre-existing list of product details here. It's more like we're querying for product details that match the given set of identifiers.


/// The class represents the information of a product.
///
/// A list of [ProductDetails] can be obtained from the [QueryProductDetailsResponse].
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, subjective: I think it would be more helpful to link to Connection.queryProductDetails here than the response data class specifically.

@cyanglaz
Copy link
Contributor Author

@mklim Updated with suggested reviews.

Copy link
Contributor

@mklim mklim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@cyanglaz cyanglaz merged commit 81dff2b into flutter:master Feb 13, 2019
@cyanglaz cyanglaz deleted the iap_getproductlist branch February 14, 2019 01:31
andreidiaconu pushed a commit to andreidiaconu/plugins that referenced this pull request Feb 17, 2019
Contains the basic draft of the combined api to get product details.
Add an example app to demonstrate the usage.
andreidiaconu added a commit to andreidiaconu/plugins that referenced this pull request Feb 17, 2019
karantanwar pushed a commit to karantanwar/plugins that referenced this pull request Feb 19, 2019
Contains the basic draft of the combined api to get product details.
Add an example app to demonstrate the usage.
karantanwar pushed a commit to karantanwar/plugins that referenced this pull request Feb 19, 2019
Contains the basic draft of the combined api to get product details.
Add an example app to demonstrate the usage.
@cyanglaz cyanglaz changed the title Iap getproductlist basic draft [In_app_purchase] getproductlist basic draft Feb 22, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants