Apple IAP

This commit is contained in:
Hillel Coren 2022-07-20 12:07:33 +03:00
parent 1ab508420d
commit b69f7f6960
2 changed files with 19 additions and 29 deletions

View File

@ -7,6 +7,7 @@ import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart'; import 'package:flutter_redux/flutter_redux.dart';
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
import 'package:in_app_purchase/in_app_purchase.dart'; import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:in_app_purchase_android/billing_client_wrappers.dart'; import 'package:in_app_purchase_android/billing_client_wrappers.dart';
import 'package:in_app_purchase_android/in_app_purchase_android.dart'; import 'package:in_app_purchase_android/in_app_purchase_android.dart';
@ -14,8 +15,8 @@ import 'package:in_app_purchase_storekit/in_app_purchase_storekit.dart';
import 'package:in_app_purchase_storekit/store_kit_wrappers.dart'; import 'package:in_app_purchase_storekit/store_kit_wrappers.dart';
import 'package:invoiceninja_flutter/constants.dart'; import 'package:invoiceninja_flutter/constants.dart';
import 'package:invoiceninja_flutter/data/web_client.dart'; import 'package:invoiceninja_flutter/data/web_client.dart';
import 'package:invoiceninja_flutter/main_app.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart'; import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/utils/dialogs.dart';
import 'package:invoiceninja_flutter/utils/localization.dart'; import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
@ -308,16 +309,6 @@ class _UpgradeDialogState extends State<UpgradeDialog> {
}); });
} }
Future<bool> _verifyPurchase(PurchaseDetails purchaseDetails) {
// IMPORTANT!! Always verify a purchase before delivering the product.
// For the purpose of an example, we directly return true.
return Future<bool>.value(true);
}
void _handleInvalidPurchase(PurchaseDetails purchaseDetails) {
// handle invalid purchase here if _verifyPurchase` failed.
}
Future<void> _listenToPurchaseUpdated( Future<void> _listenToPurchaseUpdated(
List<PurchaseDetails> purchaseDetailsList) async { List<PurchaseDetails> purchaseDetailsList) async {
for (final PurchaseDetails purchaseDetails in purchaseDetailsList) { for (final PurchaseDetails purchaseDetails in purchaseDetailsList) {
@ -328,13 +319,7 @@ class _UpgradeDialogState extends State<UpgradeDialog> {
handleError(purchaseDetails.error); handleError(purchaseDetails.error);
} else if (purchaseDetails.status == PurchaseStatus.purchased || } else if (purchaseDetails.status == PurchaseStatus.purchased ||
purchaseDetails.status == PurchaseStatus.restored) { purchaseDetails.status == PurchaseStatus.restored) {
final bool valid = await _verifyPurchase(purchaseDetails); deliverProduct(purchaseDetails);
if (valid) {
deliverProduct(purchaseDetails);
} else {
_handleInvalidPurchase(purchaseDetails);
return;
}
} }
if (purchaseDetails.pendingCompletePurchase) { if (purchaseDetails.pendingCompletePurchase) {
await _inAppPurchase.completePurchase(purchaseDetails); await _inAppPurchase.completePurchase(purchaseDetails);
@ -345,6 +330,7 @@ class _UpgradeDialogState extends State<UpgradeDialog> {
Future<void> confirmPriceChange(BuildContext context) async { Future<void> confirmPriceChange(BuildContext context) async {
if (Platform.isAndroid) { if (Platform.isAndroid) {
final localization = AppLocalization.of(context);
final InAppPurchaseAndroidPlatformAddition androidAddition = final InAppPurchaseAndroidPlatformAddition androidAddition =
_inAppPurchase _inAppPurchase
.getPlatformAddition<InAppPurchaseAndroidPlatformAddition>(); .getPlatformAddition<InAppPurchaseAndroidPlatformAddition>();
@ -352,18 +338,15 @@ class _UpgradeDialogState extends State<UpgradeDialog> {
await androidAddition.launchPriceChangeConfirmationFlow( await androidAddition.launchPriceChangeConfirmationFlow(
sku: 'purchaseId', sku: 'purchaseId',
); );
if (priceChangeConfirmationResult.responseCode == BillingResponse.ok) { if (priceChangeConfirmationResult.responseCode == BillingResponse.ok) {
ScaffoldMessenger.of(navigatorKey.currentContext) showToast(localization.priceChangeAccepted);
.showSnackBar(const SnackBar(
content: Text('Price change accepted'),
));
} else { } else {
ScaffoldMessenger.of(navigatorKey.currentContext).showSnackBar(SnackBar( showErrorDialog(
content: Text( context: context,
priceChangeConfirmationResult.debugMessage ?? message: priceChangeConfirmationResult.debugMessage ??
'Price change failed with code ${priceChangeConfirmationResult.responseCode}', localization.priceChangeFailed +
), ' ${priceChangeConfirmationResult.responseCode}');
));
} }
} }
if (Platform.isIOS) { if (Platform.isIOS) {

View File

@ -16,6 +16,8 @@ mixin LocalizationsProvider on LocaleCodeAware {
static final Map<String, Map<String, String>> _localizedValues = { static final Map<String, Map<String, String>> _localizedValues = {
'en': { 'en': {
// STARTER: lang key - do not remove comment // STARTER: lang key - do not remove comment
'price_change_accepted': 'Price change accepted',
'price_change_failed': 'Price change failed with code',
'restore_purchases': 'Restore Purchases', 'restore_purchases': 'Restore Purchases',
'activate': 'Activate', 'activate': 'Activate',
'connect_apple': 'Connect Apple', 'connect_apple': 'Connect Apple',
@ -76192,12 +76194,17 @@ mixin LocalizationsProvider on LocaleCodeAware {
_localizedValues[localeCode]['activate'] ?? _localizedValues[localeCode]['activate'] ??
_localizedValues['en']['activate']; _localizedValues['en']['activate'];
String get restorePurchases => String get restorePurchases =>
_localizedValues[localeCode]['restore_purchases'] ?? _localizedValues[localeCode]['restore_purchases'] ??
_localizedValues['en']['restore_purchases']; _localizedValues['en']['restore_purchases'];
String get priceChangeAccepted =>
_localizedValues[localeCode]['price_change_accepted'] ??
_localizedValues['en']['price_change_accepted'];
String get priceChangeFailed =>
_localizedValues[localeCode]['price_change_failed'] ??
_localizedValues['en']['price_change_failed'];
// STARTER: lang field - do not remove comment // STARTER: lang field - do not remove comment