How to add In-App Purchase subscription in Flutter.


How to add In-App Purchase subscription in Flutter.




In this tutorial we will teach you how to implement subscription in your app. For this we will use the in app purchases package. In addition we will have to create a product ID for subscription in our Google Play Console which we will use in our project.

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

android/app/build.gradle inside dependencies block

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:

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
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: 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
113
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: [
              !provider.isPurchased
                  ? 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),
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
              ):SizedBox.shrink(),
              provider.isPurchased
                  ? Center(child: Text("Premium Plan <img draggable="false" role="img" class="emoji" alt="💎" src="https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/svg/1f48e.svg">"))
                  : Center(
                    child: Text(
                        "Get Premium Plan Subscription",
                        style: TextStyle(
                            fontSize: 18, backgroundColor: Colors.greenAccent),
                      ),
                  ),
              for (var prod in provider.products)
                if (provider.hasPurchased(prod.id) != null) ...[
                  Center(
                    child: FittedBox(
                      child: Text(
                        'THANK YOU! <img draggable="false" role="img" class="emoji" alt="💕" src="https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/svg/1f495.svg">',
                        textAlign: TextAlign.center,
                        style: TextStyle(fontSize: 60, color: Colors.black),
                      ),
                    ),
                  ),
                  Container(
                    height: 50,
                  ),
                ] else ...[
                  Container(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.start,
                      children: [
                        Text(
                          "Unlock All Features Subscription: ${prod.price} per month",
                          style: TextStyle(fontSize: 18, 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
98
99
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;
  final String myProductID = 'monthly_sub30';
 
 
  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.

Flutter Native Ad Templates Implementation