dynalinks 1.0.0 copy "dynalinks: ^1.0.0" to clipboard
dynalinks: ^1.0.0 copied to clipboard

Dynalinks SDK for Flutter - Deferred deep linking and attribution for iOS and Android apps.

example/lib/main.dart

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:dynalinks/dynalinks.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Configure SDK before runApp
  try {
    await Dynalinks.configure(
      clientAPIKey: const String.fromEnvironment(
        'DYNALINKS_API_KEY',
        defaultValue: 'your-api-key-here',
      ),
      logLevel: DynalinksLogLevel.debug,
      allowSimulatorOrEmulator: true, // Allow testing on simulator
    );
  } on DynalinksException catch (e) {
    debugPrint('Failed to configure Dynalinks: $e');
  }

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Dynalinks Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const DeepLinkPage(),
    );
  }
}

class DeepLinkPage extends StatefulWidget {
  const DeepLinkPage({super.key});

  @override
  State<DeepLinkPage> createState() => _DeepLinkPageState();
}

class _DeepLinkPageState extends State<DeepLinkPage> {
  DeepLinkResult? _result;
  String? _error;
  bool _isLoading = false;
  StreamSubscription<DeepLinkResult>? _linkSubscription;

  @override
  void initState() {
    super.initState();
    _checkInitialLink();
    _listenForDeepLinks();
  }

  @override
  void dispose() {
    _linkSubscription?.cancel();
    super.dispose();
  }

  Future<void> _checkInitialLink() async {
    // Check for cold start link
    try {
      final initialLink = await Dynalinks.getInitialLink();
      if (initialLink != null) {
        _handleDeepLinkResult(initialLink);
        return;
      }
    } on DynalinksException catch (e) {
      debugPrint('Error getting initial link: $e');
    }

    // Check for deferred deep link
    _checkForDeferredDeepLink();
  }

  void _listenForDeepLinks() {
    _linkSubscription = Dynalinks.onDeepLinkReceived.listen(
      _handleDeepLinkResult,
      onError: (error) {
        debugPrint('Deep link stream error: $error');
      },
    );
  }

  Future<void> _checkForDeferredDeepLink() async {
    setState(() {
      _isLoading = true;
      _error = null;
    });

    try {
      final result = await Dynalinks.checkForDeferredDeepLink();
      _handleDeepLinkResult(result);
    } on SimulatorException {
      setState(() {
        _error = 'Deferred deep linking not available on simulator/emulator';
        _isLoading = false;
      });
    } on DynalinksException catch (e) {
      setState(() {
        _error = e.message;
        _isLoading = false;
      });
    }
  }

  void _handleDeepLinkResult(DeepLinkResult result) {
    setState(() {
      _result = result;
      _isLoading = false;
      _error = null;
    });

    if (result.matched && result.link?.deepLinkValue != null) {
      _showDeepLinkDialog(result);
    }
  }

  void _showDeepLinkDialog(DeepLinkResult result) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Deep Link Received'),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Navigate to: ${result.link?.deepLinkValue}'),
            if (result.confidence != null)
              Text('Confidence: ${result.confidence!.name}'),
            if (result.matchScore != null)
              Text('Score: ${result.matchScore}'),
          ],
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('OK'),
          ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('Dynalinks Example'),
      ),
      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: [
                    Text(
                      'SDK Status',
                      style: Theme.of(context).textTheme.titleMedium,
                    ),
                    const SizedBox(height: 8),
                    Text('Version: ${Dynalinks.version}'),
                  ],
                ),
              ),
            ),

            const SizedBox(height: 16),

            // Result/Error Card
            if (_isLoading)
              const Card(
                child: Padding(
                  padding: EdgeInsets.all(32),
                  child: Center(child: CircularProgressIndicator()),
                ),
              )
            else if (_error != null)
              Card(
                color: Theme.of(context).colorScheme.errorContainer,
                child: Padding(
                  padding: const EdgeInsets.all(16),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        'Error',
                        style: Theme.of(context).textTheme.titleMedium?.copyWith(
                              color:
                                  Theme.of(context).colorScheme.onErrorContainer,
                            ),
                      ),
                      const SizedBox(height: 8),
                      Text(
                        _error!,
                        style: TextStyle(
                          color:
                              Theme.of(context).colorScheme.onErrorContainer,
                        ),
                      ),
                    ],
                  ),
                ),
              )
            else if (_result != null)
              _buildResultCard()
            else
              const Card(
                child: Padding(
                  padding: EdgeInsets.all(16),
                  child: Text('No deep link result yet'),
                ),
              ),

            const SizedBox(height: 24),

            // Actions
            FilledButton.icon(
              onPressed: _checkForDeferredDeepLink,
              icon: const Icon(Icons.refresh),
              label: const Text('Check for Deferred Deep Link'),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildResultCard() {
    final result = _result!;
    final link = result.link;

    return Card(
      color: result.matched
          ? Theme.of(context).colorScheme.primaryContainer
          : null,
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              result.matched ? 'Match Found!' : 'No Match',
              style: Theme.of(context).textTheme.titleMedium?.copyWith(
                    color: result.matched
                        ? Theme.of(context).colorScheme.onPrimaryContainer
                        : null,
                  ),
            ),
            const Divider(),
            _buildInfoRow('Matched', result.matched.toString()),
            if (result.confidence != null)
              _buildInfoRow('Confidence', result.confidence!.name),
            if (result.matchScore != null)
              _buildInfoRow('Score', result.matchScore.toString()),
            _buildInfoRow('Deferred', result.isDeferred.toString()),
            if (link != null) ...[
              const Divider(),
              Text(
                'Link Data',
                style: Theme.of(context).textTheme.titleSmall,
              ),
              const SizedBox(height: 8),
              _buildInfoRow('ID', link.id),
              if (link.name != null) _buildInfoRow('Name', link.name!),
              if (link.path != null) _buildInfoRow('Path', link.path!),
              if (link.deepLinkValue != null)
                _buildInfoRow('Deep Link Value', link.deepLinkValue!),
              if (link.fullUrl != null)
                _buildInfoRow('Full URL', link.fullUrl.toString()),
            ],
          ],
        ),
      ),
    );
  }

  Widget _buildInfoRow(String label, String value) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          SizedBox(
            width: 120,
            child: Text(
              '$label:',
              style: const TextStyle(fontWeight: FontWeight.w500),
            ),
          ),
          Expanded(
            child: Text(value),
          ),
        ],
      ),
    );
  }
}
1
likes
160
points
111
downloads

Publisher

unverified uploader

Weekly Downloads

Dynalinks SDK for Flutter - Deferred deep linking and attribution for iOS and Android apps.

Homepage
Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on dynalinks

Packages that implement dynalinks