infly 0.4.0
infly: ^0.4.0 copied to clipboard
Short links, App Links / Universal Links and deferred deep links for Flutter, backed by infl.ly. Router-agnostic, no device fingerprinting.
example/lib/main.dart
import 'dart:async';
import 'package:infly/infly.dart';
import 'package:flutter/material.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Infly.initialize(
appId:
const String.fromEnvironment('INFLY_APP_ID', defaultValue: 'app_demo'),
publicKey: const String.fromEnvironment('INFLY_PUBLIC_KEY',
defaultValue: 'pk_live_replace_me'),
scheme: 'demoapp',
useIosPasteboard: true,
);
runApp(const ExampleApp());
}
/// Minimal host app showing the three things the SDK does.
class ExampleApp extends StatefulWidget {
/// Creates the example app.
const ExampleApp({super.key});
@override
State<ExampleApp> createState() => _ExampleAppState();
}
class _ExampleAppState extends State<ExampleApp> {
final GlobalKey<NavigatorState> _navigator = GlobalKey<NavigatorState>();
final TextEditingController _code = TextEditingController();
StreamSubscription<InflyLink>? _subscription;
InflyLink? _link;
CreatedLink? _created;
String? _message;
@override
void initState() {
super.initState();
// The SDK hands back a destination string; routing stays the app's job.
_subscription = Infly.onLink.listen((InflyLink link) {
setState(() => _link = link);
_navigator.currentState?.pushNamed(link.destination);
});
}
@override
void dispose() {
_subscription?.cancel();
_code.dispose();
super.dispose();
}
Future<void> _create() async {
try {
final CreatedLink link = await Infly.createLink(
destination: '/board/1234',
metadata: const LinkMetadata(
title: 'Join my board',
description: 'Put a sticker on it with me!'),
);
setState(() {
_created = link;
_message = null;
});
} on InflyException catch (error) {
setState(() => _message = error.message);
}
}
Future<void> _redeem() async {
final InflyLink? link = await Infly.redeemClaimCode(_code.text);
setState(() => _message = link == null
? 'No link matches that code.'
: 'Opened: ${link.destination}');
}
Future<void> _showDialog(BuildContext context) async {
final InflyLink? link = await Infly.showClaimCodeDialog(context);
if (link != null) setState(() => _message = 'Opened: ${link.destination}');
}
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: _navigator,
title: 'infly Example',
onGenerateRoute: (RouteSettings settings) => MaterialPageRoute<void>(
builder: (_) => Scaffold(
appBar: AppBar(title: Text(settings.name ?? '/')),
body: Center(child: Text('route: ${settings.name}')),
),
),
home: Scaffold(
appBar: AppBar(title: const Text('infly')),
body: ListView(
padding: const EdgeInsets.all(16),
children: <Widget>[
Text('Last link: ${_link?.destination ?? 'none'}'),
if (_link != null) Text('Source: ${_link!.source.name}'),
const SizedBox(height: 16),
FilledButton(onPressed: _create, child: const Text('Create link')),
if (_created != null)
Padding(
padding: const EdgeInsets.only(top: 8),
child: SelectableText(_created!.url),
),
const Divider(height: 32),
const Text('Deferred link: type the code (iOS fallback)'),
TextField(
controller: _code,
decoration: const InputDecoration(
labelText: 'Invite code', hintText: 'K7F2-9MQX'),
),
const SizedBox(height: 8),
OutlinedButton(onPressed: _redeem, child: const Text('Redeem')),
Builder(
builder: (BuildContext context) => TextButton(
onPressed: () => _showDialog(context),
child: const Text('Or use the built-in dialog'),
),
),
if (_message != null)
Padding(
padding: const EdgeInsets.only(top: 12),
child: Text(_message!),
),
],
),
),
);
}
}