π οΈ 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
OnePref.setString("key", "value here");
Read a value
final value = OnePref.getString("key");
π 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;
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(Constants.storeProductIds);
setState(() {
_isAvailable = isAvailable;
_products.addAll(response.productDetails);
_notFoundIds.addAll(response.notFoundIDs);
_purchasePending = false;
});
} else {
debugPrint("Store not available.");
}
}
Handle a Purchase
TextButton(
onPressed: () {
final selected = _products[selectedProduct ?? 0];
inAppEngine.handlePurchase(selected, Constants.storeProductIds);
},
child: Text(
"Buy $reward",
textAlign: TextAlign.center,
style: const TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.normal,
),
),
),
π§© Bonus: Restoring Purchases
ElevatedButton(
onPressed: () async {
await inAppEngine.restorePurchases();
},
child: const Text("Restore Purchases"),
),
| 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 |
π¦ Example Integration Flow
final engine = InAppEngine.instance;
await engine.initPurchaseStream(Constants.storeProductIds);
final available = await engine.getIsAvailable();
if (!available) return;
final products = await engine.queryProducts(Constants.storeProductIds);
if (products.productDetails.isNotEmpty) {
await engine.handlePurchase(products.productDetails.first, Constants.storeProductIds);
}