Drivers
On this page
Introduction#
A driver is the platform abstraction layer that delivers raw URI events to the DeeplinkManager. Drivers translate platform-specific deep link mechanisms — Universal Links on iOS and macOS, App Links on Android — into a uniform Stream<Uri> that the rest of the plugin consumes.
The plugin ships with AppLinksDriver, which covers all supported native platforms via the app_links package. If you need to source URIs from a custom mechanism (push notifications, in-app QR scanning, test harnesses), you can implement the DeeplinkDriver contract and register it in place of the default driver.
The DeeplinkDriver Contract#
All drivers extend the abstract class DeeplinkDriver, defined in lib/src/drivers/deeplink_driver.dart:
abstract class DeeplinkDriver {
String get name;
bool get isSupported;
Future<void> initialize(Map<String, dynamic> config);
Future<Uri?> getInitialLink();
Stream<Uri> get onLink;
void dispose();
}
name#
String get name;
A stable identifier for the driver. Used for logging and diagnostics. Return a lowercase, hyphenated string, for example 'app_links' or 'my-custom-driver'.
isSupported#
bool get isSupported;
Returns true when the driver can operate on the current platform. The DeeplinkServiceProvider skips driver initialization and stream setup when this returns false, so your check must be synchronous. Use Platform.isAndroid, Platform.isIOS, etc., guarded by a try/catch for environments where dart:io is unavailable, and check kIsWeb before any Platform access.
onLink#
Stream<Uri> get onLink;
A broadcast stream that emits every URI received while the application is running. The DeeplinkServiceProvider subscribes to this stream during the boot phase and forwards each emission to DeeplinkManager.handleUri(). Return Stream.empty() on unsupported platforms.
initialize#
Future<void> initialize(Map<String, dynamic> config);
Called once by the service provider before any link is consumed. Use this to create platform clients, open channels, or apply configuration values sourced from the deeplink config map. Keep this method idempotent — the provider does not guard against duplicate calls.
getInitialLink#
Future<Uri?> getInitialLink();
Returns the URI that cold-started the application, or null if the app was launched normally. This is called once after initialize() completes. Swallow exceptions internally and return null on failure — callers do not expect this method to throw.
dispose#
void dispose();
Releases any resources held by the driver (stream subscriptions, platform channels, timers). Called by the service provider during application teardown. If your driver holds no resources, the body can be left empty.
AppLinksDriver#
AppLinksDriver is the default driver. It delegates to the app_links package, which handles Universal Links (iOS / macOS) and App Links (Android) without any native Dart code in this plugin.
import 'package:magic_deeplink/magic_deeplink.dart';
// AppLinksDriver is registered automatically by DeeplinkServiceProvider.
// You only need to interact with it directly when writing custom boot logic.
final driver = AppLinksDriver();
await driver.initialize({});
final initial = await driver.getInitialLink(); // Uri? from cold start
driver.onLink.listen((uri) {
// Handle foreground links
});
Platform Support#
| Platform | Supported |
|---|---|
| Android | Yes — App Links (HTTPS intent filter) |
| iOS | Yes — Universal Links (apple-app-site-association) |
| macOS | Yes — Universal Links |
| Web | No |
| Windows | No |
| Linux | No |
AppLinksDriver.isSupported returns false for web (kIsWeb) and for any platform not in the set {Android, iOS, macOS}. The service provider will not attempt initialization or stream subscription when isSupported is false.
Custom Drivers#
Implementing the Contract#
Extend DeeplinkDriver and implement every member of the contract. The example below shows a driver that emits URIs received from a push notification payload:
import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:magic_deeplink/magic_deeplink.dart';
class PushNotificationDriver extends DeeplinkDriver {
final StreamController<Uri> _controller =
StreamController<Uri>.broadcast();
@override
String get name => 'push-notification';
@override
bool get isSupported {
if (kIsWeb) return false;
try {
return Platform.isAndroid || Platform.isIOS;
} catch (_) {
return false;
}
}
@override
Future<void> initialize(Map<String, dynamic> config) async {
// Subscribe to your notification service here and pipe URIs
// into _controller whenever a deep link payload arrives.
}
@override
Future<Uri?> getInitialLink() async {
// Return a URI if the app was cold-started from a notification,
// or null if no link was attached to the launch payload.
return null;
}
@override
Stream<Uri> get onLink => _controller.stream;
/// Call this from your notification handler to emit a URI.
void emit(Uri uri) => _controller.add(uri);
@override
void dispose() {
_controller.close();
}
}
Registering a Custom Driver#
Pass your driver to DeeplinkManager.setDriver() before the service provider's boot() phase completes. The canonical place is inside a custom service provider's boot() method, or directly in your AppServiceProvider:
import 'package:magic/magic.dart';
import 'package:magic_deeplink/magic_deeplink.dart';
class AppServiceProvider extends ServiceProvider {
@override
void register() {}
@override
Future<void> boot() async {
final manager = app.make<DeeplinkManager>('deeplinks');
manager.setDriver(PushNotificationDriver());
}
}
You can also set the driver imperatively at any point before the first link is consumed:
DeeplinkManager().setDriver(PushNotificationDriver());
Related#
- Handlers — Chain-of-responsibility URI handling after the driver emits a link
- Configuration —
config/deeplink.dartdriver selection and options - Service Provider — Boot lifecycle, driver initialization, and stream wiring