Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/in_app_purchase/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@

* Migrate to Google Billing Library 3.0
* Add `obfuscatedProfileId`, `purchaseToken` in [BillingClientWrapper.launchBillingFlow].
* Removed `developerPayload` in [BillingClientWrapper.acknowledgePurchase], [BillingClientWrapper.consumeAsync], [InAppPurchaseConnection.completePurchase], [InAppPurchaseConnection.consumePurchase].
* **Breaking Change**
* Removed `developerPayload` in [BillingClientWrapper.acknowledgePurchase], [BillingClientWrapper.consumeAsync], [InAppPurchaseConnection.completePurchase], [InAppPurchaseConnection.consumePurchase].
* Removed `isRewarded` from [SkuDetailsWrapper].

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there any useful context to provide about why they are removed? E.g., link to discussion of removal in the SDK?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

added

* [SkuDetailsWrapper.introductoryPriceCycles] now returns `int` instead of `String`.
* Above breaking changes are inline with the breaking changes introduced in [Google Play Billing 3.0 release](https://developer.android.com/google/play/billing/release-notes#3-0).
* Additional information on some the changes:
* [Dropping reward SKU support](https://support.google.com/googleplay/android-developer/answer/9155268?hl=en)
* [Developer payload](https://developer.android.com/google/play/billing/developer-payload)

## 0.4.1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,11 @@ public void querySkuDetailsAsync_clientDisconnected() {
verify(result, never()).success(any());
}

// Test launchBillingFlow not crash if `accountId` is `null`
// Ideally, we should check if the `accountId` is null in the parameter; however,
// since PBL 3.0, the `accountId` variable is not public.
@Test
public void launchBillingFlow_ok_null_AccountId() {
public void launchBillingFlow_null_AccountId_do_not_crash() {
// Fetch the sku details first and then prepare the launch billing flow call
String skuId = "foo";
queryForSkus(singletonList(skuId));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,11 @@ class BillingClient {
/// The [skuDetails] needs to have already been fetched in a [querySkuDetails]
/// call. The [accountId] is an optional hashed string associated with the user
/// that's unique to your app. It's used by Google to detect unusual behavior.
/// Do not pass in a cleartext [accountId], Do not use this field to store any Personally Identifiable Information (PII)
/// Do not pass in a cleartext [accountId], and do not use this field to store any Personally Identifiable Information (PII)
/// such as emails in cleartext. Attempting to store PII in this field will result in purchases being blocked.
/// Google Play recommends that you use either encryption or a one-way hash to generate an obfuscated identifier to send to Google Play.
///
/// Specifies an optional [obfuscatedProfileId] that is uniquely associated with the user's profile in your app.
/// Specifies an optional [obfuscatedProfileId] that is uniquely associated with the user's profile in your app.
/// Some applications allow users to have multiple profiles within a single account. Use this method to send the user's profile identifier to Google.
/// Setting this field requests the user's obfuscated account id.
///
Expand All @@ -174,10 +174,8 @@ class BillingClient {
/// [`BillingClient#launchBillingFlow`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient#launchbillingflow).
/// It constructs a
/// [`BillingFlowParams`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams)
/// instance by [setting the given
/// skuDetails](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder.html#setskudetails)
/// , [the given
/// accountId](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder#setObfuscatedAccountId(java.lang.String))
/// instance by [setting the given skuDetails](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder.html#setskudetails),
/// [the given accountId](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder#setObfuscatedAccountId(java.lang.String))
/// and the [obfuscatedProfileId] (https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder#setobfuscatedprofileid).
///
/// When this method is called to purchase a subscription, an optional `oldSku`
Expand All @@ -195,6 +193,8 @@ class BillingClient {
String? purchaseToken,
ProrationMode? prorationMode}) async {
assert(sku != null);
assert((oldSku == null) == (purchaseToken == null),
'oldSku and purchaseToken should have the same nullability');
Comment thread
cyanglaz marked this conversation as resolved.
Outdated
final Map<String, dynamic> arguments = <String, dynamic>{
'sku': sku,
'accountId': accountId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ class PurchaseWrapper {
///
/// The value is `null` if it wasn't specified when the purchase was acknowledged or consumed.
/// The `developerPayload` is removed from [BillingClientWrapper.acknowledgePurchase], [BillingClientWrapper.consumeAsync], [InAppPurchaseConnection.completePurchase], [InAppPurchaseConnection.consumePurchase]
/// after plugin version `0.5.0`. As a result, this will be `null` for new purchases happened after `0.5.0`.
/// after plugin version `0.5.0`. As a result, this will be `null` for new purchases that happen after updating to `0.5.0`.
final String? developerPayload;

/// Whether the purchase has been acknowledged.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,7 @@ class SkuDetailsWrapper {

/// The number of subscription billing periods for which the user will be given the introductory price, such as 3.
/// Returns 0 if the SKU is not a subscription or doesn't have an introductory period.
/// Returns -1 if the value is not available.
@JsonKey(defaultValue: -1)
@JsonKey(defaultValue: 0)
final int introductoryPriceCycles;

/// The billing period of [introductoryPrice], in ISO 8601 format.
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,40 @@ void main() {
expect(arguments['obfuscatedProfileId'], equals(profileId));
});

test(
'Change subscription throws assertion error `oldSku` and `purchaseToken` has different nullability',
() async {
const String debugMessage = 'dummy message';
final BillingResponse responseCode = BillingResponse.ok;
final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
responseCode: responseCode, debugMessage: debugMessage);
stubPlatform.addResponse(
name: launchMethodName,
value: buildBillingResultMap(expectedBillingResult),
);
final SkuDetailsWrapper skuDetails = dummySkuDetails;
final String accountId = 'hashedAccountId';
final String profileId = 'hashedProfileId';

expect(
billingClient.launchBillingFlow(
sku: skuDetails.sku,
accountId: accountId,
obfuscatedProfileId: profileId,
oldSku: dummyOldPurchase.sku,
purchaseToken: null),
throwsAssertionError);

expect(
billingClient.launchBillingFlow(
sku: skuDetails.sku,
accountId: accountId,
obfuscatedProfileId: profileId,
oldSku: null,
purchaseToken: dummyOldPurchase.purchaseToken),
throwsAssertionError);
});

test(
'serializes and deserializes data on change subscription without proration',
() async {
Expand All @@ -225,22 +259,22 @@ void main() {
final SkuDetailsWrapper skuDetails = dummySkuDetails;
final String accountId = 'hashedAccountId';
final String profileId = 'hashedProfileId';
final String purchaseToken = 'aPurchaseToken';

expect(
await billingClient.launchBillingFlow(
sku: skuDetails.sku,
accountId: accountId,
obfuscatedProfileId: profileId,
oldSku: dummyOldPurchase.sku,
purchaseToken: purchaseToken),
purchaseToken: dummyOldPurchase.purchaseToken),
equals(expectedBillingResult));
Map<dynamic, dynamic> arguments =
stubPlatform.previousCallMatching(launchMethodName).arguments;
expect(arguments['sku'], equals(skuDetails.sku));
expect(arguments['accountId'], equals(accountId));
expect(arguments['oldSku'], equals(dummyOldPurchase.sku));
expect(arguments['purchaseToken'], equals(purchaseToken));
expect(
arguments['purchaseToken'], equals(dummyOldPurchase.purchaseToken));
expect(arguments['obfuscatedProfileId'], equals(profileId));
});

Expand All @@ -258,7 +292,6 @@ void main() {
final SkuDetailsWrapper skuDetails = dummySkuDetails;
final String accountId = 'hashedAccountId';
final String profileId = 'hashedProfileId';
final String purchaseToken = 'aPurchaseToken';
final prorationMode = ProrationMode.immediateAndChargeProratedPrice;

expect(
Expand All @@ -268,15 +301,16 @@ void main() {
obfuscatedProfileId: profileId,
oldSku: dummyOldPurchase.sku,
prorationMode: prorationMode,
purchaseToken: purchaseToken),
purchaseToken: dummyOldPurchase.purchaseToken),
equals(expectedBillingResult));
Map<dynamic, dynamic> arguments =
stubPlatform.previousCallMatching(launchMethodName).arguments;
expect(arguments['sku'], equals(skuDetails.sku));
expect(arguments['accountId'], equals(accountId));
expect(arguments['oldSku'], equals(dummyOldPurchase.sku));
expect(arguments['obfuscatedProfileId'], equals(profileId));
expect(arguments['purchaseToken'], equals(purchaseToken));
expect(
arguments['purchaseToken'], equals(dummyOldPurchase.purchaseToken));
expect(arguments['prorationMode'],
ProrationModeConverter().toJson(prorationMode));
});
Expand Down