Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
5be7c0a
Intial add of country code, no tests
reidbaker Jan 19, 2024
5d6f1cc
Add tests for getBillingConfig
reidbaker Jan 19, 2024
e19b644
Formating
reidbaker Jan 19, 2024
3f5a4e3
Manipulate data in translator class instead of impl
reidbaker Jan 24, 2024
337a7d7
Add dart side code to call getBillingConfig and conversion tests
reidbaker Jan 24, 2024
99af529
Correct null test to include empty country code, fix non null billing…
reidbaker Jan 25, 2024
fdc42cd
move buildBillingConfigMap to the class that uses it
reidbaker Jan 25, 2024
88ccd2a
Merge branch 'main' into i141627-country-code-api
reidbaker Jan 25, 2024
036e2f2
Write documentation and remove todos, remove unused import
reidbaker Jan 25, 2024
91950f3
Analyzer warnings
reidbaker Jan 25, 2024
7d4af42
Merge branch 'main' into i141627-country-code-api
reidbaker Jan 25, 2024
5cd0acb
java format warnings
reidbaker Jan 25, 2024
894473c
Version code change
reidbaker Jan 25, 2024
e33f22c
Restore in app purchase instructions in example readme from bad PR ht…
reidbaker Jan 26, 2024
1dc004b
Update packages/in_app_purchase/in_app_purchase_android/android/src/m…
reidbaker Jan 26, 2024
319ffe7
Add example app code that shows country code in UI rename addition ap…
reidbaker Jan 26, 2024
28e95ad
Remove "Demonstrates how to use" verbiage since that is confusing whi…
reidbaker Jan 29, 2024
3c263a8
Merge branch 'main' into i141627-country-code-api
reidbaker Jan 29, 2024
4cd74ec
Merge branch 'main' into i141627-country-code-api
reidbaker Jan 30, 2024
d7934fc
Remove changes to ios readme
reidbaker Jan 30, 2024
5252d6e
Readme link to signing docs and changelog verbiage update
reidbaker Jan 30, 2024
5e363fc
Restore getCountryCode tests
reidbaker Jan 30, 2024
62477c4
Use run with client since BillingConfigWrapper uses a billing result
reidbaker Jan 30, 2024
a514dc1
Merge branch 'main' into i141627-country-code-api
reidbaker Jan 30, 2024
f047aac
Use run with client since BillingConfigWrapper uses a billing result
reidbaker Jan 30, 2024
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
Prev Previous commit
Next Next commit
Add dart side code to call getBillingConfig and conversion tests
  • Loading branch information
reidbaker committed Jan 24, 2024
commit 337a7d7f4ec86b46714160b66876994bfa682cef
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ static HashMap<String, Object> fromBillingResult(BillingResult billingResult) {
return info;
}

/**
* Converter from {@link BillingResult} and {@link BillingConfig} to map.
*/
static HashMap<String, Object> fromBillingConfig(BillingResult result, BillingConfig billingConfig) {
HashMap<String, Object> info = fromBillingResult(result);
info.put("countryCode", billingConfig.getCountryCode());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:json_annotation/json_annotation.dart';

import '../../billing_client_wrappers.dart';
import '../channel.dart';
import 'billing_config_wrapper.dart';

part 'billing_client_wrapper.g.dart';

Expand Down Expand Up @@ -324,6 +325,17 @@ class BillingClient {
return result ?? false;
}

@visibleForTesting
final String getBillingConfigMethodString =
'BillingClient#getBillingConfig()';

/// TODO
Future<BillingConfigWrapper> getBillingConfig() async {
return BillingConfigWrapper.fromJson((await channel
.invokeMapMethod<String, dynamic>(getBillingConfigMethodString)) ??
<String, dynamic>{});
}

/// The method call handler for [channel].
@visibleForTesting
Future<void> callHandler(MethodCall call) async {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/material.dart';
import 'package:json_annotation/json_annotation.dart';

import '../../billing_client_wrappers.dart';

// WARNING: Changes to `@JsonSerializable` classes need to be reflected in the
// below generated file. Run `flutter packages pub run build_runner watch` to
// rebuild and watch for further changes.
part 'billing_config_wrapper.g.dart';

/// The error message shown when the map represents billing config is invalid from method channel.
///
/// This usually indicates a serious underlining code issue in the plugin.
@visibleForTesting
const String kInvalidBillingConfigErrorMessage =
'Invalid billing config map from method channel.';

/// Params containing the response code and the debug message from the Play Billing API response.
@JsonSerializable()
@BillingResponseConverter()
@immutable
class BillingConfigWrapper implements HasBillingResponse {
/// Constructs the object with [responseCode] and [debugMessage].
const BillingConfigWrapper({required this.responseCode, this.debugMessage, this.countryCode});

/// Constructs an instance of this from a key value map of data.
///
/// The map needs to have named string keys with values matching the names and
/// types of all of the members on this class.
factory BillingConfigWrapper.fromJson(Map<String, dynamic>? map) {
if (map == null || map.isEmpty) {
return const BillingConfigWrapper(
responseCode: BillingResponse.error,
debugMessage: kInvalidBillingResultErrorMessage,
countryCode: '',
);
}
return _$BillingConfigWrapperFromJson(map);
}

/// Response code returned in the Play Billing API calls.
@override
final BillingResponse responseCode;

/// Debug message returned in the Play Billing API calls.
///
/// Defaults to `null`.
/// This message uses an en-US locale and should not be shown to users.
@JsonKey(defaultValue: '')
final String? debugMessage;

/// https://developer.android.com/reference/com/android/billingclient/api/BillingConfig#getCountryCode()
@JsonKey(defaultValue: '')
final String? countryCode;

@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType) {
return false;
}

return other is BillingConfigWrapper &&
other.responseCode == responseCode &&
other.debugMessage == debugMessage &&
other.countryCode == countryCode;
}

@override
int get hashCode => Object.hash(responseCode, debugMessage, countryCode);
}

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 @@ -7,6 +7,7 @@ import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_inte

import '../billing_client_wrappers.dart';
import '../in_app_purchase_android.dart';
import 'billing_client_wrappers/billing_config_wrapper.dart';

/// Contains InApp Purchase features that are only available on PlayStore.
class InAppPurchaseAndroidPlatformAddition
Expand Down Expand Up @@ -146,4 +147,11 @@ class InAppPurchaseAndroidPlatformAddition
(BillingClient client) => client.isFeatureSupported(feature),
);
}

/// TODO
Future<BillingConfigWrapper> getBillingConfig() async {
return _billingClientManager.runWithClientNonRetryable(
Copy link
Member

Choose a reason for hiding this comment

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

Should this return a BillingConfigWrapper and then be also be retryable, as it returns a subclass of HasBillingResponse?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wanted to keep the exposed api as small as possible so I thought the country code was the right level to expose. I didnt even think about if it should be retryable I just mirrored the other commands. Let me look at what that does and make a call.

Copy link
Member

Choose a reason for hiding this comment

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

I think this comment still applies

(BillingClient client) => client.getBillingConfig(),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:in_app_purchase_android/billing_client_wrappers.dart';
import 'package:in_app_purchase_android/src/billing_client_wrappers/billing_config_wrapper.dart';
import 'package:in_app_purchase_android/src/channel.dart';

import '../stub_in_app_purchase_platform.dart';
Expand Down Expand Up @@ -641,6 +642,39 @@ void main() {
expect(arguments['feature'], equals('subscriptions'));
});
});

group('billingConfig', () {
const String billingConfigMethodName = 'BillingClient#getBillingConfig()';
test('billingConfig returns object', () async {
late Map<Object?, Object?> arguments;
stubPlatform.addResponse(
name: billingConfigMethodName,
value: const BillingConfigWrapper(
countryCode: 'US',
responseCode: BillingResponse.ok,
debugMessage: ''),
additionalStepBeforeReturn: (dynamic value) =>
arguments = value as Map<dynamic, dynamic>,
);
final BillingConfigWrapper result =
await billingClient.getBillingConfig();
expect(result.countryCode, 'US');
});


test('handles method channel returning null', () async {
stubPlatform.addResponse(
name: billingConfigMethodName,
);
final BillingConfigWrapper result =
await billingClient.getBillingConfig();
expect(
result,
equals(const BillingConfigWrapper(
responseCode: BillingResponse.error,
debugMessage: kInvalidBillingConfigErrorMessage)));
});
});
}

/// This allows a value of type T or T? to be treated as a value of type T?.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'package:in_app_purchase_android/billing_client_wrappers.dart';
import 'package:in_app_purchase_android/in_app_purchase_android.dart';
import 'package:in_app_purchase_android/src/billing_client_wrappers/billing_config_wrapper.dart';
import 'package:test/test.dart';

const PurchaseWrapper dummyPurchase = PurchaseWrapper(
Expand Down Expand Up @@ -252,3 +253,12 @@ Map<String, dynamic> buildBillingResultMap(BillingResultWrapper original) {
'debugMessage': original.debugMessage,
};
}

Map<String, dynamic> buildBillingConfigMap(BillingConfigWrapper original) {
return <String, dynamic>{
'responseCode':
const BillingResponseConverter().toJson(original.responseCode),
'debugMessage': original.debugMessage,
'countryCode': original.countryCode,
};
}