journiq_flutter_sdk 0.2.1 copy "journiq_flutter_sdk: ^0.2.1" to clipboard
journiq_flutter_sdk: ^0.2.1 copied to clipboard

Journiq deep linking, attribution, and analytics SDK for Flutter. Wraps native Android and iOS SDKs via platform channels.

Journiq Flutter SDK #

Official Flutter plugin for Journiq — deep linking, deferred deep links, event tracking, attribution analytics, in-app notifications, and push.

Wraps the native Android SDK and iOS SDK via platform channels.

Features #

  • Deferred Deep Links — Attribute installs to the link that drove them, even across the app store
  • Link Management — Create, list, and retrieve short links programmatically
  • Event Tracking — Track conversions and custom events with offline queue and automatic batching
  • Analytics — Retrieve link click stats and app configuration
  • In-App Notifications — Receive and display real-time in-app notifications with custom UI
  • Push Registration — Register FCM device tokens for push notifications
  • Cross-platform — Single Dart API backed by native SDKs on both Android and iOS

Requirements #

Platform Minimum Version
Android API 24 (Android 7.0)
iOS 13.0
Flutter 3.3.0+
Dart 3.11.0+

Installation #

Add to your pubspec.yaml:

dependencies:
  journiq_flutter_sdk: ^0.2.1

Then run:

flutter pub get

Quick Start #

1. Initialize the SDK #

import 'package:journiq_flutter_sdk/journiq_flutter_sdk.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Journiq.configure(apiKey: 'jq_pub_your_key_here');
  runApp(MyApp());
}
final match = await Journiq.deepLinks.checkDeferredDeepLink();
if (match.matched) {
  // Attribution is stored automatically — events will be linked to this deep link
  Navigator.pushNamed(context, match.deepLinkPath ?? '/');
}
// When the app opens via a URL scheme (e.g., myapp://product/123?jq_link=...)
void handleDeepLink(Uri uri) {
  // Extract and store attribution, returns a clean URI for routing
  final cleanUri = Journiq.deepLinks.handleIncomingLink(uri);
  navigateTo(cleanUri.path);
}

4. Track Events #

// deepLinkId is automatically attached from the last attribution source
await Journiq.events.track(
  'PURCHASE',
  metadata: {'amount': '29.99', 'currency': 'USD'},
);

// Or pass explicitly if needed
await Journiq.events.track(
  'PURCHASE',
  deepLinkId: 'specific_link_id',
  metadata: {'amount': '29.99', 'currency': 'USD'},
);
final link = await Journiq.links.create(LinkCreateRequest(
  webUrl: 'https://example.com/product/123',
  title: 'Cool Product',
  deepLinkPath: '/product/123',
  utmSource: 'app',
  utmMedium: 'share',
));
// Share link.shortUrl

5. User Identity #

// After login
await Journiq.setIdentity('user_12345');

// On logout
await Journiq.logout();

6. Push Notifications #

Register the device's FCM token so the backend can send push and in-app notifications:

import 'package:firebase_messaging/firebase_messaging.dart';

final token = await FirebaseMessaging.instance.getToken();
if (token != null) {
  await Journiq.push.registerToken(token);
}

// Re-register on token refresh
FirebaseMessaging.instance.onTokenRefresh.listen((newToken) {
  Journiq.push.registerToken(newToken);
});

Handle incoming FCM data messages:

FirebaseMessaging.onMessage.listen((RemoteMessage message) {
  // Let the SDK handle Journiq messages (returns true if handled)
  final handled = Journiq.push.handleDataMessage(message.data);
  if (!handled) {
    // Handle your own messages
  }
});

7. In-App Notifications #

Listen for new notifications (stream-based)

Journiq.notifications.onNewNotification.listen((notification) {
  print('New: ${notification.title}');
});

Register a handler to control exactly how notifications appear in your app:

Journiq.notifications.setDisplayHandler(context, (ctx, notification) {
  // Return a widget to display, or null to suppress
  return MaterialBanner(
    content: Text(notification.title),
    actions: [
      TextButton(
        onPressed: () {
          Journiq.notifications.markAsRead(notification.id);
          JourniqNotifications.reportAction(notification, NotificationAction.tapped);
        },
        child: Text('VIEW'),
      ),
      TextButton(
        onPressed: () {
          JourniqNotifications.reportAction(notification, NotificationAction.dismissed);
        },
        child: Text('DISMISS'),
      ),
    ],
  );
});

Fetch notifications

final result = await Journiq.notifications.getAll(page: 1, limit: 20);
for (final n in result.notifications) {
  print('${n.title} - read: ${n.read}');
}

Mark as read & unread count

await Journiq.notifications.markAsRead(notificationId);
final count = await Journiq.notifications.getUnreadCount();

// Or listen to count changes
Journiq.notifications.onUnreadCountChanged.listen((count) {
  updateBadge(count);
});

API Reference #

Journiq #

Method Description
configure({apiKey, baseUrl?}) Initialize the SDK. Call once at app startup.
isInitialized Whether the SDK has been configured.
setIdentity(userId) Set user identity for cross-device attribution.
logout() Remove user identity and clear attribution.
onAppForegrounded() Trigger event queue flush (call from lifecycle handler).
attributedDeepLinkId The currently stored deep link ID (read-only).
attributedClickId The currently stored click ID (read-only).
Method Description
checkDeferredDeepLink() Check for a deferred deep link match on first open. Auto-stores attribution. Returns MatchResult.
handleIncomingLink(Uri) Extract attribution from an incoming URL scheme link. Returns clean Uri for routing.
Method Description
create(LinkCreateRequest) Create a new deep link. Returns DeepLink.
list({page, limit}) List deep links with pagination.
get(linkId) Get a single deep link by ID.

Journiq.events #

Method Description
track(eventName, {deepLinkId?, metadata?}) Track a conversion or custom event. Auto-attaches stored deepLinkId if not provided.
flush() Force flush queued events immediately.

Journiq.analytics #

Method Description
getLinkStats(linkId) Get click statistics for a link. Returns LinkStats.
getAppConfig() Get app configuration. Returns AppConfig.

Journiq.notifications #

Method Description
onNewNotification Stream of new notifications as they arrive.
onUnreadCountChanged Stream of unread count changes.
getAll({page, limit, unreadOnly}) Fetch paginated notifications. Returns NotificationsResult.
markAsRead(notificationId) Mark a notification as read.
getUnreadCount() Get current unread count.
setDisplayHandler(context, handler) Register a custom widget builder for incoming notifications.
setActionHandler(handler) Register a callback for notification tap/dismiss actions.
removeDisplayHandler() Remove the display handler.

Journiq.push #

Method Description
registerToken(fcmToken) Register the device FCM token with Journiq.
handleDataMessage(data) Process an FCM data message. Returns true if handled by Journiq.

Platform Setup #

1. Configure URL Schemes in Journiq Dashboard #

In the Journiq dashboard, navigate to Apps → your app → Edit and configure:

Field Example Description
iOS URL Scheme myapp://{{path}} Template used to open your iOS app. {{path}} is replaced with the deep link path at redirect time.
Android URL Scheme myapp://{{path}} Template used to construct the Android intent URL.
Bundle ID com.example.myapp Your iOS app bundle identifier
Package Name com.example.myapp Your Android application ID
App Store URL https://apps.apple.com/app/id123456 Fallback if app not installed (iOS)
Play Store URL https://play.google.com/store/apps/details?id=com.example.myapp Fallback if app not installed (Android)

Important: The {{path}} placeholder is required. When a user clicks a link with deepLinkPath: "product/123", the redirect service generates myapp://product/123.

2. iOS Setup #

Install native SDK

cd ios && pod install

Register your URL scheme

Add your custom scheme to ios/Runner/Info.plist:

<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>myapp</string>
    </array>
    <key>CFBundleURLName</key>
    <string>com.example.myapp</string>
  </dict>
</array>

Replace myapp with the scheme portion of your iOS URL Scheme (everything before ://).

3. Android Setup #

The SDK dependency is pulled from Maven Central automatically.

Register your URL scheme

Add an intent filter to your main activity in android/app/src/main/AndroidManifest.xml:

<activity
    android:name=".MainActivity"
    android:launchMode="singleTop"
    ...>

    <!-- Existing intent filters ... -->

    <!-- Journiq deep link URL scheme -->
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="myapp" />
    </intent-filter>
</activity>

Replace myapp with the scheme portion of your Android URL Scheme.

Use the app_links package to listen for incoming URLs, then parse them with the Journiq SDK:

import 'package:app_links/app_links.dart';
import 'package:journiq_flutter_sdk/journiq_flutter_sdk.dart';

class DeepLinkHandler {
  final _appLinks = AppLinks();

  void init() {
    // Handle link when app is already running
    _appLinks.uriLinkStream.listen((Uri uri) {
      _handleDeepLink(uri);
    });

    // Handle link that launched the app
    _appLinks.getInitialLink().then((uri) {
      if (uri != null) _handleDeepLink(uri);
    });
  }

  void _handleDeepLink(Uri uri) {
    final path = uri.path.replaceFirst('/', ''); // e.g. "product/123"
    final params = uri.queryParameters;           // e.g. {"ref": "campaign1"}

    // Navigate to the appropriate screen
    navigateTo(path, params);
  }
}

Alternatively, if you use go_router, deep links are handled automatically via its route definitions.

How It Works #

User clicks Journiq link (e.g. https://links.example.com/abc123)
    │
    ▼
Journiq redirect service detects platform
    │
    ├── iOS mobile ──► Redirects to myapp://product/123
    │                   (falls back to App Store if not installed)
    │
    ├── Android ────► Redirects via intent URL
    │                   intent:#Intent;scheme=myapp;package=com.example.myapp;
    │                   S.browser_fallback_url=<Play Store URL>;end
    │                   (falls back to Play Store if not installed)
    │
    └── Web/Desktop ► Redirects to webUrl

Every click goes through the redirect service, ensuring analytics are always recorded before the app opens.

License #

MIT

0
likes
0
points
574
downloads

Publisher

unverified uploader

Weekly Downloads

Journiq deep linking, attribution, and analytics SDK for Flutter. Wraps native Android and iOS SDKs via platform channels.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on journiq_flutter_sdk

Packages that implement journiq_flutter_sdk