onepref 0.0.25
onepref: ^0.0.25 copied to clipboard
This package is a well-structured wrapper around Flutter's in_app_purchase API that centralizes in-app purchase (IAP) logic for both Android (Google Play) and iOS (App Store).
๐ ๏ธ OnePref + InAppEngine #
This package is endorsed, which means you can simply use shared_preferences and in_app_purchase normally.
This package will be automatically included in your app when you do โ no need to add it manually to your pubspec.yaml.
โจ Features #
OnePref provides the same functionality as shared_preferences, but in a simpler, developer-friendly API.
Additionally, it includes an InAppEngine utility that helps you integrate in-app purchases quickly and safely โ saving you hours of setup time.
Key Highlights #
- ๐ Simplified preference storage using OnePref.
- ๐ฐ Streamlined in-app purchase management for Android & iOS.
- ๐งพ Support for both consumable and non-consumable products.
- ๐ Built-in subscription upgrade/downgrade support (Android).
- ๐งฉ Easy product query and restore logic.
- ๐ง Debug-friendly logs and structured
PurchaseResult.
๐ Getting Started #
1๏ธโฃ Install #
flutter pub add onepref
import 'package:onepref/onepref.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await OnePref.init();
runApp(const MyApp());
}
Write a value #
await OnePref.setString("key", "value here");
await OnePref.setBool("darkMode", true);
await OnePref.setInt("launchCount", 5);
Read a value #
final value = OnePref.getString("key");
final isDark = OnePref.getBool("darkMode");
final count = OnePref.getInt("launchCount");
Premium & Remove Ads helpers #
// Write
await OnePref.setPremium(true);
await OnePref.setRemoveAds(true);
// Read
final isPremium = OnePref.getPremium();
final noAds = OnePref.getRemoveAds();
Other Utilities #
// Check whether a key exists
final exists = OnePref.containsKey("key");
// String list support
await OnePref.setStringList("items", ["a", "b", "c"]);
final items = OnePref.getStringList("items");
// Remove a single key or everything
await OnePref.removeKey("key");
await OnePref.removeAllSavedPrefs();
๐ Usage (In-App Purchases) #
โ ๏ธ ATTENTION!
Before using InAppEngine, make sure you have correctly configured in-app purchases
in the Play Console (Android) or App Store Connect (iOS).
Setup variables #
late final List<String> _notFoundIds = <String>[];
late final List<ProductDetails> _products = <ProductDetails>[];
late final List<PurchaseDetails> _purchases = <PurchaseDetails>[];
late bool _isAvailable = false;
late bool _purchasePending = false;
final InAppEngine inAppEngine = InAppEngine.instance;
Define your products #
const storeProductIds = [
InAppEngineProductId(id: "premium_monthly", isConsumable: false, isSubscription: true),
InAppEngineProductId(id: "remove_ads", isConsumable: false, isOneTimePurchase: true),
InAppEngineProductId(id: "coins_100", isConsumable: true, reward: 100),
];
Initialize and Query Products #
@override
void initState() {
super.initState();
// Listen to purchase updates
inAppEngine.inAppPurchase.purchaseStream.listen(
(List<PurchaseDetails> purchaseDetailsList) {
listenToPurchaseUpdated(purchaseDetailsList);
},
onDone: () {},
onError: (Object error) {
debugPrint("Purchase Stream Error: $error");
},
);
getProducts(); // Fetch product details
}
Future<void> getProducts() async {
final isAvailable = await inAppEngine.getIsAvailable();
if (isAvailable) {
final response = await inAppEngine.queryProducts(storeProductIds);
setState(() {
_isAvailable = isAvailable;
_products.addAll(response.productDetails);
_notFoundIds.addAll(response.notFoundIDs);
_purchasePending = false;
});
} else {
debugPrint("Store not available.");
}
}
Handle a Purchase #
TextButton(
onPressed: () async {
final selected = _products[selectedProduct ?? 0];
final initiated = await inAppEngine.handlePurchase(selected, storeProductIds);
if (!initiated) {
debugPrint("Could not initiate purchase.");
}
},
child: Text(
"Buy $reward",
textAlign: TextAlign.center,
style: const TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.normal,
),
),
),
Handle Purchase Results #
Future<void> listenToPurchaseUpdated(
List<PurchaseDetails> purchaseDetailsList) async {
final results = await inAppEngine.purchaseListener(
purchaseDetailsList: purchaseDetailsList,
productsIds: storeProductIds,
);
for (final result in results) {
if (result.purchaseComplete == true) {
debugPrint("Purchase completed: ${result.productId}");
await OnePref.setPremium(true);
} else if (result.purchaseRestore == true) {
debugPrint("Purchase restored: ${result.productId}");
await OnePref.setPremium(true);
} else if (result.purchaseConsumed == true) {
debugPrint("Consumable consumed: ${result.productId}");
} else if (result.message != null) {
debugPrint("Purchase message: ${result.message}");
}
}
}
๐งฉ Restoring Purchases #
ElevatedButton(
onPressed: () async {
await inAppEngine.restorePurchases();
// Results arrive via the purchaseStream listener above
},
child: const Text("Restore Purchases"),
),
๐ Subscription Upgrade / Downgrade (Android only) #
final success = await inAppEngine.upgradeOrDowngradeSubscription(
currentSubPurchaseDetails, // existing GooglePlayPurchaseDetails
newSubProductDetails, // new ProductDetails
);
| Feature | Description |
|---|---|
| ๐น Shared Preferences | Simple key/value storage with OnePref |
| ๐น Product Query | Fetch Play/App Store products easily |
| ๐น Purchase Handling | Buy consumables & non-consumables |
| ๐น Subscription | Manage upgrades/downgrades on Android |
| ๐น Restore | Restore past purchases with one line |
| ๐น Debug Logging | Built-in safe logging for dev mode |