ferry_link_flutter 0.1.0
ferry_link_flutter: ^0.1.0 copied to clipboard
Flutter SDK for Ferry deep linking, deferred deep links, and link-level attribution on iOS and Android.
import 'package:ferry_link_flutter/ferry_link_flutter.dart';
import 'package:ferry_platform_interface/ferry_platform_interface.dart';
import 'package:flutter/material.dart';
import 'demo_ferry_platform.dart';
/// Minimal example app for the ferry Flutter plugin. Demonstrates the
/// three steps from the README's 5-minute integration guide:
///
/// 1. Ferry.configure, called once at app start (see below).
/// 2. A direct universal/app link open, via the "Simulate direct open"
/// button, which calls Ferry.handle with a sample link URL. This is a
/// real call into the native SDK's local URL parsing; no network call
/// is made for a link that already carries its data in the query
/// string.
/// 3. A simulated deferred first-install match, via the "Simulate
/// deferred match" button. See demo_ferry_platform.dart: this exists
/// to make the onLink shape visible in a running app without a real
/// install and without calling the real Ferry API. The real deferred
/// match flow (first-launch detection, signal gathering order,
/// single-shot POST /v1/match) is ferry-android's and ferry-ios's own
/// responsibility, covered by their test suites, not reimplemented
/// here.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// Swap in the demo decorator before anything else runs, so every call
// this app makes to Ferry.* (through the real FerryPlatform.instance
// singleton) still reaches the real native side for configure/handle/
// track, with only onLink augmented. See demo_ferry_platform.dart.
final demoPlatform = DemoFerryPlatform(FerryPlatform.instance);
FerryPlatform.instance = demoPlatform;
// Step 1: configure. Call once, as early as possible. This reads
// nothing and sends nothing; pk_test_xxx is a placeholder public key
// for this example and for tests, never a real project's key.
await Ferry.configure(
publicKey: 'pk_test_xxx',
options: const FerryOptions(debugLogging: true),
);
runApp(FerryExampleApp(demoPlatform: demoPlatform));
}
class FerryExampleApp extends StatelessWidget {
const FerryExampleApp({super.key, required this.demoPlatform});
final DemoFerryPlatform demoPlatform;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Ferry example',
home: FerryHomePage(demoPlatform: demoPlatform),
);
}
}
class FerryHomePage extends StatefulWidget {
const FerryHomePage({super.key, required this.demoPlatform});
final DemoFerryPlatform demoPlatform;
@override
State<FerryHomePage> createState() => _FerryHomePageState();
}
class _FerryHomePageState extends State<FerryHomePage> {
FerryLink? _lastLink;
@override
void initState() {
super.initState();
// Step 2/3: one router for both a direct open and a deferred match.
// Discriminate on link.isDeferred, never on link.method.
Ferry.onLink.listen((link) {
setState(() => _lastLink = link);
});
}
/// The one Ferry call that reports its failure to the caller, because
/// a share sheet with no link in it is worse than an error.
Future<void> _createLink() async {
String message;
try {
final created = await Ferry.createLink(
domain: 'go.acme.com',
data: const {'screen': 'profile', 'user': 'u_42'},
);
message = 'Created ${created.url}';
} on FerryException catch (e) {
message = 'createLink failed: ${e.error}';
}
if (!mounted) return;
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(message)));
}
@override
Widget build(BuildContext context) {
final link = _lastLink;
return Scaffold(
appBar: AppBar(title: const Text('Ferry example')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ElevatedButton(
onPressed: () => Ferry.handle(
'https://go.acme.com/welcome?ref=footer&campaign=fall_sale',
),
child: const Text('Simulate direct open'),
),
const SizedBox(height: 8),
ElevatedButton(
onPressed: widget.demoPlatform.simulateDeferredMatch,
child: const Text('Simulate deferred match (demo)'),
),
const SizedBox(height: 8),
ElevatedButton(
onPressed: () => Ferry.track(FerryEvents.signup),
child: const Text('Track a signup event'),
),
const SizedBox(height: 8),
ElevatedButton(
onPressed: _createLink,
child: const Text('Create a link'),
),
const SizedBox(height: 24),
Text(
link == null
? 'No link received yet.'
: 'Last link:\n'
'data: ${link.data}\n'
'url: ${link.url}\n'
'method: ${link.method.rawValue}\n'
'isDeterministic: ${link.confidence.isDeterministic}\n'
'score: ${link.confidence.score}\n'
'isDeferred: ${link.isDeferred}\n'
'clickId: ${link.clickId}',
),
],
),
),
);
}
}