encore_flutter 1.0.34 copy "encore_flutter: ^1.0.34" to clipboard
encore_flutter: ^1.0.34 copied to clipboard

Flutter plugin wrapping the native Encore iOS and Android SDKs for monetization, offers, and entitlements. All offer UI is rendered natively via StoreKit (iOS) and Play Billing (Android).

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:encore_flutter/encore_flutter.dart';
import 'package:purchases_flutter/purchases_flutter.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const ExampleApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Encore Flutter Example',
      theme: ThemeData(
        colorSchemeSeed: Colors.deepPurple,
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final List<String> _eventLog = [];
  String? _activeLanguage;

  @override
  void initState() {
    super.initState();
    _initEncore();
  }

  void _log(String message) {
    final now = DateTime.now();
    final timestamp = '${now.hour.toString().padLeft(2, '0')}:${now.minute.toString().padLeft(2, '0')}:${now.second.toString().padLeft(2, '0')}';
    setState(() => _eventLog.insert(0, '[$timestamp] $message'));
  }

  Future<void> _initEncore() async {
    await Purchases.configure(
      PurchasesConfiguration('YOUR_REVENUECAT_API_KEY'),
    );

    await Encore.shared.configure(
      apiKey: 'pk_test_dyzxq1bl6jdt9dly78qdjnad',
      logLevel: EncoreLogLevel.debug,
    );


    Encore.shared.onPurchaseRequest((purchaseRequest) async {
      _log('onPurchaseRequest: productId=${purchaseRequest.productId}, placementId=${purchaseRequest.placementId}');
      final products = await Purchases.getProducts([purchaseRequest.productId]);
      if (products.isNotEmpty) {
        await Purchases.purchaseStoreProduct(products.first);
      }
    });

    Encore.shared.onPurchaseComplete((result, productId) {
      _log('onPurchaseComplete: $productId (token: ${result.purchaseToken})');
    });

    Encore.shared.onPassthrough((placementId) {
      _log('onPassthrough: $placementId');
    });

    await Encore.shared.identify(
      userId: 'demo_user_flutter_001',
      attributes: const EncoreUserAttributes(
        email: 'user@example.com',
        subscriptionTier: 'premium',
      ),
    );

    _log('identify: demo_user_flutter_001');
  }

  Future<void> _showOffer() async {
    _log('placement: presenting...');
    final result = await Encore.shared.placement('example_placement').show();

    final message = switch (result) {
      EncorePresentationResultGranted() => 'placement: granted',
      EncorePresentationResultNotGranted(:final reason) => 'placement: not granted ($reason)',
    };

    _log(message);
  }

  Future<void> _resetSdk() async {
    await Encore.shared.reset();
    setState(() => _activeLanguage = null);
    _log('reset: SUCCESS (language cleared, falls back to device locale)');
  }

  /// Override the locale that the SDK reports to the backend on the next
  /// `/config` and `/offers/search` calls. Beats the device's
  /// `Accept-Language` header in the resolver, so this is how to test
  /// localization without changing iOS Settings → Language.
  ///
  /// Pass `null` to clear and revert to device locale.
  Future<void> _setLanguage(String? code) async {
    await Encore.shared.setUserAttributes(
      EncoreUserAttributes(language: code),
    );
    setState(() => _activeLanguage = code);
    _log(code == null
        ? 'setUserAttributes: language cleared (device locale)'
        : 'setUserAttributes: language=$code → next placement should render in this locale');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Encore Flutter Example')),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(16),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                Row(
                  children: [
                    Expanded(
                      child: FilledButton(
                        onPressed: _showOffer,
                        child: const Text('Show Offer'),
                      ),
                    ),
                    const SizedBox(width: 12),
                    Expanded(
                      child: OutlinedButton(
                        onPressed: _resetSdk,
                        child: const Text('Reset SDK'),
                      ),
                    ),
                  ],
                ),
                const SizedBox(height: 12),
                _LanguagePicker(
                  active: _activeLanguage,
                  onPick: _setLanguage,
                ),
              ],
            ),
          ),
          const Divider(height: 1),
          Expanded(
            child: _eventLog.isEmpty
                ? const Center(child: Text('No events yet'))
                : ListView.builder(
                    padding: const EdgeInsets.all(12),
                    itemCount: _eventLog.length,
                    itemBuilder: (context, index) => Padding(
                      padding: const EdgeInsets.symmetric(vertical: 2),
                      child: Text(
                        _eventLog[index],
                        style: Theme.of(context).textTheme.bodySmall?.copyWith(
                              fontFamily: 'monospace',
                            ),
                      ),
                    ),
                  ),
          ),
        ],
      ),
    );
  }
}

/// Quick locale-override picker for end-to-end testing of /config + /offers
/// localization. Tap a language → SDK sends `?language=<code>` on the next
/// fetch and the placement renders in that locale (assuming the publisher
/// has approved translations on the backend).
///
/// Codes match the six Knowunity is rolling out plus English source.
class _LanguagePicker extends StatelessWidget {
  const _LanguagePicker({required this.active, required this.onPick});

  final String? active;
  final Future<void> Function(String?) onPick;

  static const _options = <(String code, String label)>[
    ('en', '🇺🇸 EN'),
    ('de', '🇩🇪 DE'),
    ('fr', '🇫🇷 FR'),
    ('es', '🇪🇸 ES'),
    ('it', '🇮🇹 IT'),
    ('pl', '🇵🇱 PL'),
    ('pt', '🇧🇷 PT'),
  ];

  @override
  Widget build(BuildContext context) {
    return Wrap(
      spacing: 6,
      runSpacing: 6,
      crossAxisAlignment: WrapCrossAlignment.center,
      children: [
        const Text('Language:', style: TextStyle(fontWeight: FontWeight.w500)),
        for (final (code, label) in _options)
          ChoiceChip(
            label: Text(label),
            selected: active == code,
            onSelected: (_) => onPick(code),
          ),
        TextButton(
          onPressed: active == null ? null : () => onPick(null),
          child: const Text('Auto'),
        ),
      ],
    );
  }
}
1
likes
130
points
4.01k
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Flutter plugin wrapping the native Encore iOS and Android SDKs for monetization, offers, and entitlements. All offer UI is rendered natively via StoreKit (iOS) and Play Billing (Android).

Homepage
Repository (GitHub)
View/report issues

Topics

#monetization #in-app-purchase #subscriptions #offers

License

unknown (license)

Dependencies

flutter

More

Packages that depend on encore_flutter

Packages that implement encore_flutter