traput_dynamic_linking 0.0.1 copy "traput_dynamic_linking: ^0.0.1" to clipboard
traput_dynamic_linking: ^0.0.1 copied to clipboard

Traput Dynamic Linking SDK for Flutter. Handles Universal Links (iOS), App Links (Android), and deferred deep links via a single API (Traput.onLink()). Logic-only, no UI.

traput_dynamic_linking #

Official Flutter SDK for Traput (Traput - ترابط) — dynamic links for mobile apps.

  • Traput — Product, documentation, pricing (Firebase Dynamic Links replacement).
  • Dashboard — Create projects, get API key, manage links.

Get your API key and subdomain from the Dashboard.

What it does #

  • Initializes the SDK with an API key, base URL, and subdomain (one Traput project per app).
  • Handles Universal Links (iOS) and App Links (Android) - opens app directly without redirects
  • Captures deferred deep links via traput_token query parameter
  • Provides unified API: Traput.onLink() - handles all link types (Universal, App, deferred)
  • Captures links from:
    • Android: App Links (intent data), deferred tokens (intent extras/query params)
    • iOS: Universal Links (NSUserActivity), deferred tokens (launch URL/query params)
  • Resolves deferred tokens via backend endpoint: POST {baseUrl}/deferred/resolve

Primary API: Traput.onLink() - recommended for all new projects
Legacy API: resolveDeferredLink() - deprecated, use onLink() instead

This package contains no UI.

Install #

Add to your app (from pub.dev):

dependencies:
  traput_dynamic_linking: ^0.0.1

``

Quick start (Dart) #

Initialize and register link handler:

import 'package:traput_dynamic_linking/traput_dynamic_linking.dart';

void main() {
  Traput.initialize(
    apiKey: '<YOUR_API_KEY>',
    baseUrl: 'https://api.traput.com',
    subdomain: 'your-project', // From Dashboard; must match your Traput project
  );

  // Register callback to handle all link types (Universal Links, App Links, deferred)
  Traput.onLink((link) {
    // Handle Universal Link, App Link, or deferred link
    print('Received link: ${link.uri}');
    
    if (link.uri.pathSegments.contains('product')) {
      // Navigate to product page
    }
    
    // For deferred links, access resolved data
    if (link.isDeferred) {
      print('Deferred token: ${link.deferredToken}');
      print('Resolved data: ${link.data}');
    }
  });

  runApp(MyApp());
}

The callback is automatically invoked:

  • Cold start: When app is launched from a Universal/App Link
  • Warm start: When app is already running and a link is opened
  • Deferred: When a deferred token is resolved
// Initialize once on app startup
Traput.initialize(
  apiKey: '<YOUR_API_KEY>',
  baseUrl: 'https://api.traput.com',
  subdomain: 'your-project',
);

// Then resolve (usually on first screen / first app session)
final resolved = await Traput.instance.resolveDeferredLink();
if (resolved != null) {
  // Navigate using resolved.deepLink
  // Optional metadata from backend: resolved.data
}

Note: resolveDeferredLink() only handles deferred links. Use Traput.onLink() for Universal Links, App Links, and deferred links.

API reference #

Traput.initialize({ apiKey, baseUrl, subdomain, httpClient, timeout, enableDebugLogging }) #

  • apiKey (required): The raw Traput API key to send in the X-API-Key header.
  • baseUrl (required): Traput backend API root, including scheme + host (and optional port), e.g.:
    • https://api.traput.com
    • http://localhost:3000
  • subdomain (required): Your Traput project's subdomain (must match the project that owns the API key). The SDK sends this on every API request so the backend can enforce one project per app.
  • httpClient (optional): Custom HTTP client for testing or custom network configuration.
  • timeout (optional): Timeout for network requests. Defaults to 10 seconds.
  • enableDebugLogging (optional): Whether to enable debug logging. Defaults to false. When enabled, logs are emitted (but never secrets like API keys or tokens).

The SDK calls POST {baseUrl}/deferred/resolve and GET {baseUrl}/links/data with the subdomain on every request.

Throws:

  • TraputInvalidApiKeyException if API key is empty
  • TraputInvalidBaseUrlException if base URL is invalid
  • TraputMissingConfigurationException if subdomain is empty
  • TraputInitializationException if timeout is invalid

Primary API - Handles Universal Links, App Links, and deferred deep links.

Registers a callback that is invoked when the app is opened via a link.

Parameters:

  • callback: Function that receives a TraputLink object

When callback is invoked:

  • Cold start: App is launched from a Universal/App Link
  • Warm start: App is already running and a link is opened
  • Deferred: A deferred token is resolved (if present in link)

TraputLink properties:

  • uri: Uri - The URI that opened the app (Universal Link or App Link URL)
  • deferredToken: String? - Optional deferred token if this link was resolved from a deferred session
  • data: Map<String, Object?> - Additional data extracted from the link (for deferred links, contains resolved data)
  • isDeferred: bool - Whether this link contains a deferred token

Example:

Traput.onLink((link) {
  // Extract path segments
  final segments = link.uri.pathSegments;
  if (segments.length >= 2 && segments[0] == 'r') {
    final slug = segments[1]; // e.g., 'abc' from /r/abc
    // Navigate based on slug
  }
  
  // Extract query parameters
  final productId = link.uri.queryParameters['productId'];
  
  // Handle deferred links
  if (link.isDeferred) {
    final resolvedData = link.data;
    // Use resolved data for navigation
  }
});

Note: Only one callback can be registered at a time. Registering a new callback replaces the previous one.

Deprecated: Use Traput.onLink() instead for handling all link types.

  • Returns null when there is no captured token.
  • Uses consume-once semantics: the captured token is cleared on the native side when consumed.
  • Returns ResolvedDeferredLink on success:
    • deepLink: Uri
    • data: Map<String, Object?>
  • Throws TraputApiException on failures, including:
    • non-200 responses from the backend
    • network/client failures (e.g. timeouts, connectivity)
    • invalid/unsupported response bodies (missing/invalid deepLink)

Migration: See Universal Links Documentation for migration guide.

Debug logging

When enableDebugLogging: true is set in Traput.initialize(), the SDK emits debug logs (prefixed with [Traput]) for:

  • Link processing
  • Deferred link resolution
  • Network requests (sanitized)
  • Errors (sanitized, no secrets)

Important: Logs never include secrets (API keys, tokens, or other sensitive data).

Breaking change: required subdomain #

As of this version, subdomain is required in Traput.initialize(). One Flutter app corresponds to one Traput project, identified by its subdomain.

  • If you are upgrading: Add subdomain: 'your-project' to every Traput.initialize() call. The value must match your Traput project’s subdomain (the one that owns your API key). The backend rejects requests when the API key’s project does not match the subdomain (403 Forbidden).
  • If you are new: Always pass subdomain when initializing; see Quick start above.

Backend contract (what the SDK sends) #

Endpoint: POST /deferred/resolve

  • Headers:
    • X-API-Key: <apiKey>
    • Content-Type: application/json
  • Body:
    • deferredSessionId: the captured traput_token value
    • platform: "ios" or "android"
    • bundleId: your app bundle id/package name

Platform integration notes #

Android #

The Android plugin captures links via getInitialLink() method:

  • App Links: Captures full URL from intent.data (when android:autoVerify="true" is set)
  • Deferred tokens: Captures traput_token from:
    • intent.extras["traput_token"]
    • fallback: intent.data?.getQueryParameter("traput_token")

It also listens to onNewIntent for warm start scenarios (consume-once semantics).

App Links Setup:

  • Add intent filter in AndroidManifest.xml with android:autoVerify="true"
  • Configure data elements with scheme https, host <subdomain>.traput.link, pathPrefix /r
  • See Universal Links Documentation for complete setup

Manual test (App Link):

adb shell am start -a android.intent.action.VIEW -d "https://myapp.traput.link/r/test"

Manual test (deferred link with query param):

adb shell am start -a android.intent.action.VIEW -d "myapp://open?traput_token=abc123"

Important:

  • For App Links, ensure assetlinks.json is accessible and verified
  • Play Store install itself does not automatically deliver arbitrary query params to your app
  • To use deferred linking, your app must receive/produce the token on first launch and pass it via the launch Intent extras (e.g. via your attribution flow)

iOS #

The iOS plugin captures links via getInitialLink() method:

  • Universal Links: Captures full URL from NSUserActivity (including cold start)
  • Deferred tokens: Captures traput_token from:
    • launch URL (didFinishLaunchingWithOptions)
    • open URL (application(_:open:options:))
    • universal links query parameters

Universal Links Setup:

  • Enable Associated Domains capability in Xcode
  • Add domain: applinks:<subdomain>.traput.link
  • See Universal Links Documentation for complete setup

Important:

  • For Universal Links, your app must be configured with Associated Domains and receive the URL
  • Ensure AASA file is accessible at https://<subdomain>.traput.link/.well-known/apple-app-site-association
  • All links must use subdomain format: https://<subdomain>.traput.link/r/*

Development #

Run SDK unit tests:

cd sdk/flutter
flutter test

Run analyzer:

cd sdk/flutter
flutter analyze

How to test against the local backend #

If you run the backend at http://localhost:3000, initialize with:

  • baseUrl: "http://localhost:3000"

Then use Traput.onLink() to handle links, or ensure your app receives a traput_token on first launch and call resolveDeferredLink() (deprecated).

Troubleshooting #

Common Issues #

Links not opening the app:

  • iOS: Verify Associated Domains are configured in Xcode
  • Android: Verify android:autoVerify="true" is set in AndroidManifest.xml
  • Check that AASA/assetlinks.json files are accessible

Deferred links not resolving:

  • Check API key is correct
  • Verify backend is accessible
  • Enable debug logging to see what's happening

Initialization errors:

  • Ensure API key is not empty
  • Ensure base URL includes scheme and host
  • Ensure subdomain is not empty and matches your Traput project’s subdomain
  • Check error messages for specific issues

Error Handling #

The SDK throws typed exceptions that you can catch:

try {
  Traput.initialize(
    apiKey: 'your-api-key',
    baseUrl: 'https://api.traput.com',
    subdomain: 'your-project', // From Dashboard
  );
} on TraputInvalidApiKeyException {
  // Handle invalid API key
} on TraputInvalidBaseUrlException {
  // Handle invalid base URL
} on TraputMissingConfigurationException {
  // Handle missing/empty subdomain
} on TraputException catch (e) {
  // Handle other Traput errors
  print('Error: ${e.message}');
}

Common Mistakes #

  1. Forgetting to call initialize(): Always call Traput.initialize() before using the SDK.

  2. Omitting subdomain: subdomain is required and must match your Traput project’s subdomain; the backend returns 403 if the API key’s project does not match.

  3. Registering callback too late: Register Traput.onLink() as early as possible, ideally right after initialization.

  4. Not handling errors: Wrap SDK calls in try-catch to handle errors gracefully.

  5. Incorrect AndroidManifest.xml: Ensure android:autoVerify="true" is set for App Links.

  6. Missing Associated Domains: iOS requires Associated Domains capability to be enabled.

  7. Testing in simulator: Universal Links don't work in iOS Simulator - test on real devices.

For more detailed troubleshooting, see the Troubleshooting Guide.

Additional Documentation #

For setup when using the published package from pub.dev, see Traput documentation.

0
likes
150
points
21
downloads

Publisher

unverified uploader

Weekly Downloads

Traput Dynamic Linking SDK for Flutter. Handles Universal Links (iOS), App Links (Android), and deferred deep links via a single API (Traput.onLink()). Logic-only, no UI.

Homepage
Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter, http

More

Packages that depend on traput_dynamic_linking

Packages that implement traput_dynamic_linking