Offer Code Redemption
Guide to implementing promotional offer codes and subscription management with flutter_inapp_purchase v6.0.0, covering iOS and Android platforms.
Overview
This plugin provides native support for:
- iOS: Offer code redemption sheet and subscription management (iOS 14+)
- Android: Deep linking to subscription management
- Cross-platform: Introductory offer eligibility checking
iOS Offer Code Redemption
Present Code Redemption Sheet
import 'dart:io';
import 'package:flutter_inapp_purchase/flutter_inapp_purchase.dart';
class OfferCodeHandler {
final _iap = FlutterInappPurchase.instance;
/// Present iOS system offer code redemption sheet (iOS 16+)
Future<void> presentOfferCodeRedemption() async {
if (!Platform.isIOS) {
debugPrint('Offer code redemption is only available on iOS');
return;
}
try {
// Present the system offer code redemption sheet
await _iap.presentCodeRedemptionSheet();
debugPrint('Offer code redemption sheet presented');
// Results will come through purchaseUpdated stream
_listenForRedemptionResults();
} catch (e) {
debugPrint('Failed to present offer code sheet: $e');
}
}
/// Alternative method for iOS 14+ compatibility
Future<void> presentOfferCodeRedemptionIOS() async {
if (!Platform.isIOS) return;
try {
await _iap.presentCodeRedemptionSheetIOS();
debugPrint('iOS offer code redemption sheet presented');
} catch (e) {
debugPrint('Failed to present iOS offer code sheet: $e');
}
}
void _listenForRedemptionResults() {
FlutterInappPurchase.purchaseUpdated.listen((purchase) {
if (purchase != null) {
debugPrint('Offer code redeemed: ${purchase.productId}');
// Handle successful redemption
_handleRedeemedPurchase(purchase);
}
});
}
void _handleRedeemedPurchase(PurchasedItem purchase) {
// Process the redeemed purchase
// Verify receipt, deliver content, etc.
}
}
Introductory Offers
class IntroductoryOfferHandler {
final _iap = FlutterInappPurchase.instance;
/// Check if user is eligible for introductory offer (iOS only)
Future<bool> isEligibleForIntroductoryOffer(String productId) async {
if (!Platform.isIOS) return false;
try {
final isEligible = await _iap.isEligibleForIntroOfferIOS(productId);
debugPrint('Intro offer eligibility for $productId: $isEligible');
return isEligible;
} catch (e) {
debugPrint('Failed to check intro offer eligibility: $e');
return false;
}
}
/// Get subscription status for a specific product
Future<Map<String, dynamic>?> getSubscriptionStatus(String productId) async {
if (!Platform.isIOS) return null;
try {
final status = await _iap.getSubscriptionStatusIOS(productId);
debugPrint('Subscription status for $productId: $status');
return status;
} catch (e) {
debugPrint('Failed to get subscription status: $e');
return null;
}
}
}
Subscription Management
iOS Subscription Management
class SubscriptionManager {
final _iap = FlutterInappPurchase.instance;
/// Show iOS subscription management screen (iOS 15+)
Future<void> showManageSubscriptions() async {
if (!Platform.isIOS) {
debugPrint('Subscription management is only available on iOS');
return;
}
try {
await _iap.showManageSubscriptions();
debugPrint('Subscription management screen presented');
} catch (e) {
debugPrint('Failed to show subscription management: $e');
}
}
/// Alternative method for iOS-specific subscription management
Future<void> showManageSubscriptionsIOS() async {
if (!Platform.isIOS) return;
try {
await _iap.showManageSubscriptionsIOS();
debugPrint('iOS subscription management screen presented');
} catch (e) {
debugPrint('Failed to show iOS subscription management: $e');
}
}
/// Get subscription group information (iOS only)
Future<String?> getSubscriptionGroup(String productId) async {
if (!Platform.isIOS) return null;
try {
final group = await _iap.getSubscriptionGroupIOS(productId);
debugPrint('Subscription group for $productId: $group');
return group;
} catch (e) {
debugPrint('Failed to get subscription group: $e');
return null;
}
}
}
Android Subscription Management
Deep Linking to Subscriptions
class AndroidSubscriptionManager {
final _iap = FlutterInappPurchase.instance;
/// Open Android subscription management (deep link to Play Store)
Future<void> openSubscriptionManagement([String? productId]) async {
if (!Platform.isAndroid) {
debugPrint('Android subscription management is only available on Android');
return;
}
try {
// Deep link to subscription management in Play Store
await _iap.deepLinkToSubscriptionsAndroid(sku: productId);
debugPrint('Opened Android subscription management');
} catch (e) {
debugPrint('Failed to open subscription management: $e');
}
}
/// Get Android billing connection state
Future<String?> getConnectionState() async {
if (!Platform.isAndroid) return null;
try {
final state = await _iap.getConnectionStateAndroid();
debugPrint('Android connection state: $state');
return state;
} catch (e) {
debugPrint('Failed to get connection state: $e');
return null;
}
}
}
Complete Implementation Example
Cross-Platform Offer Handler
class CrossPlatformOfferHandler {
final _iap = FlutterInappPurchase.instance;
/// Present offer code redemption (iOS) or subscription management (Android)
Future<void> handleOfferRedemption() async {
try {
if (Platform.isIOS) {
// iOS: Present code redemption sheet
await _iap.presentCodeRedemptionSheet();
debugPrint('iOS offer code redemption sheet presented');
_listenForPurchases();
} else if (Platform.isAndroid) {
// Android: Open subscription management
await _iap.deepLinkToSubscriptionsAndroid();
debugPrint('Android subscription management opened');
}
} catch (e) {
debugPrint('Failed to handle offer redemption: $e');
}
}
/// Check introductory offer eligibility (iOS only)
Future<bool> checkIntroOfferEligibility(String productId) async {
if (!Platform.isIOS) return false;
try {
return await _iap.isEligibleForIntroOfferIOS(productId);
} catch (e) {
debugPrint('Failed to check intro offer eligibility: $e');
return false;
}
}
void _listenForPurchases() {
FlutterInappPurchase.purchaseUpdated.listen((purchase) {
if (purchase != null) {
debugPrint('Purchase received: ${purchase.productId}');
// Handle the purchase
}
});
}
}
Additional Features
App Store Information (iOS)
class AppStoreInfo {
final _iap = FlutterInappPurchase.instance;
/// Get App Store country code (iOS only)
Future<String?> getAppStoreCountry() async {
if (!Platform.isIOS) return null;
try {
final country = await _iap.getAppStoreCountryIOS();
debugPrint('App Store country: $country');
return country;
} catch (e) {
debugPrint('Failed to get App Store country: $e');
return null;
}
}
/// Get promoted product (iOS only)
Future<String?> getPromotedProduct() async {
if (!Platform.isIOS) return null;
try {
final productId = await _iap.getPromotedProduct();
debugPrint('Promoted product: $productId');
return productId;
} catch (e) {
debugPrint('Failed to get promoted product: $e');
return null;
}
}
}
Usage Examples
In a Flutter App
class OfferRedemptionPage extends StatelessWidget {
final _offerHandler = CrossPlatformOfferHandler();
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Redeem Offers'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (Platform.isIOS) ...[
ElevatedButton(
onPressed: () async {
await _offerHandler.handleOfferRedemption();
},
child: Text('Redeem Offer Code'),
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () async {
final eligible = await _offerHandler.checkIntroOfferEligibility('your_product_id');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Eligible for intro offer: $eligible')),
);
},
child: Text('Check Intro Offer Eligibility'),
),
],
if (Platform.isAndroid) ...[
ElevatedButton(
onPressed: () async {
await _offerHandler.handleOfferRedemption();
},
child: Text('Manage Subscriptions'),
),
],
],
),
),
);
}
}
Important Notes
Platform Differences
- iOS: Full support for offer code redemption through system sheet (iOS 14+)
- Android: No direct promo code API - users must redeem through Play Store
- Subscription Management: Both platforms support opening native subscription management
Requirements
- iOS: Minimum iOS 14.0 for offer code redemption
- iOS: Minimum iOS 15.0 for subscription management
- Android: Requires Google Play Billing Library 5.x+
Best Practices
- Always check platform before calling platform-specific methods
- Handle errors gracefully as native dialogs may fail
- Listen to purchase streams when presenting offer code redemption
- Use subscription management for user convenience