API reference
Every public class, method, getter, stream, enum and field in lander_flutter 0.2.0.
Everything below is exported by one import:
import 'package:lander_flutter/lander_flutter.dart';| Export | Kind |
|---|---|
Lander | Static entry point |
LanderLink | A link delivered to the app |
LanderShortLink | A link created with createLink |
LanderConfidence | Enum: how sure Lander is |
LanderException | Error from calls that need the API |
landerSdkVersion | The SDK version string |
Lander
abstract final class LanderAll members are static. You never create an instance.
Lander.initialize
static Future<void> initialize({
required String apiKey,
String baseUrl = 'https://api.golander.link',
bool enableLogging = false,
})Starts the SDK. Call it once, as early as possible (before runApp is fine). Loads or creates the install ID, reads the launch link and starts listening for links, then reports the launch with POST /v1/sdk/init in the background. The returned future does not wait for the network.
Prop
Type
- Throws
ArgumentErrorwhenapiKeystarts withsk_, or does not start withpk_. - Never throws for network errors.
- A second call is ignored and returns the future of the first call.
- Calls
WidgetsFlutterBinding.ensureInitialized().
Lander.onDeepLink
static Stream<LanderLink> get onDeepLinkA broadcast stream of every link the app receives: Universal Links, App Links, custom scheme URLs and deferred links.
- Safe to listen to at any time, even before
initialize. - Links that arrive while nobody listens are buffered and replayed, in order, to the next listener.
- Includes the launch link unless
getInitialLinkclaimed it first. - Unknown links and links that could not be resolved are delivered with
isResolved == falseand onlyuriset. - Does not include links returned by
claimHandoff.
Lander.getInitialLink
static Future<LanderLink?> getInitialLink()The link that launched the app, or null. On a first launch this may be a deferred link, so it waits for the launch report in that case. Delivered once: returns null if onDeepLink already delivered it, and after this call onDeepLink will not deliver it.
Throws StateError before initialize.
Lander.createLink
static Future<LanderShortLink> createLink({
String path = '/',
Map<String, Object> params = const {},
String? title,
String? campaign,
String? channel,
List<String> tags = const [],
Uri? iosFallbackUrl,
Uri? androidFallbackUrl,
Uri? webFallbackUrl,
String? ogTitle,
String? ogDescription,
Uri? ogImageUrl,
DateTime? expiresAt,
})Creates a short link with POST /v1/sdk/links. The slug is random and the domain is the project's default domain.
Prop
Type
- Throws
ArgumentErrorwhenpathdoes not start with/or aparamsvalue is notString,numorbool. - Throws
LanderExceptionwhen the request fails after retries. - Throws
StateErrorbeforeinitialize.
See Creating links.
Lander.claimHandoff
static Future<LanderLink?> claimHandoff(String userId)Claims the link your backend bound to this user with POST /v1/handoffs, after sign in. Returns the link (isDeferred true, confidence deterministic, method authenticated_handoff) or null when nothing is pending. The newest pending handoff wins and every pending one for the user is cleared.
- The link is only returned, never also emitted on
onDeepLink. - Throws
ArgumentErrorwhenuserId, trimmed, is empty or longer than 256 characters. - Throws
LanderExceptionwhen the request fails after retries, or with codeinstall_not_registeredwhen the install could not be registered yet. - Throws
StateErrorbeforeinitialize.
See Deferred links.
Lander.trackEvent
static Future<void> trackEvent(
String name, {
Map<String, Object?> properties = const {},
String? linkId,
})Records a custom event in the on device queue, which sends it in batches with retries. Completes once the event is queued.
Prop
Type
- Throws
ArgumentErrorfor an invalidname, alinkIdthat is not a UUID, or properties that cannot be encoded as JSON. - Never throws for network errors.
- Throws
StateErrorbeforeinitialize.
See Events.
Lander.installId
static String? get installIdThe random UUID v4 of this install, once initialize has completed; null before. Stored outside backups and removed on uninstall.
Test only members
Lander.debugHttpClient, Lander.debugClient and Lander.debugReset() are annotated @visibleForTesting and exist for the SDK's own tests. Do not use them in app code.
LanderLink
@immutable
class LanderLinkA deep link delivered to the app. When Lander knows the link, the fields mirror the ResolvedLink returned by the API. When it does not (unknown link, custom scheme URL, network unavailable) only uri is set and isResolved is false.
Constructors
const LanderLink({
required Uri uri,
String? linkId,
String? url,
String? path,
Map<String, Object> params = const {},
String? campaign,
String? channel,
bool isDeferred = false,
LanderConfidence confidence = LanderConfidence.unattributed,
String? method,
})
/// A link Lander could not resolve. Only uri is set.
const LanderLink.unresolved(Uri uri)
/// Builds a link from a ResolvedLink JSON object. uri falls back to the link's own url.
factory LanderLink.fromJson(Map<String, Object?> json, {Uri? uri})The public constructors make it easy to build links in your own tests. See Testing.
Fields
Prop
Type
Getters
Prop
Type
route examples:
uri | path | route |
|---|---|---|
https://acme.golander.link/p-123 | /product/123 | /product/123 |
https://acme.golander.link/unknown | null | /unknown |
acmeshop://product/123?color=red | null | /product/123?color=red |
acmeshop:// | null | / |
Equality and toString
Two LanderLinks are equal when every field is equal (params compared by content). toString() gives a readable summary, for example LanderLink(<id>, path: /product/123, params: {productId: 123}, uri: https://acme.golander.link/p-123, deterministic via universal_link) or LanderLink(unresolved, uri: acmeshop://product/123).
LanderShortLink
@immutable
class LanderShortLinkA short link created with Lander.createLink.
const LanderShortLink({
required String id,
required Uri url,
required String domain,
required String slug,
required String path,
Map<String, Object> params = const {},
String? title,
String? campaign,
String? channel,
List<String> tags = const [],
DateTime? expiresAt,
DateTime? createdAt,
})
factory LanderShortLink.fromJson(Map<String, Object?> json)Prop
Type
Two LanderShortLinks are equal when id and url are equal. toString() returns url.toString().
LanderConfidence
enum LanderConfidence { deterministic, probabilistic, unattributed }| Value | Meaning |
|---|---|
deterministic | Matched by an exact identifier: a Universal Link or App Link open, an Android install referrer token, the iOS Continue in app page or an authenticated handoff. |
probabilistic | Matched by coarse signals (OS version, country, click time, optionally a network hash) within a short window. Only iOS deferred links of projects that opted in. |
unattributed | No link could be tied to this open. |
static LanderConfidence parse(Object? value)Returns the value whose name equals value, or unattributed for anything else.
LanderException
class LanderException implements Exception {
const LanderException({
required String code,
required String message,
int? statusCode,
Duration? retryAfter,
});
}Thrown by calls that need an answer from the API: createLink and claimHandoff. initialize and trackEvent never throw on network or server errors.
Prop
Type
toString() returns LanderException(code, statusCode): message.
API error codes you may see from the SDK endpoints: validation_error, invalid_domain, destination_blocked (400), invalid_api_key (401), wrong_key_kind, project_suspended (403), install_not_found (404), rate_limited, link_quota_exceeded (429), internal_error (500).
landerSdkVersion
const String landerSdkVersion = '0.2.0';The version reported to the API as sdkVersion and in the X-Lander-Sdk header.
Network behavior
The SDK only talks to Lander's public API, never to a database.
| Endpoint | Called by | Attempts |
|---|---|---|
POST /v1/sdk/init | initialize, every launch | 3 on a first launch, 1 otherwise |
POST /v1/sdk/resolve | Every http or https link that opens the app | 2 |
POST /v1/sdk/events | The event queue | 1 per flush; the queue retries with backoff |
POST /v1/sdk/links | createLink | 3 |
POST /v1/sdk/handoffs/claim | claimHandoff | 3 |
- Every request sends
Authorization: Bearer <publishable key>,Content-Type: application/jsonandX-Lander-Sdk: flutter/0.2.0. - Every attempt has a 10 second timeout.
- Retries happen only for network errors, timeouts, 408, 429 and 5xx, with exponential backoff from 500 ms up to 4 s (or longer if
Retry-Afterasks). - Every write carries an
Idempotency-Keythat stays the same across retries, so a retry never creates a second link, claim or install.