In-App Purchase Consumable in Flutter with donations and rewards examples.

 

In-App Purchase Consumable in Flutter with donations and rewards examples.




In this flutter article, we will implement consumables using in-app purchases package using donation and rewards examples. Consumable products can be purchased multiple times they can be used for like donations and buying coins for digital goods.

1- Add these permissions to

android/app/src/main/AndroidManifest.xml

    <uses-permission android:name="com.android.vending.BILLING" />
    <uses-permission android:name="android.permission.INTERNET"/>

2- Add this line in the dependencies block

android/app/build.gradle



dependencies {

implementation 'com.android.billingclient:billing:3.0.2'

}

3- Make sure you are using your own product ID

4- Add this to your package’s pubspec.yaml file:

in_app_purchase: ^0.5.2

This is our file: 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
48
49
50
51
52
53
54
55
56
57
import 'package:flutter/material.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:shared_preferences/shared_preferences.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();
 
    _getValueFromShared(provider);
    super.initState();
  }
 
 
  _getValueFromShared(provider) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    int coinValue = prefs.getInt('coins') ?? 0;
    bool isPurchased = prefs.getBool('isPurchased') ?? false;
    provider.coins = coinValue;
    provider.isPurchased = isPurchased;
  }
 
  @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 first Screen UI file: 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
108
109
110
111
112
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.buyConsumable(purchaseParam: purchaseParam, autoConsume: true);
  }
 
 
  @override
  Widget build(BuildContext context) {
    var provider = Provider.of<ProviderModel>(context);
 
 
    return Scaffold(
      appBar: AppBar(
        title: Text("In App Purchase"),
      ),
      body: Center(
        child: Container(
          height: 500,
          width: 200,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            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)
                Container(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.start,
                    children: [
                      Text(
                        "Donate / Buy Coins ${prod.price}",
                        style: TextStyle(fontSize: 22, color: Colors.black54),
                        textAlign: TextAlign.center,
                      ),
                      FlatButton(
                        onPressed: () => _buyProduct(prod),
                        child: Text('Donate / Buy Coins'),
                        color: Colors.green,
                      ),
                    ],
                  ),
                ),
 
              provider.isPurchased?Center(
                child: FittedBox(
                  child: Text(
                    'THANK YOU Greatly\nappreciate your\n<img draggable="false" role="img" class="emoji" alt="💲" src="https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/svg/1f4b2.svg">donation!!',
                    textAlign: TextAlign.center,
                    style: TextStyle(fontSize: 20, color: Colors.black),
                  ),
                ),
              ):SizedBox.shrink(),
 
              Center(
                child: FittedBox(
                  child: Text(
                    '<img draggable="false" role="img" class="emoji" alt="🪙" src="https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/svg/1fa99.svg"> ${provider.coins}',
                    textAlign: TextAlign.center,
                    style: TextStyle(fontSize: 60, color: Colors.black),
                  ),
                ),
              ),
 
 
 
 
 
            ],
          ),
        ),
      ),
    );
  }
}

We are going to use provider state management and Shared preferences to save app status so add this to your package’s pubspec.yaml file:

provider: ^4.3.1
shared_preferences: ^2.0.5

This is our provider model class: 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
import 'dart:async';
import 'dart:io';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:collection/collection.dart';
 
 
import 'package:flutter/cupertino.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
 
class ProviderModel with ChangeNotifier {
  InAppPurchaseConnection _iap = InAppPurchaseConnection.instance;
  bool available = true;
  StreamSubscription subscription;
  final String myProductID = 'consumable_product';
 
  bool _isPurchased = false;
  bool get isPurchased => _isPurchased;
  set isPurchased(bool value) {
    _isPurchased = value;
    notifyListeners();
  }
 
  int _coins = 0;
  int get coins => _coins;
  set coins(int value) {
    _coins = value;
    notifyListeners();
  }
 
  List _purchases = [];
  List get purchases => _purchases;
  set purchases(List value) {
    _purchases = value;
    notifyListeners();
  }
 
  List _products = [];
  List get products => _products;
  set products(List value) {
    _products = value;
    notifyListeners();
  }
 
  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() {
    PurchaseDetails purchase = hasPurchased(myProductID);
 
    if (purchase != null && purchase.status == PurchaseStatus.purchased) {
      if (purchase.pendingCompletePurchase) {
        _iap.completePurchase(purchase);
         
if (purchase != null && purchase.status == PurchaseStatus.purchased) {
         isPurchased = true;
        _coins += 10;
        }
 
        _saveValueInShared();
      }
    }
  }
 
  _saveValueInShared() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    prefs.setInt('coins', coins);
 
    prefs.setBool('isPurchased', isPurchased);
  }
 
 
 PurchaseDetails hasPurchased(String productID) {
    return purchases
        .firstWhereOrNull((purchase) => purchase.productID == productID);
  }
 
  Future<void> _getProducts() async {
    Set<String> ids = Set.from([myProductID]);
    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;
  }
}

Popular posts from this blog

In-App Purchase with null safety in Flutter 2.5.

How to add In-App Purchase subscription in Flutter.

Flutter Native Ad Templates Implementation