clippr 0.0.4 copy "clippr: ^0.0.4" to clipboard
clippr: ^0.0.4 copied to clipboard

Deep linking and mobile attribution SDK for Flutter. Seamless replacement for Firebase Dynamic Links.

example/lib/main.dart

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)),
        ],
      ),
    );
  }
}
0
likes
150
points
37
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Deep linking and mobile attribution SDK for Flutter. Seamless replacement for Firebase Dynamic Links.

Homepage
Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter

More

Packages that depend on clippr

Packages that implement clippr