LinkFive - Successful Subscriptions

Flutter Provider Plugin Example

Flutter Provider Plugin Example

Let's get right into the provider example.

We also have a Flutter provider plugin on pub.dev

Create a new Provider class

We're using a ChangeNotifier to notify all listeners that something has changed.

class LinkFiveProvider extends ChangeNotifier {
}

We will initialize LinkFive in it's constructor. This will also check if an active subscription is currently existing.

We will also listen for all data changes that is coming through the plugin with a listener.

  • SubscriptionData: Is the subscription product which contains the price, the duration and the name of your subscriptions. This data is used to offer a subscription product to your users.
  • ActiveSubscriptionData: Is an active verified subscription that the user purchased.
LinkFiveProvider() {
LinkFivePurchases.init("API_KEY");
LinkFivePurchases
.products
.listen(_subscriptionDataUpdate)
LinkFivePurchases
.activeProducts
.listen(_activeSubscriptionDataUpdate)
}

Inside the listener methods, you can just save the data to the ChangeNotifier and notify all Listeners that something has changed.

void _subscriptionDataUpdate(LinkFiveSubscriptionData? data) async {
availableSubscriptionData = data;
notifyListeners();
}
void _activeSubscriptionDataUpdate(LinkFiveActiveSubscriptionData? data) {
activeSubscriptionData = data;
notifyListeners();
}

This was the basic example and should be enough to implement subscriptions into your App. You should also save the streams to the ChangeNotifier and cancel them on dispose.

Add your Provider to your other providers

In your main method or wherever you want to add the provider to the Widget tree, add the provider like any other providers.

MultiProvider(providers: [
ChangeNotifierProvider(
create: (context) => LinkFiveProvider(),
lazy: false,
),
// Your other providers
])

Consume the Provider

In your build method, right before you want to offer the subscriptions, you can consume the provider using a Consumer< LinkFiveProvider >

@override
Widget build(BuildContext context) {
return Container(
child: Consumer<LinkFiveProvider>(
builder: (_, linkFiveProvider, __) {
var subscriptionData = linkFiveProvider.availableSubscriptionData;
if (subscriptionData != null) {
// use the subscription Data to build your Purchase buttons
// example:
return Column(
children: [
Row(
children: buildSubscriptionButtons(subscriptionData),
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
)
],
);
}
return Center(child: Text('No Subscription found...'));
},
));
}

In your buildSubscriptionButtons method, loop through the subscriptions and create a button for each element.

buildSubscriptionButtons(LinkFiveSubscriptionData subscriptionData) {
return subscriptionData.linkFiveSkuData
.map((linkFiveProductDetails) => ElevatedButton(
onPressed: () {
LinkFivePurchases.purchase(linkFiveProductDetails.productDetails);
},
child: Text(linkFiveProductDetails.productDetails.price),
))
.toList();
}

When the user presses the button, LinkFivePurchases.purchase(...) will be called and handles the whole purchase flow.

The verified receipt will be passed to the activeSubscription stream.



Complete Provider Example

class LinkFiveProvider extends ChangeNotifier {
/// LinkFive client
final LinkFivePurchasesMain linkFivePurchases = LinkFivePurchasesMain();
/// LinkFive subscription holder that you can offer to your user
LinkFiveSubscriptionData? availableSubscriptionData;
/// All verified receipt received by LinkFive
LinkFiveActiveSubscriptionData? activeSubscriptionData;
/// Streams that will be cleaned on dispose
List<StreamSubscription> _streams = [];
/// All verified receipts as List or emptyList
List<LinkFiveVerifiedReceipt> get verifiedReceiptList =>
activeSubscriptionData?.subscriptionList ?? [];
/// LinkFive as CallbackInterface for your Paywall
CallbackInterface get callbackInterface => linkFivePurchases;
/// Init LinkFive with your API Key
/// [LinkFiveEnvironment] is 99,999..% [LinkFiveEnvironment.PRODUCTION] better not touch it
LinkFiveProvider(String apiKey,
{LinkFiveEnvironment environment = LinkFiveEnvironment.PRODUCTION}) {
linkFivePurchases.init(apiKey, env: environment);
_streams.add(linkFivePurchases
.products
.listen(_subscriptionDataUpdate));
_streams.add(linkFivePurchases
.activeProducts
.listen(_activeSubscriptionDataUpdate));
}
/// Saves available Subscriptions and notifies all listeners
void _subscriptionDataUpdate(LinkFiveSubscriptionData? data) async {
availableSubscriptionData = data;
notifyListeners();
}
/// Saves active Subscriptions and notifies all listeners
void _activeSubscriptionDataUpdate(LinkFiveActiveSubscriptionData? data) {
activeSubscriptionData = data;
notifyListeners();
}
/// Fetch all available Subscription for purchase for the user
/// The provider will notify you for changes
fetchSubscriptions() async {
return LinkFivePurchases.fetchSubscriptions();
}
/// Restore Subscriptions of the user
/// The provider will notify you for changes
restoreSubscriptions() async {
return LinkFivePurchases.restore();
}
/// make a purchase
/// The provider will notify you for changes
/// The future returns if the "purchase screen" is visible to the user
/// and not if the purchase was successful
purchase(ProductDetails productDetail) async {
return LinkFivePurchases.purchase(productDetail);
}
@override
void dispose() async {
for (var element in _streams) {
await element.cancel();
}
_streams = [];
super.dispose();
}
/// helper function for the paywall to make it easier.
/// returns the subscriptionDataList or if null, an empty list
List<SubscriptionData> getSubscriptionListData(BuildContext context) =>
availableSubscriptionData?.getSubscriptionData(context: context) ?? [];
}