Flutter In App Purchases paying for App features and Unlock them | Non Consumable.





Non-consumables are purchased once by users. Services that do not expire or decrease with use are usually implemented as non-consumables, such as removing ads from App for users.

In this tutorial, we will cover how to Implement Non-Consumables using the in_app_purchase plugin in your flutter App.


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 line in the dependencies block of your project's build.gradle.

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 plugin to your package’s pubspec.yaml file:

1
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
import 'dart:async';
 
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 first Screen UI file where we show our pay button: 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
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);
 
 
    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: Row(
                      mainAxisAlignment: MainAxisAlignment.start,
                      children: [
                        Text(provider.available ? "Store is Available" : "Store is not Available",
                          style: TextStyle(fontSize: 22, color: Colors.green),),
                      ],
                    ),
                  ),
                ),
              ),
              provider.isPurchased ? Row(children: [Text("Features Unlocked"),Icon(Icons.lock_open)  ]
 
 
                ,):Row(children: [Text("Features Locked"),Icon(Icons.lock)],),
 
 
              for (var prod in provider.products)
                if (provider.hasPurchased(prod.id) != null) ...[
                  Center(
                    child: FittedBox(
                      child: Text(
                        'THANK YOU!',
                        textAlign: TextAlign.center,
                        style: TextStyle(fontSize: 60, color: Colors.black),
                      ),
                    ),
                  ),
                  Container(
                    height: 50,
                  ),
                ]else ...[
                  Container(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.start,
                      children: [
                        Text(
                          "Unlock Features pay ${prod.price}",
                          style: TextStyle(fontSize: 22, color: Colors.black54),
                          textAlign: TextAlign.center,
                        ),
                        FlatButton(
                          onPressed: () => _buyProduct(prod),
                          child: Text('Pay'),
                          color: Colors.green,
                        ),
                      ],
                    ),
                  ),
                ]
 
 
 
            ],
          ),
        ),
      ),
    );
  }
}

We are going to use provider state management so add this to your package’s pubspec.yaml file:

provider: ^4.3.1

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
import 'dart:async';
import 'dart:io';
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 = 'in_app_payment_test';
 
 
  bool _isPurchased = false;
  bool get isPurchased => _isPurchased;
  set isPurchased(bool value) {
    _isPurchased = 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;
        }
      }
 
    }
  }
 
 
 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