Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 2bac766

Browse filesBrowse files
authored
[in_app_purchase_android] GooglePlayPurchaseParam add possibility set selected offerToken (#8452)
Option to add purchase parameters in GooglePlayPurchaseParam to set selected offer token. In subscribtion with multiple offer in base plan, the user can choose which offer to want buy and then this selected offer token is sent to the billing flow flutter/flutter#150348
1 parent e8e8da3 commit 2bac766
Copy full SHA for 2bac766

File tree

Expand file treeCollapse file tree

5 files changed

+105
-3
lines changed
Filter options
Expand file treeCollapse file tree

5 files changed

+105
-3
lines changed

‎packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md

Copy file name to clipboardExpand all lines: packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.4.0+2
2+
3+
* Adds support for setting the `offerToken` on `GooglePlayPurchaseParam`.
4+
15
## 0.4.0+1
26

37
* Updates compileSdk 34 to flutter.compileSdkVersion.

‎packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform.dart

Copy file name to clipboardExpand all lines: packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform.dart
+4-2Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,13 +142,15 @@ class InAppPurchaseAndroidPlatform extends InAppPurchasePlatform {
142142
@override
143143
Future<bool> buyNonConsumable({required PurchaseParam purchaseParam}) async {
144144
ChangeSubscriptionParam? changeSubscriptionParam;
145+
String? offerToken;
145146

146147
if (purchaseParam is GooglePlayPurchaseParam) {
147148
changeSubscriptionParam = purchaseParam.changeSubscriptionParam;
149+
offerToken = purchaseParam.offerToken;
148150
}
149151

150-
String? offerToken;
151-
if (purchaseParam.productDetails is GooglePlayProductDetails) {
152+
if (offerToken == null &&
153+
purchaseParam.productDetails is GooglePlayProductDetails) {
152154
offerToken =
153155
(purchaseParam.productDetails as GooglePlayProductDetails).offerToken;
154156
}

‎packages/in_app_purchase/in_app_purchase_android/lib/src/types/google_play_purchase_param.dart

Copy file name to clipboardExpand all lines: packages/in_app_purchase/in_app_purchase_android/lib/src/types/google_play_purchase_param.dart
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,16 @@ class GooglePlayPurchaseParam extends PurchaseParam {
1313
required super.productDetails,
1414
super.applicationUserName,
1515
this.changeSubscriptionParam,
16+
this.offerToken,
1617
});
1718

1819
/// The 'changeSubscriptionParam' containing information for upgrading or
1920
/// downgrading an existing subscription.
2021
final ChangeSubscriptionParam? changeSubscriptionParam;
22+
23+
/// For One-time product, "offerToken" shouldn't be filled.
24+
///
25+
/// For subscriptions, to get the offer token corresponding to the selected
26+
/// offer call productDetails.subscriptionOfferDetails?.get(selectedOfferIndex)?.offerToken
27+
final String? offerToken;
2128
}

‎packages/in_app_purchase/in_app_purchase_android/pubspec.yaml

Copy file name to clipboardExpand all lines: packages/in_app_purchase/in_app_purchase_android/pubspec.yaml
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ name: in_app_purchase_android
22
description: An implementation for the Android platform of the Flutter `in_app_purchase` plugin. This uses the Android BillingClient APIs.
33
repository: https://github.com/flutter/packages/tree/main/packages/in_app_purchase/in_app_purchase_android
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22
5-
version: 0.4.0+1
5+
6+
version: 0.4.0+2
67

78
environment:
89
sdk: ^3.6.0

‎packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart

Copy file name to clipboardExpand all lines: packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart
+88Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,33 @@ import 'billing_client_wrappers/product_details_wrapper_test.dart';
2020
import 'billing_client_wrappers/purchase_wrapper_test.dart';
2121
import 'test_conversion_utils.dart';
2222

23+
const ProductDetailsWrapper dummySubscriptionProductDetails =
24+
ProductDetailsWrapper(
25+
description: 'description',
26+
name: 'name',
27+
productId: 'productId',
28+
productType: ProductType.subs,
29+
title: 'title',
30+
subscriptionOfferDetails: <SubscriptionOfferDetailsWrapper>[
31+
SubscriptionOfferDetailsWrapper(
32+
basePlanId: 'basePlanId',
33+
offerTags: <String>['offerTags'],
34+
offerId: 'offerId',
35+
offerIdToken: 'offerToken',
36+
pricingPhases: <PricingPhaseWrapper>[
37+
PricingPhaseWrapper(
38+
billingCycleCount: 4,
39+
billingPeriod: 'billingPeriod',
40+
formattedPrice: r'$100',
41+
priceAmountMicros: 100000000,
42+
priceCurrencyCode: 'USD',
43+
recurrenceMode: RecurrenceMode.finiteRecurring,
44+
),
45+
],
46+
),
47+
],
48+
);
49+
2350
void main() {
2451
TestWidgetsFlutterBinding.ensureInitialized();
2552

@@ -255,6 +282,67 @@ void main() {
255282
});
256283

257284
group('make payment', () {
285+
test('buy non consumable subscribe offer, serializes and deserializes data',
286+
() async {
287+
const ProductDetailsWrapper productDetails =
288+
dummySubscriptionProductDetails;
289+
const String accountId = 'hashedAccountId';
290+
const String debugMessage = 'dummy message';
291+
const BillingResponse sentCode = BillingResponse.ok;
292+
const BillingResultWrapper expectedBillingResult = BillingResultWrapper(
293+
responseCode: sentCode, debugMessage: debugMessage);
294+
295+
when(mockApi.launchBillingFlow(any)).thenAnswer((_) async {
296+
// Mock java update purchase callback.
297+
iapAndroidPlatform.billingClientManager.client.hostCallbackHandler
298+
.onPurchasesUpdated(PlatformPurchasesResponse(
299+
billingResult: convertToPigeonResult(expectedBillingResult),
300+
purchases: <PlatformPurchase>[
301+
PlatformPurchase(
302+
orderId: 'orderID1',
303+
products: <String>[productDetails.productId],
304+
isAutoRenewing: false,
305+
packageName: 'package',
306+
purchaseTime: 1231231231,
307+
purchaseToken: 'token',
308+
signature: 'sign',
309+
originalJson: 'json',
310+
developerPayload: 'dummy payload',
311+
isAcknowledged: true,
312+
purchaseState: PlatformPurchaseState.purchased,
313+
quantity: 1,
314+
)
315+
],
316+
));
317+
318+
return convertToPigeonResult(expectedBillingResult);
319+
});
320+
final Completer<PurchaseDetails> completer = Completer<PurchaseDetails>();
321+
PurchaseDetails purchaseDetails;
322+
final Stream<List<PurchaseDetails>> purchaseStream =
323+
iapAndroidPlatform.purchaseStream;
324+
late StreamSubscription<List<PurchaseDetails>> subscription;
325+
subscription = purchaseStream.listen((List<PurchaseDetails> details) {
326+
purchaseDetails = details.first;
327+
completer.complete(purchaseDetails);
328+
subscription.cancel();
329+
}, onDone: () {});
330+
final GooglePlayPurchaseParam purchaseParam = GooglePlayPurchaseParam(
331+
offerToken:
332+
productDetails.subscriptionOfferDetails?.first.offerIdToken,
333+
productDetails:
334+
GooglePlayProductDetails.fromProductDetails(productDetails).first,
335+
applicationUserName: accountId);
336+
final bool launchResult = await iapAndroidPlatform.buyNonConsumable(
337+
purchaseParam: purchaseParam);
338+
339+
final PurchaseDetails result = await completer.future;
340+
expect(launchResult, isTrue);
341+
expect(result.purchaseID, 'orderID1');
342+
expect(result.status, PurchaseStatus.purchased);
343+
expect(result.productID, productDetails.productId);
344+
});
345+
258346
test('buy non consumable, serializes and deserializes data', () async {
259347
const ProductDetailsWrapper productDetails = dummyOneTimeProductDetails;
260348
const String accountId = 'hashedAccountId';

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.