nami_flutter 0.1.0 copy "nami_flutter: ^0.1.0" to clipboard
nami_flutter: ^0.1.0 copied to clipboard

PlatformAndroidiOS
outdated

Subscription and in-app purchase (IAP) marketing platform for Flutter. Integrate with a few lines of code. Analytics, CRM, and create customized purchase experiences in the cloud. Generous free usage tier.

example/lib/main.dart

import 'dart:async';
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:nami_flutter/analytics/nami_analytics_support.dart';
import 'package:nami_flutter/billing/nami_purchase_manager.dart';
import 'package:nami_flutter/customer/nami_customer_manager.dart';
import 'package:nami_flutter/entitlement/nami_entitlement_manager.dart';
import 'package:nami_flutter/ml/nami_ml_manager.dart';
import 'package:nami_flutter/nami.dart';
import 'package:nami_flutter/nami_configuration.dart';
import 'package:nami_flutter/nami_log_level.dart';
import 'package:nami_flutter/paywall/nami_paywall_manager.dart';
import 'package:nami_flutter/paywall/nami_sku.dart';

import 'about.dart';

void main() {
  runApp(MaterialApp(home: MyApp()));
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
  static const _testExternalIdentifier = "9a9999a9-99aa-99a9-aa99-999a999999a8";
  static const _androidAppPlatformId = "b1a6572f-b0fc-45cd-8561-110c039c7744";
  static const _iosAppPlatformId = "db5e6672-ae5b-4a0e-b545-2b60d5fa9066";

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        theme: ThemeData(
          buttonTheme: ButtonThemeData(
            buttonColor: Color.fromARGB(255, 65, 109, 124),
          ),
          primaryColor: Color.fromARGB(255, 65, 109, 124),
          accentColor: Color.fromARGB(255, 65, 109, 124),
        ),
        home: Scaffold(
            appBar: AppBar(
              centerTitle: true,
              title: SizedBox(
                  height: 24,
                  child: Image.asset("assets/images/nami_logo_white.png")),
            ),
            body: _buildMainPageBody()));
  }

  @override
  void initState() {
    super.initState();
    print('--------- initState ---------');
    WidgetsBinding.instance?.addObserver(this);
    initPlatformState();
    NamiPaywallManager.signInEvents().listen((namiPaywall) {
      Nami.clearExternalIdentifier();
      Nami.setExternalIdentifier(
          _testExternalIdentifier, NamiExternalIdentifierType.uuid);
      print('--------- Sign In Clicked ---------');
    });
    _printCustomerJourneyState();
    _handleActiveEntitlementsFuture(
        NamiEntitlementManager.activeEntitlements());
    NamiEntitlementManager.entitlementChangeEvents()
        .listen((activeEntitlements) {
      print("EntitlementChangeListener triggered");
      _handleActiveEntitlements(activeEntitlements);
    });
    NamiPurchaseManager.purchaseChangeEvents()
        .listen((purchaseChangeEventData) {
      print("PurchasesChangedHandler triggered");
      _evaluateLastPurchaseEvent(purchaseChangeEventData);
    });
    NamiAnalyticsSupport.analyticsEvents().listen((analyticsData) {
      _printAnalyticsEventData(analyticsData);
    });
  }

  @override
  void dispose() {
    WidgetsBinding.instance?.removeObserver(this);
    super.dispose();
  }

  @override
  Future<void> didChangeAppLifecycleState(AppLifecycleState state) async {
    if (state == AppLifecycleState.resumed) {
      print('--------- ON RESUME ---------');
      _printCustomerJourneyState();
      _handleActiveEntitlementsFuture(
          NamiEntitlementManager.activeEntitlements());
    }
  }

  void _evaluateLastPurchaseEvent(
      PurchaseChangeEventData purchaseChangeEventData) {
    print('--------- Start ---------');
    print("Purchase State ${purchaseChangeEventData.purchaseState}");
    if (purchaseChangeEventData.purchaseState == NamiPurchaseState.purchased) {
      print("\nActive Purchases: ");
      purchaseChangeEventData.activePurchases.forEach((element) {
        print("\tSkuId: ${element.skuId}");
      });
    } else {
      print("Reason : ${purchaseChangeEventData.error}");
    }
    print('--------- End ---------');
  }

  void _handleActiveEntitlements(List<NamiEntitlement> activeEntitlements) {
    print('--------- Start ---------');
    if (activeEntitlements.isNotEmpty) {
      print("Active entitlements found!");
      activeEntitlements.forEach((element) {
        print(element.toString());
      });
    } else {
      print("No active entitlements");
    }
    print('--------- End ---------');
  }

  void _handleActiveEntitlementsFuture(
      Future<List<NamiEntitlement>> activeEntitlementsFuture) async {
    _handleActiveEntitlements(await activeEntitlementsFuture);
  }

  void _printCustomerJourneyState() async {
    var state = await NamiCustomerManager.currentCustomerJourneyState();
    print('--------- Start ---------');
    print("currentCustomerJourneyState");
    print("formerSubscriber ==> ${state?.formerSubscriber}");
    print("inGracePeriod ==> ${state?.inGracePeriod}");
    print("inIntroOfferPeriod ==> ${state?.inIntroOfferPeriod}");
    print("inTrialPeriod ==> ${state?.inTrialPeriod}");
    print('--------- End ---------');
  }

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initPlatformState() async {
    var namiConfiguration = NamiConfiguration(
        appPlatformIDApple: _iosAppPlatformId,
        appPlatformIDGoogle: _androidAppPlatformId,
        namiLogLevel: NamiLogLevel.debug);
    Nami.configure(namiConfiguration);
    // If the widget was removed from the tree while the asynchronous platform
    // message was in flight, we want to discard the reply rather than calling
    // setState to update our non-existent appearance.
    if (!mounted) return;
  }

  SingleChildScrollView _buildMainPageBody() {
    return SingleChildScrollView(
        child: Padding(
            padding: EdgeInsets.all(16.0),
            child: Column(
                mainAxisSize: MainAxisSize.max,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  Text(
                    "Basic Flutter",
                    style: TextStyle(fontSize: 24, fontStyle: FontStyle.italic),
                  ),
                  Container(
                      margin: const EdgeInsets.only(top: 8),
                      child: ElevatedButton(
                          onPressed: () async {
                            await Navigator.push(
                              context,
                              MaterialPageRoute(
                                  builder: (context) => AboutPage()),
                            );
                          },
                          child: Text("About"))),
                  buildHeaderBodyContainer("Introduction",
                      "This application demonstrates common calls used in a Nami enabled application."),
                  buildHeaderBodyContainer("Instructions",
                      "If you suspend and resume this app three times in the simulator, an example paywall will be raised - or you can use the [Subscribe] button below to raise the same paywall."),
                  buildHeaderBodyContainer("Important info",
                      "Any Purchase will be remembered while the application is [Active, Suspended, Resume] but cleared when the application is launched.\nExamine the application source code for more details on calls used to respond and monitor purchases."),
                  Container(
                    margin: const EdgeInsets.only(top: 48),
                    child: ElevatedButton(
                      onPressed: () async {
                        NamiMLManager.coreAction("subscribe");
                        print('Subscribe clicked!');
                        var preparePaywallResult =
                            await NamiPaywallManager.preparePaywallForDisplay();
                        if (preparePaywallResult.success) {
                          NamiPaywallManager.raisePaywall();
                        } else {
                          print('preparePaywallForDisplay Error -> '
                              '${preparePaywallResult.error}');
                        }
                      },
                      child: Text('Subscribe'),
                    ),
                  )
                ])));
  }

  void _printAnalyticsEventData(NamiAnalyticsData analyticsData) {
    print('--------- Start ---------');
    print('analyticsEvents');
    print("TYPE " + analyticsData.type.toString());
    print("CAMPAIGN_ID " +
        analyticsData.eventData[NamiAnalyticsKeys.CAMPAIGN_ID]);
    print("CAMPAIGN_NAME " +
        analyticsData.eventData[NamiAnalyticsKeys.CAMPAIGN_NAME]);
    dynamic campaignType =
        analyticsData.eventData[NamiAnalyticsKeys.CAMPAIGN_TYPE];
    print("CAMPAIGN_TYPE ${campaignType?.toString()}");
    bool namiTriggered =
        analyticsData.eventData[NamiAnalyticsKeys.NAMI_TRIGGERED];
    print("NAMI_TRIGGERED " + namiTriggered.toString());
    print(
        "PAYWALL_ID " + analyticsData.eventData[NamiAnalyticsKeys.PAYWALL_ID]);
    print("PAYWALL_NAME " +
        analyticsData.eventData[NamiAnalyticsKeys.PAYWALL_NAME]);
    List<NamiSKU> products =
        analyticsData.eventData[NamiAnalyticsKeys.PAYWALL_PRODUCTS];
    print("PAYWALL_PRODUCTS " + products.toString());
    print("PAYWALL_TYPE " +
        analyticsData.eventData[NamiAnalyticsKeys.PAYWALL_TYPE]);
    dynamic purchaseActivityType =
        analyticsData.eventData[NamiAnalyticsKeys.PURCHASE_ACTIVITY_TYPE];
    print("PURCHASE_ACTIVITY_TYPE ${purchaseActivityType.toString()}");
    dynamic purchasedProduct =
        analyticsData.eventData[NamiAnalyticsKeys.PURCHASE_PRODUCT];
    print("PURCHASE_PRODUCT ${purchasedProduct.toString()}");
    dynamic purchaseTimestamp =
        analyticsData.eventData[NamiAnalyticsKeys.PURCHASE_TIMESTAMP];
    print("PURCHASE_TIMESTAMP ${purchaseTimestamp.toString()}");
    print('--------- End ---------');
  }
}

Container buildHeaderBodyContainer(String header, String body) {
  return Container(
      margin: const EdgeInsets.only(top: 16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          Container(
              margin: const EdgeInsets.only(top: 8),
              child: Text(
                header,
                style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
              )),
          Text(
            body,
            style: TextStyle(
              fontSize: 16,
            ),
          ),
        ],
      ));
}
5
likes
130
points
8
downloads

Publisher

verified publishernamiml.com

Weekly Downloads

Subscription and in-app purchase (IAP) marketing platform for Flutter. Integrate with a few lines of code. Analytics, CRM, and create customized purchase experiences in the cloud. Generous free usage tier.

Homepage
Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on nami_flutter

Packages that implement nami_flutter