nohmo 0.4.1
nohmo: ^0.4.1 copied to clipboard
Official Nohmo analytics SDK for Flutter — device tracking, session journeys, install attribution, deep linking, crash reporting and event batching for iOS and Android.
example/lib/main.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:nohmo/nohmo.dart';
// Supplied at build time so this example can be pointed at a real project, or
// at a local ingestion server, without editing the source:
//
// flutter run --dart-define=NOHMO_PROJECT_ID=proj_xxxx \
// --dart-define=NOHMO_API_KEY=pk_xxxx
//
// On an Android emulator the host machine is reachable at 10.0.2.2, so a local
// backend is --dart-define=NOHMO_HOST=http://10.0.2.2:8000
const String kProjectId =
String.fromEnvironment('NOHMO_PROJECT_ID', defaultValue: 'proj_xxxx');
const String kApiKey =
String.fromEnvironment('NOHMO_API_KEY', defaultValue: 'pk_xxxx');
const String kHost =
String.fromEnvironment('NOHMO_HOST', defaultValue: 'https://www.nohmo.in');
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Nohmo.init(
projectId: kProjectId,
apiKey: kApiKey,
host: kHost,
debug: true,
);
runApp(const ExampleApp());
}
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Nohmo example',
theme: ThemeData(colorSchemeSeed: Colors.indigo, useMaterial3: true),
// Every route change becomes SCREEN_VIEW + TIME_SPENT.
navigatorObservers: <NavigatorObserver>[Nohmo.observer],
// Every tap becomes PRESS / LONG_PRESS / RAGE_CLICK.
builder: (BuildContext context, Widget? child) =>
NohmoAutocapture(child: child ?? const SizedBox.shrink()),
initialRoute: '/',
routes: <String, WidgetBuilder>{
'/': (_) => const HomeScreen(),
'/checkout': (_) => const CheckoutScreen(),
},
);
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
StreamSubscription<NohmoDeepLink>? _deepLinkSub;
String _status = '';
@override
void initState() {
super.initState();
// Fires for both a Smart Link that opened an installed app and one restored
// after install (deferred deep linking).
_deepLinkSub = Nohmo.deepLinks.listen((NohmoDeepLink link) {
if (!mounted) return;
setState(() => _status = 'Deep link: ${link.value} (${link.source.name})');
});
}
@override
void dispose() {
_deepLinkSub?.cancel();
super.dispose();
}
Future<void> _login() async {
await Nohmo.linkUser('user_42',
email: 'ada@example.com', meta: <String, dynamic>{'plan': 'pro'});
if (mounted) setState(() => _status = 'Linked user_42');
}
Future<void> _invite() async {
final String link = await Nohmo.buildInviteLink(channel: 'whatsapp');
if (mounted) setState(() => _status = link);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Nohmo example')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
ElevatedButton(
onPressed: () => Nohmo.send('custom_event',
<String, dynamic>{'source': 'home', 'value': 42}),
child: const Text('Send custom event'),
),
const SizedBox(height: 12),
ElevatedButton(onPressed: _login, child: const Text('Log in')),
const SizedBox(height: 12),
ElevatedButton(
onPressed: _invite,
child: const Text('Build invite link'),
),
const SizedBox(height: 12),
// An explicit name overrides what autocapture would infer.
NohmoTracked(
name: 'go_to_checkout',
child: FilledButton(
onPressed: () => Navigator.of(context).pushNamed('/checkout'),
child: const Text('Checkout'),
),
),
const SizedBox(height: 24),
Text(_status, style: Theme.of(context).textTheme.bodySmall),
],
),
),
);
}
}
class CheckoutScreen extends StatelessWidget {
const CheckoutScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Checkout')),
body: Center(
child: ElevatedButton(
onPressed: () {
Nohmo.trackConversion('purchase',
<String, dynamic>{'amount': 29.99, 'currency': 'USD'});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Conversion recorded')),
);
},
child: const Text('Pay 29.99'),
),
),
);
}
}