clippr 0.0.4
clippr: ^0.0.4 copied to clipboard
Deep linking and mobile attribution SDK for Flutter. Seamless replacement for Firebase Dynamic Links.
import 'package:flutter/material.dart';
import 'package:clippr/clippr.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Clippr.initialize(apiKey: 'clippr_live_your_api_key_here', debug: true);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Clippr Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: 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> {
String _status = 'Initializing...';
ClipprLink? _currentLink;
int _eventsSent = 0;
@override
void initState() {
super.initState();
_initDeepLinks();
}
Future<void> _initDeepLinks() async {
setState(() => _status = 'Checking for deep link...');
final initialLink = await Clippr.getInitialLink();
if (initialLink case final initialLink?) {
_handleDeepLink(initialLink, 'getInitialLink');
} else {
setState(() => _status = 'No deep link found');
}
Clippr.onLink = (link) => _handleDeepLink(link, 'onLink');
}
void _handleDeepLink(ClipprLink link, String source) {
debugPrint('Deep link received via $source:');
debugPrint(' Path: ${link.path}');
debugPrint(' Match Type: ${link.matchType}');
debugPrint(' Confidence: ${link.confidence}');
debugPrint(' Campaign: ${link.attribution?.campaign}');
setState(() {
_status = 'Link received via $source';
_currentLink = link;
});
}
Future<void> _trackTestEvent() async {
try {
await Clippr.track('test_event', params: {
'button': 'test_button',
'timestamp': DateTime.now().millisecondsSinceEpoch,
});
setState(() {
_eventsSent++;
_status = 'Event tracked successfully!';
});
} catch (e) {
setState(() => _status = 'Error: $e');
}
}
Future<void> _trackPurchase() async {
try {
await Clippr.trackRevenue(
'purchase',
revenue: 9.99,
currency: 'USD',
params: {'product_id': 'demo_product'},
);
setState(() {
_eventsSent++;
_status = 'Purchase tracked!';
});
} catch (e) {
setState(() => _status = 'Error: $e');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Clippr Demo'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Status Card
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Status',
style:
TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
const SizedBox(height: 8),
Text(_status, style: TextStyle(color: Colors.grey[600])),
const SizedBox(height: 4),
Text(
'Events sent: $_eventsSent',
style: TextStyle(color: Colors.grey[600], fontSize: 12),
),
],
),
),
),
const SizedBox(height: 16),
// Deep Link Card
if (_currentLink != null)
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Deep Link',
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 16),
),
const SizedBox(height: 12),
_InfoRow('Path', _currentLink!.path),
_InfoRow('Match Type', _currentLink!.matchType.name),
_InfoRow(
'Confidence',
_currentLink!.confidence != null
? '${(_currentLink!.confidence! * 100).toStringAsFixed(1)}%'
: 'N/A',
),
const Divider(height: 24),
const Text(
'Attribution',
style: TextStyle(
fontWeight: FontWeight.w500, fontSize: 14),
),
const SizedBox(height: 8),
_InfoRow('Campaign',
_currentLink!.attribution?.campaign ?? 'none'),
_InfoRow('Source',
_currentLink!.attribution?.source ?? 'none'),
_InfoRow('Medium',
_currentLink!.attribution?.medium ?? 'none'),
if (_currentLink!.metadata != null) ...[
const Divider(height: 24),
_InfoRow('Metadata', _currentLink!.metadata.toString()),
],
],
),
),
),
const SizedBox(height: 16),
// Action Buttons
FilledButton.icon(
onPressed: _trackTestEvent,
icon: const Icon(Icons.send),
label: const Text('Track Test Event'),
),
const SizedBox(height: 8),
OutlinedButton.icon(
onPressed: _trackPurchase,
icon: const Icon(Icons.shopping_cart),
label: const Text('Track Purchase (\$9.99)'),
),
],
),
),
);
}
}
class _InfoRow extends StatelessWidget {
final String label;
final String value;
const _InfoRow(this.label, this.value);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label, style: TextStyle(color: Colors.grey[600])),
Text(value, style: const TextStyle(fontWeight: FontWeight.w500)),
],
),
);
}
}