localytics_flutter_sdk 1.0.2
localytics_flutter_sdk: ^1.0.2 copied to clipboard
Flutter plugin for the Localytics analytics, push, and engagement SDK on Android and iOS.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:localytics_flutter_sdk/localytics_flutter_sdk.dart';
void main() {
runApp(const ExampleApp());
}
/// Demonstrates a handful of the most common Localytics calls.
///
/// The native SDK still has to be initialized in the host app's
/// `Application` (Android) and `AppDelegate` (iOS) per the Localytics
/// docs — this sample app only exercises the Dart-side API.
class ExampleApp extends StatelessWidget {
/// Creates the example app shell.
const ExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Localytics Example',
theme: ThemeData(useMaterial3: true, colorSchemeSeed: Colors.indigo),
home: const _HomePage(),
);
}
}
class _HomePage extends StatefulWidget {
const _HomePage();
@override
State<_HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<_HomePage> {
String _lastResult = 'No call yet';
List<InboxCampaign> _inbox = const <InboxCampaign>[];
bool _darkModeEnabled = false;
bool _locationMonitoringEnabled = false;
bool _persistLocationMonitoring = false;
Future<void> _run(String label, Future<void> Function() action) async {
try {
await action();
if (!mounted) return;
setState(() => _lastResult = '$label OK');
} on Object catch (error) {
if (!mounted) return;
setState(() => _lastResult = '$label FAILED: $error');
}
}
Future<void> _refreshInbox() async {
try {
final List<InboxCampaign> campaigns =
await Localytics.refreshInboxCampaigns();
if (!mounted) return;
setState(() {
_inbox = campaigns;
_lastResult = 'Inbox refreshed (${campaigns.length})';
});
} on Object catch (error) {
if (!mounted) return;
setState(() => _lastResult = 'Inbox FAILED: $error');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Localytics Example')),
body: ListView(
padding: const EdgeInsets.all(16),
children: <Widget>[
Text('Last call: $_lastResult'),
const Divider(),
_Section(
title: 'Privacy',
children: <Widget>[
FilledButton(
onPressed: () => _run(
'setLoggingEnabled(true)',
() => Localytics.setLoggingEnabled(true),
),
child: const Text('Enable verbose logging'),
),
FilledButton.tonal(
onPressed: () => _run(
'setOptedOut(false)',
() => Localytics.setOptedOut(false),
),
child: const Text('Opt user IN'),
),
FilledButton.tonal(
onPressed: () => _run(
'setOptedOut(true)',
() => Localytics.setOptedOut(true),
),
child: const Text('Opt user OUT'),
),
],
),
_Section(
title: 'Customer',
children: <Widget>[
FilledButton(
onPressed: () => _run('setCustomerId', () async {
await Localytics.setCustomerId('demo-user-123');
await Localytics.setCustomerEmail('demo@example.com');
await Localytics.setCustomerFullName('Demo User');
}),
child: const Text('Identify demo user'),
),
],
),
_Section(
title: 'Events',
children: <Widget>[
FilledButton(
onPressed: () => _run(
'tagEvent',
() => Localytics.tagEvent(
'TestTheme'
),
),
child: const Text("tagEvent('TestTheme')"),
),
FilledButton(
onPressed: () => _run(
'tagScreen',
() => Localytics.tagScreen('Home'),
),
child: const Text("tagScreen('Home')"),
),
FilledButton(
onPressed: () => _run(
'tagPurchased',
() => Localytics.tagPurchased(
itemName: 'Shirt',
itemId: 'sku-123',
itemType: 'Apparel',
itemPriceCents: 1500,
attributes: <String, String>{'color': 'blue'},
),
),
child: const Text('tagPurchased Shirt \$15'),
),
],
),
_Section(
title: 'Profile',
children: <Widget>[
FilledButton(
onPressed: () => _run(
'setProfileAttribute(Age=45)',
() => Localytics.setProfileAttribute(
'Age',
45,
scope: ProfileScope.organization,
),
),
child: const Text('setProfileAttribute Age=45'),
),
FilledButton(
onPressed: () => _run(
'incrementProfileAttribute(Age, +1)',
() => Localytics.incrementProfileAttribute(
'Age',
scope: ProfileScope.organization,
),
),
child: const Text('Increment Age by 1'),
),
],
),
_Section(
title: 'Appearance',
children: <Widget>[
// Toggles `Localytics.enableDarkMode(...)` which overrides
// the SDK's automatic system-theme detection for in-app
// messages and the App Inbox UI. Available on Android
// (>= 7.1.0) and iOS (>= 7.1.1).
SwitchListTile(
title: const Text('Force dark mode for in-apps & inbox'),
subtitle: Text(
_darkModeEnabled
? 'Currently forced ON'
: 'Currently following system / light',
),
value: _darkModeEnabled,
onChanged: (bool value) async {
await _run(
'enableDarkMode($value)',
() => Localytics.enableDarkMode(value),
);
if (!mounted) return;
setState(() => _darkModeEnabled = value);
},
),
],
),
_Section(
title: 'Location',
children: <Widget>[
SwitchListTile(
title: const Text('Location monitoring enabled'),
subtitle: const Text(
'Request location permission in your app first, '
'then toggle. Does not show the system dialog.',
),
value: _locationMonitoringEnabled,
onChanged: (bool value) async {
await _run(
'setLocationMonitoringEnabled($value)',
() => Localytics.setLocationMonitoringEnabled(value),
);
if (!mounted) return;
setState(() => _locationMonitoringEnabled = value);
},
),
SwitchListTile(
title: const Text('Persist location monitoring'),
subtitle: const Text(
'Re-enable monitoring when permission becomes available.',
),
value: _persistLocationMonitoring,
onChanged: (bool value) async {
await _run(
'persistLocationMonitoring($value)',
() => Localytics.persistLocationMonitoring(value),
);
if (!mounted) return;
setState(() => _persistLocationMonitoring = value);
},
),
],
),
_Section(
title: 'Inbox',
children: <Widget>[
FilledButton(
onPressed: _refreshInbox,
child: const Text('Refresh inbox'),
),
for (final InboxCampaign campaign in _inbox)
ListTile(
title: Text(campaign.title ?? campaign.name),
subtitle: Text(campaign.summary ?? ''),
trailing: Text(campaign.read ? 'read' : 'unread'),
),
],
),
_Section(
title: 'Lifecycle',
children: <Widget>[
FilledButton(
onPressed: () => _run('upload', Localytics.upload),
child: const Text('Force upload'),
),
],
),
],
),
);
}
}
class _Section extends StatelessWidget {
const _Section({required this.title, required this.children});
final String title;
final List<Widget> children;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
const SizedBox(height: 16),
Text(title, style: Theme.of(context).textTheme.titleMedium),
const SizedBox(height: 8),
...children.map(
(Widget c) => Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: c,
),
),
],
);
}
}