I have integrated in flutter in_app_purchase subscription (android ), but it always automatically refund after 3 days
I am using below code for flutter subscription. I can't find the actual issue in the code, please help what I have missed in this code
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'util/ConsumableStore.dart';
const bool _kAutoConsume = true;
const String _kConsumableId = 'consumable';
const List _kProductIds = ['subscription_item', 'purchase_item'];
class StoreScreenNew extends StatefulWidget {
@override
_StoreScreenState createState() => _StoreScreenState();
}
class _StoreScreenState extends State {
final InAppPurchaseConnection _connection = InAppPurchaseConnection.instance;
StreamSubscription> _subscription;
List _notFoundIds = [];
List _products = [];
List _purchases = [];
bool _isAvailable = false;
bool _purchasePending = false;
bool _loading = true;
String _queryProductError;
bool _isConnected = false;
String storeName = "";
@override
void initState() {
checkInternet().then((onValue) {
setState(() {
_isConnected = onValue;
});
});
Stream purchaseUpdated =
InAppPurchaseConnection.instance.purchaseUpdatedStream;
_subscription = purchaseUpdated.listen((purchaseDetailsList) {
_listenToPurchaseUpdated(purchaseDetailsList);
}, onDone: () {
_subscription.cancel();
}, onError: (error) {
// handle error here.
});
initStoreInfo();
super.initState();
}
Future checkInternet() async {
try {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
return Future.value(true);
} else {
return Future.value(false);
}
} on SocketException catch (_) {
return Future.value(false);
}
}
Future initStoreInfo() async {
if (Platform.isIOS) {
storeName = "iTunes";
} else {
storeName = "Play Store";
}
final bool isAvailable = await _connection.isAvailable();
if (!isAvailable) {
setState(() {
_isAvailable = isAvailable;
_products = [];
_purchases = [];
_notFoundIds = [];
_purchasePending = false;
_loading = false;
});
return;
}
ProductDetailsResponse productDetailResponse =
await _connection.queryProductDetails(_kProductIds.toSet());
if (productDetailResponse.error != null) {
setState(() {
_queryProductError = productDetailResponse.error.message;
_isAvailable = isAvailable;
_products = productDetailResponse.productDetails;
_purchases = [];
_notFoundIds = productDetailResponse.notFoundIDs;
_purchasePending = false;
_loading = false;
});
return;
}
if (productDetailResponse.productDetails.isEmpty) {
setState(() {
_queryProductError = null;
_isAvailable = isAvailable;
_products = productDetailResponse.productDetails;
_purchases = [];
_notFoundIds = productDetailResponse.notFoundIDs;
_purchasePending = false;
_loading = false;
});
return;
}
final QueryPurchaseDetailsResponse purchaseResponse =
await _connection.queryPastPurchases();
if (purchaseResponse.error != null) {
// handle query past purchase error..
}
final List verifiedPurchases = [];
for (PurchaseDetails purchase in purchaseResponse.pastPurchases) {
if (await _verifyPurchase(purchase)) {
verifiedPurchases.add(purchase);
}
}
setState(() {
_isAvailable = isAvailable;
_products = productDetailResponse.productDetails;
_purchases = verifiedPurchases;
_notFoundIds = productDetailResponse.notFoundIDs;
_purchasePending = false;
_loading = false;
});
}
@override
void dispose() {
_subscription.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
List stack = [];
if (_queryProductError == null) {
stack.add(
ListView(
children: [
_buildConnectionCheckTile(),
_buildProductList(),
addPrivacy(),
addLink()
],
),
);
} else {
stack.add(Center(
child: Text(_queryProductError),
));
}
if (_purchasePending) {
stack.add(
Stack(
children: [
Opacity(
opacity: 0.3,
child: const ModalBarrier(dismissible: false, color: Colors.grey),
),
Center(
child: CircularProgressIndicator(),
),
],
),
);
}
return MaterialApp(
home: Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).primaryColor,
automaticallyImplyLeading: true,
title: Text('PRO',
style: Theme.of(context).textTheme.headline5),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.pop(context, false),
)),
body: _isConnected
? Stack(
children: stack,
)
: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
height: 10,
),
Container(
margin: EdgeInsets.all(20),
child: Text(
"Check your internet connection and try again.",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.black45, fontSize: 26),
))
])),
),
);
}
Card _buildConnectionCheckTile() {
if (_loading) {
return Card(child: ListTile(title: const Text('Trying to connect...')));
}
final Widget storeHeader = ListTile(
leading: Icon(_isAvailable ? Icons.check : Icons.block,
color: _isAvailable ? Colors.green : ThemeData.light().errorColor),
title: Text(
'The store is ' + (_isAvailable ? 'available' : 'unavailable') + '.'),
);
final List children = [
!_isAvailable ? storeHeader : Container()
];
if (!_isAvailable) {
children.addAll([
Divider(),
ListTile(
title: Text('Not connected',
style: TextStyle(color: ThemeData.light().errorColor)),
subtitle: const Text(
'Unable to connect to the payments processor. Has this app been configured correctly? See the example README for instructions.'),
),
]);
}
return Card(child: Column(children: children));
}
Card _buildProductList() {
if (_loading) {
return Card(
child: (ListTile(
leading: CircularProgressIndicator(),
title: Text('Fetching products...'))));
}
if (!_isAvailable) {
return Card();
}
final ListTile productHeader = ListTile(
title: Text(
'Available Options',
style: TextStyle(fontSize: 20),
),
);
List productList = [];
if (_notFoundIds.isNotEmpty) {
productList.add(ListTile(
title: Text('[${_notFoundIds.join(", ")}] not found',
style: TextStyle(color: ThemeData.light().errorColor)),
subtitle: Text(
'This app needs special configuration to run. Please see example/README.md for instructions.')));
}
Map purchases =
Map.fromEntries(_purchases.map((PurchaseDetails purchase) {
if (purchase.pendingCompletePurchase) {
InAppPurchaseConnection.instance.completePurchase(purchase);
}
return MapEntry(purchase.productID, purchase);
}));
productList.addAll(_products.map(
(ProductDetails productDetails) {
PurchaseDetails previousPurchase = purchases[productDetails.id];
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white,
boxShadow: [
BoxShadow(color: Colors.grey, spreadRadius: 1),
],
),
margin: EdgeInsets.all(5),
padding: EdgeInsets.all(10),
child: Column(
children: [
Text(
productDetails.title,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color:
previousPurchase != null ? Colors.green : Colors.black),
),
SizedBox(
height: 10,
),
Divider(),
SizedBox(
height: 10,
),
Text(
productDetails.description,
textAlign: TextAlign.left,
),
SizedBox(
height: 20,
),
Divider(),
Container(
alignment: Alignment.bottomRight,
child: previousPurchase != null
? Container(
padding: const EdgeInsets.all(10.0),
decoration: new BoxDecoration(
shape: BoxShape.circle,
color: Colors.green,
),
child: Icon(
Icons.check,
size: 30,
color: Colors.white,
))
: FlatButton(
child: Text(
productDetails.price,
style: TextStyle(fontSize: 18),
),
color: Colors.green[800],
textColor: Colors.white,
onPressed: () {
PurchaseParam purchaseParam = PurchaseParam(
productDetails: productDetails,
applicationUserName: null,
sandboxTesting: false);
if (productDetails.id == _kConsumableId) {
_connection.buyConsumable(
purchaseParam: purchaseParam,
autoConsume: _kAutoConsume || Platform.isIOS);
} else {
_connection.buyNonConsumable(
purchaseParam: purchaseParam);
}
},
))
],
),
);
},
));
return Card(
margin: EdgeInsets.all(10),
elevation: 0,
child: Column(
children: [
productHeader,
Divider(),
] +
productList,
));
}
void showPendingUI() {
setState(() {
_purchasePending = true;
});
}
void deliverProduct(PurchaseDetails purchaseDetails) async {
if (purchaseDetails.productID == _kConsumableId) {
await ConsumableStore.save(purchaseDetails.purchaseID);
App.setPurchasesStatus(true);
setState(() {
_purchasePending = false;
});
} else {
setState(() {
_purchases.add(purchaseDetails);
_purchasePending = false;
});
}
}
void handleError(IAPError error) {
setState(() {
_purchasePending = false;
});
}
Future _verifyPurchase(PurchaseDetails purchaseDetails) {
return Future.value(true);
}
void _handleInvalidPurchase(PurchaseDetails purchaseDetails) {
}
void _listenToPurchaseUpdated(List purchaseDetailsList) {
purchaseDetailsList.forEach((PurchaseDetails purchaseDetails) async {
if (purchaseDetails.status == PurchaseStatus.pending) {
showPendingUI();
} else {
if (purchaseDetails.status == PurchaseStatus.error) {
handleError(purchaseDetails.error);
} else if (purchaseDetails.status == PurchaseStatus.purchased) {
bool valid = await _verifyPurchase(purchaseDetails);
if (valid) {
deliverProduct(purchaseDetails);
} else {
_handleInvalidPurchase(purchaseDetails);
return;
}
}
if (Platform.isAndroid) {
if (!_kAutoConsume && purchaseDetails.productID == _kConsumableId) {
await InAppPurchaseConnection.instance
.consumePurchase(purchaseDetails);
}
}
if (purchaseDetails.pendingCompletePurchase) {
await InAppPurchaseConnection.instance
.completePurchase(purchaseDetails);
}
}
});
}
}
