Flutter In App Purchases with List of products | paying for App features/Digital items and Unlock them | Non Consumable.
Flutter In App Purchases with List of products | paying for App features/Digital items and Unlock them | Non Consumable.
NOTE: For list of digital items we need to create more than one Product IDs in our google play console which is explained in our youtube video and add them in our providermodel.dart class and we need to some changes in our UI homescreen.dart file.
1- Add these permissions to
android/app/src/main/AndroidManifest.xml
1 2 | <uses-permission android:name="com.android.vending.BILLING" /> <uses-permission android:name="android.permission.INTERNET"/> |
2- Add this to dependencies block
android/app/build.gradle
1 2 3 4 5 | dependencies {implementation 'com.android.billingclient:billing:3.0.2'} |
3- Make sure you are using your own product ID
4- Add this to pubspec.yaml file:
1 | in_app_purchase: ^0.5.2 |
This is main.dart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | import 'package:flutter/material.dart';import 'package:in_app_purchase/in_app_purchase.dart';import 'homescreen.dart';import 'package:provider/provider.dart';import 'providermodel.dart';void main() { InAppPurchaseConnection.enablePendingPurchases(); runApp(ChangeNotifierProvider( create: (context) => ProviderModel(), child: MaterialApp(home: MyApp(),)));}class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState();}class _MyAppState extends State<MyApp> { @override void initState() { var provider = Provider.of<ProviderModel>(context, listen: false);provider.initialize(); super.initState(); } @override void dispose() { var provider = Provider.of<ProviderModel>(context, listen: false); provider.subscription.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return HomeScreen(); }} |
Here is our UI : homescreen.dart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | import 'package:flutter/material.dart';import 'package:in_app_purchase/in_app_purchase.dart';import 'package:provider/provider.dart';import 'providermodel.dart';class HomeScreen extends StatefulWidget { @override _HomeScreenState createState() => _HomeScreenState();}class _HomeScreenState extends State<HomeScreen> { InAppPurchaseConnection _iap = InAppPurchaseConnection.instance; @override void initState() { var provider = Provider.of<ProviderModel>(context, listen: false); provider.verifyPurchase(); super.initState(); } void _buyProduct(ProductDetails prod) { final PurchaseParam purchaseParam = PurchaseParam(productDetails: prod); _iap.buyNonConsumable(purchaseParam: purchaseParam); } @override Widget build(BuildContext context) { var provider = Provider.of<ProviderModel>(context);// This is our app UI where we show our products return Scaffold( appBar: AppBar( title: Text("In App Purchase List of products"), ), body: Center( child: Container( width: 300, child: ListView( children: [ Container( child: Padding( padding: const EdgeInsets.all(8.0), child: Container( color: Colors.grey.withOpacity(0.2), child: FittedBox( child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Text( provider.available ? "Store is Available" : "Store is not Available", style: TextStyle(fontSize: 22, color: Colors.green), ), ], ), ), ), ), ), for (var prod in provider.products) if (provider.hasPurchased(prod.id) != null) ...[ Center( child: Text(// If you want to change title change it from google console in-app products section "You Paid for ${prod.title} \n THANK YOU!<img draggable="false" role="img" class="emoji" alt=" textAlign: TextAlign.center, style: TextStyle(fontSize: 22, color: Colors.black), ), ), Container( height: 50, ), ] else ...[ Container( child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ Text(// If you want to change description change it from google console in-app products section "${prod.description}", style: TextStyle(fontSize: 22, color: Colors.black54), textAlign: TextAlign.center, ), Text(// If you want to change price change it from google console in-app products section "${prod.price}", style: TextStyle(fontSize: 22, color: Colors.black54), textAlign: TextAlign.center, ), FlatButton( onPressed: () => _buyProduct(prod), child: Text('Pay'), color: Colors.green, ), ], ), ), Container( height: 10, ) ] ], ), ), ), ); }} |
We are using provider state management so add this to your package’s pubspec.yaml file:
provider: ^4.3.1Our provider model: providermodel.dart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | import 'dart:async';import 'dart:io';import 'package:flutter/cupertino.dart';import 'package:in_app_purchase/in_app_purchase.dart';import 'package:collection/collection.dart';class ProviderModel with ChangeNotifier { InAppPurchaseConnection _iap = InAppPurchaseConnection.instance; bool available = true; StreamSubscription subscription;// here to add more Products in this case we have 2 Product IDs final String myFirstProductID = 'in_app_payment_test'; final String mySecondProductID = 'in_app_payment_test2';// here to Create boolean for our First Product to check if its Purchased our not. bool _isFirstItemPurchased = false; bool get isFirstItemPurchased => _isFirstItemPurchased; set isFirstItemPurchased(bool value) { _isFirstItemPurchased = value; notifyListeners(); }// here to Create boolean for our Second Product to check if its Purchased our not. bool _isSecondItemPurchased = false; bool get isSecondItemPurchased => _isSecondItemPurchased; set isSecondItemPurchased(bool value) { _isSecondItemPurchased = value; notifyListeners(); }// here is the list of purchases List _purchases = []; List get purchases => _purchases; set purchases(List value) { _purchases = value; notifyListeners(); }// our product list List _products = []; List get products => _products; set products(List value) { _products = value; notifyListeners(); }// here we initialize and check our purchases void initialize() async { available = await _iap.isAvailable(); if (available) { await _getProducts(); await _getPastPurchases(); verifyPurchase(); subscription = _iap.purchaseUpdatedStream.listen((data) { purchases.addAll(data); verifyPurchase(); }); } } void verifyPurchase() {// here verify and complete our First Product Purchase PurchaseDetails purchase = hasPurchased(myFirstProductID); if (purchase != null && purchase.status == PurchaseStatus.purchased) { if (purchase.pendingCompletePurchase) { _iap.completePurchase(purchase); if (purchase != null && purchase.status == PurchaseStatus.purchased) { isFirstItemPurchased = true; } } }// here verify and complete our second Product Purchase PurchaseDetails secondPurchase = hasPurchased(mySecondProductID); if (secondPurchase != null && secondPurchase.status == PurchaseStatus.purchased) { if (secondPurchase.pendingCompletePurchase) { _iap.completePurchase(secondPurchase); if (secondPurchase != null && secondPurchase.status == PurchaseStatus.purchased) { isSecondItemPurchased = true; } } } } PurchaseDetails hasPurchased(String productID) { return purchases .firstWhereOrNull((purchase) => purchase.productID == productID); } Future<void> _getProducts() async { Set<String> ids = Set.from([myFirstProductID, mySecondProductID]); ProductDetailsResponse response = await _iap.queryProductDetails(ids); products = response.productDetails; } Future<void> _getPastPurchases() async { QueryPurchaseDetailsResponse response = await _iap.queryPastPurchases(); for (PurchaseDetails purchase in response.pastPurchases) { if (Platform.isIOS) { _iap.consumePurchase(purchase); } } purchases = response.pastPurchases; }} |