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
160
points
111
downloads

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

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on clippr

Packages that implement clippr