Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
2 changes: 2 additions & 0 deletions packages/in_app_purchase/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
## 0.3.0

* Migrate the `Google Play Library` to 2.0.3.
* **[Breaking Change]:** Added `enablePendingPurchases` in `InAppPurchaseConnection`. The application has
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 a link to the Play documentation on enablePendingPurchases would be useful here.

to call this method when initializing the `InAppPurchaseConnection` on Android.
* Introduce a new class `BillingResultWrapper` which contains a detailed result of a BillingClient operation.
* **[Breaking Change]:** All the BillingClient methods that previously return a `BillingResponse` now return a `BillingResultWrapper`, including: `launchBillingFlow`, `startConnection` and `consumeAsync`.
* **[Breaking Change]:** The `SkuDetailsResponseWrapper` now contains a `billingResult` field in place of `billingResponse` field.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ interface BillingClientFactory {
*
* @param context The context used to create the {@link BillingClient}.
* @param channel The method channel used to create the {@link BillingClient}.
* @param enablePendingPurchases Whether to enable pending purchases. Throws an exception if it is
* false.
* @return The {@link BillingClient} object that is created.
*/
BillingClient createBillingClient(@NonNull Context context, @NonNull MethodChannel channel);
BillingClient createBillingClient(
@NonNull Context context, @NonNull MethodChannel channel, boolean enablePendingPurchases);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
final class BillingClientFactoryImpl implements BillingClientFactory {

@Override
public BillingClient createBillingClient(Context context, MethodChannel channel) {
return BillingClient.newBuilder(context)
.enablePendingPurchases()
.setListener(new PluginPurchaseListener(channel))
.build();
public BillingClient createBillingClient(
Context context, MethodChannel channel, boolean enablePendingPurchases) {
BillingClient.Builder builder = BillingClient.newBuilder(context);
if (enablePendingPurchases) {
builder.enablePendingPurchases();
}
return builder.setListener(new PluginPurchaseListener(channel)).build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) {
isReady(result);
break;
case InAppPurchasePlugin.MethodNames.START_CONNECTION:
startConnection((int) call.argument("handle"), result);
startConnection(
(int) call.argument("handle"),
(boolean) call.argument("enablePendingPurchases"),
result);
break;
case InAppPurchasePlugin.MethodNames.END_CONNECTION:
endConnection(result);
Expand Down Expand Up @@ -236,9 +239,12 @@ public void onPurchaseHistoryResponse(
});
}

private void startConnection(final int handle, final MethodChannel.Result result) {
private void startConnection(
final int handle, final boolean enablePendingPurchases, final MethodChannel.Result result) {
if (billingClient == null) {
billingClient = billingClientFactory.createBillingClient(applicationContext, methodChannel);
billingClient =
billingClientFactory.createBillingClient(
applicationContext, methodChannel, enablePendingPurchases);
}

billingClient.startConnection(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ public class MethodCallHandlerTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);

factory = (context, channel) -> mockBillingClient;
factory = (context, channel, true) -> mockBillingClient;
methodChannelHandler = new MethodCallHandlerImpl(activity, context, mockMethodChannel, factory);
}

Expand Down
1 change: 1 addition & 0 deletions packages/in_app_purchase/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:in_app_purchase/in_app_purchase.dart';
import 'consumable_store.dart';

void main() {
InAppPurchaseConnection.enablePendingPurchases();
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Comment here explaining what this is and linking to the Play documentation would be useful.

runApp(MyApp());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ typedef void PurchasesUpdatedListener(PurchasesResultWrapper purchasesResult);
/// some minor changes to account for language differences. Callbacks have been
/// converted to futures where appropriate.
class BillingClient {
bool _enablePendingPurchases = false;

BillingClient(PurchasesUpdatedListener onPurchasesUpdated) {
assert(onPurchasesUpdated != null);
channel.setMethodCallHandler(callHandler);
Expand All @@ -71,6 +73,17 @@ class BillingClient {
Future<bool> isReady() async =>
await channel.invokeMethod<bool>('BillingClient#isReady()');

/// Enable the [BillingClientWrapper] to handle pending purchases.
///
/// This method is required to be called when initialize the application.
Copy link
Contributor

Choose a reason for hiding this comment

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

Small optional wording nit:

Suggested change
/// This method is required to be called when initialize the application.
/// Play requires that you call this method when initializing your application.

https://developers.google.com/style/voice

/// It is to acknowledge your application has been updated to support pending purchases.
/// See [Support pending transactions](https://developer.android.com/google/play/billing/billing_library_overview#pending)
/// for more details.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: paragraph break below would make sense, I think.

/// Failure to call this method before any other method in the [startConnection] will throw an exception.
void enablePendingPurchases() {
_enablePendingPurchases = true;
}

/// Calls
/// [`BillingClient#startConnection(BillingClientStateListener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#startconnection)
/// to create and connect a `BillingClient` instance.
Expand All @@ -84,13 +97,18 @@ class BillingClient {
Future<BillingResultWrapper> startConnection(
{@required
OnBillingServiceDisconnected onBillingServiceDisconnected}) async {
assert(_enablePendingPurchases,
'enablePendingPurchases() must be called before calling startConnection');
List<Function> disconnectCallbacks =
_callbacks[_kOnBillingServiceDisconnected] ??= [];
disconnectCallbacks.add(onBillingServiceDisconnected);
return BillingResultWrapper.fromJson(await channel
.invokeMapMethod<String, dynamic>(
"BillingClient#startConnection(BillingClientStateListener)",
<String, dynamic>{'handle': disconnectCallbacks.length - 1}));
<String, dynamic>{
'handle': disconnectCallbacks.length - 1,
'enablePendingPurchases': _enablePendingPurchases
}));
}

/// Calls
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ class GooglePlayConnection
_purchaseUpdatedController
.add(await _getPurchaseDetailsFromResult(resultWrapper));
}) {
if (InAppPurchaseConnection.enablePendingPurchase) {
billingClient.enablePendingPurchases();
}
_readyFuture = _connect();
WidgetsBinding.instance.addObserver(this);
_purchaseUpdatedController = StreamController.broadcast();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,28 @@ abstract class InAppPurchaseConnection {
return _purchaseUpdatedStream;
}

/// Whether pending purchase is enabled.
///
/// See also [enablePendingPurchases] for more on pending purchases.
static bool get enablePendingPurchase => _enablePendingPurchase;
static bool _enablePendingPurchase = false;

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

/// Enable the [InAppPurchaseConnection] to handle pending purchases.
///
/// Android Only: This method is required to be called when initialize the application.
/// It is to acknowledge your application has been updated to support pending purchases.
/// See [Support pending transactions](https://developer.android.com/google/play/billing/billing_library_overview#pending)
/// for more details.
/// Failure to call this method before access [instance] will throw an exception.
///
/// It is an no-op on iOS.
static void enablePendingPurchases() {
_enablePendingPurchase = true;
}

/// Query product details for the given set of IDs.
///
/// The [identifiers] need to exactly match existing configured product
Expand Down