Skip to main content

gemicore_flutter 0.4.0 copy "gemicore_flutter: ^0.4.0" to clipboard
gemicore_flutter: ^0.4.0 copied to clipboard

Purchases for Flutter: App Store and Google Play subscriptions, offerings and paywalls, card, Apple Pay and Google Pay payments, and entitlements with one API key.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:gemicore_flutter/gemicore_flutter.dart';

import 'paywall_screen.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // The only setup: the publishable key from the Gemicore dashboard. A pk_test_ key uses the store
  // sandboxes, or the Gemicore test store when no store is available (a simulator, an emulator).
  // Apple Pay and Google Pay inside the app need the native setup in the README, then physical goods
  // sell with Gemicore.instance.payWithSheet.
  await Gemicore.configure(apiKey: const String.fromEnvironment('GEMICORE_KEY'));
  runApp(const ExampleApp());
}

class ExampleApp extends StatelessWidget {
  const ExampleApp({super.key});

  @override
  Widget build(BuildContext context) =>
      const MaterialApp(title: 'Gemicore example', home: StorePage());
}

class StorePage extends StatefulWidget {
  const StorePage({super.key});

  @override
  State<StorePage> createState() => _StorePageState();
}

class _StorePageState extends State<StorePage> {
  List<GemicoreProduct> _products = const [];
  CustomerInfo? _customer;
  String? _message;

  @override
  void initState() {
    super.initState();
    _customer = Gemicore.instance.cachedCustomerInfo;
    // Renewals, refunds and purchases from other devices arrive here without polling.
    Gemicore.instance.customerInfoStream.listen((info) => setState(() => _customer = info));
    _load();
  }

  Future<void> _load() async {
    try {
      final products = await Gemicore.instance.getProducts();
      setState(() => _products = products);
    } on GemicoreException catch (error) {
      setState(() => _message = error.message);
    }
  }

  Future<void> _buy(GemicoreProduct product) async {
    try {
      final result = await Gemicore.instance.purchase(product);
      setState(() {
        _message = switch (result.status) {
          PurchaseResultStatus.completed => 'Thanks for your purchase',
          PurchaseResultStatus.cancelled => null,
          PurchaseResultStatus.pending => 'Waiting for approval',
        };
      });
    } on GemicoreException catch (error) {
      setState(() => _message = error.message);
    }
  }

  Future<void> _payByCard(GemicoreProduct product) async {
    // Card, Apple Pay and Google Pay are for physical goods and services only.
    final result = await Gemicore.instance.payWithCard(product, email: 'buyer@example.com');
    setState(() => _message = result.isCompleted ? 'Paid' : 'Payment not finished');
  }

  // A placement is a named spot in the app. The dashboard decides which offering it shows each
  // customer (rules by country, app version or attributes, or an experiment); an unknown name shows
  // the current offering.
  Future<void> _showPlacementPaywall() async {
    final result = await presentPaywall(context, placement: 'onboarding');
    if (!mounted) return;
    setState(() => _message = 'Placement paywall: ${result.outcome.name}');
  }

  // Shown only when the dashboard switched the Customer Center on; it never cancels anything itself,
  // the store does.
  Future<void> _showCustomerCenter() async {
    try {
      final shown = await presentCustomerCenter(context);
      if (!mounted || shown) return;
      setState(() => _message = 'The Customer Center is not enabled in the dashboard');
    } on GemicoreException catch (error) {
      if (mounted) setState(() => _message = error.message);
    }
  }

  @override
  Widget build(BuildContext context) {
    final isPro = _customer?.hasEntitlement('pro') ?? false;
    return Scaffold(
      appBar: AppBar(
        title: Text(isPro ? 'Pro unlocked' : 'Free plan'),
        actions: [
          TextButton(
            onPressed: () =>
                Navigator.of(context)
                    .push(MaterialPageRoute<void>(builder: (_) => const PaywallScreen())),
            child: const Text('Paywall'),
          ),
          TextButton(
            onPressed: () async {
              final info = await Gemicore.instance.restorePurchases();
              setState(() => _customer = info);
            },
            child: const Text('Restore'),
          ),
        ],
      ),
      body: ListView(
        children: [
          if (_message != null) ListTile(title: Text(_message!)),
          ListTile(
            title: const Text('Paywall for the onboarding placement'),
            onTap: _showPlacementPaywall,
          ),
          ListTile(title: const Text('Customer Center'), onTap: _showCustomerCenter),
          for (final product in _products)
            ListTile(
              title: Text(product.title),
              subtitle: Text(product.priceString ?? product.description ?? ''),
              trailing: product.card != null
                  ? TextButton(onPressed: () => _payByCard(product), child: const Text('Pay'))
                  : TextButton(onPressed: () => _buy(product), child: const Text('Buy')),
            ),
        ],
      ),
    );
  }
}
0
likes
140
points
--
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Purchases for Flutter: App Store and Google Play subscriptions, offerings and paywalls, card, Apple Pay and Google Pay payments, and entitlements with one API key.

Homepage
Repository (GitHub)
View/report issues

Topics

#in-app-purchase #subscriptions #paywall #payments #monetization

License

Apache-2.0 (license)

Dependencies

flutter, flutter_secure_storage, flutter_stripe, http, in_app_purchase, in_app_purchase_android, in_app_purchase_storekit, intl, package_info_plus, url_launcher

More

Packages that depend on gemicore_flutter