layers_flutter 1.0.0 copy "layers_flutter: ^1.0.0" to clipboard
layers_flutter: ^1.0.0 copied to clipboard

Layers SDK for Flutter. Analytics with ATT, SKAN, and deep link integrations.

Layers Flutter SDK #

Flutter SDK for Layers analytics, built on a Rust core via dart:ffi.

Installation #

dependencies:
  layers_flutter: ^0.1.0

Usage #

import 'package:layers_flutter/layers_flutter.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await Layers.init(LayersConfig(
    apiKey: 'your-api-key',
    appId: 'your-app-id',
  ));

  runApp(MyApp());
}

Track Events #

Layers.track('button_tapped', properties: {'screen': 'home'});

Screen Views #

Layers.screen('HomeScreen');

Automatic Screen Tracking #

Add LayersNavigatorObserver to your MaterialApp to track screen views automatically when routes change:

MaterialApp(
  navigatorObservers: [LayersNavigatorObserver()],
  // ...
)

Identify Users #

Layers.identify('user-123');

Set User Properties #

Layers.setUserProperties({'plan': 'premium', 'signup_date': '2025-01-15'});

Control what data the SDK collects. Set analytics and/or advertising to true or false. Null values mean "not determined".

Layers.setConsent(ConsentSettings(analytics: true, advertising: false));

ATT Integration #

Request App Tracking Transparency authorization on iOS. On Android, all ATT methods return safe defaults.

// Check if ATT is available (iOS 14.5+)
final available = await ATT.isAvailable();

if (available) {
  // Check current status before prompting
  final status = await ATT.getStatus();

  if (status == ATTStatus.notDetermined) {
    // Show the system ATT dialog
    final result = await ATT.requestAuthorization();

    if (result == ATTStatus.authorized) {
      // User granted tracking permission
      final idfa = await ATT.getAdvertisingId();
    }
  }
}

SKAN Integration #

Update SKAdNetwork conversion values on iOS. All methods are no-ops on Android.

// SKAN 2.0+: update fine conversion value (0-63)
await SKAN.updateConversionValue(42);

// SKAN 4.0: update with coarse value and optional window lock
await SKAN.updatePostbackConversionValue(
  fineValue: 42,
  coarseValue: SKANCoarseValue.high,
  lockWindow: true,
);

iOS Setup #

Add your URL scheme to Info.plist:

<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>myapp</string>
    </array>
  </dict>
</array>

For Universal Links, add the Associated Domains entitlement:

applinks:yourdomain.com

Android Setup #

Add intent filters to AndroidManifest.xml:

<activity ...>
  <!-- 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>

  <!-- App Links (verified) -->
  <intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="https" android:host="yourdomain.com" />
  </intent-filter>
</activity>

Dart Code #

// Get the deep link that launched the app (cold start)
final initialLink = await DeepLinks.getInitialLink();
if (initialLink != null) {
  handleDeepLink(initialLink);
}

// Listen for deep links while the app is running (warm start)
final unsubscribe = DeepLinks.addListener((data) {
  // data.url, data.scheme, data.host, data.path, data.queryParams
  handleDeepLink(data);
});

// Stop listening when done
unsubscribe();

Commerce Tracking #

Commerce.trackPurchase(
  productId: 'pro_monthly',
  revenue: 9.99,
  currency: 'USD',
  transactionId: 'txn_abc123',
  store: 'app_store',
  quantity: 1,
);

RevenueCat Integration #

Connect your existing RevenueCat Purchases instance to automatically track subscription events and sync user properties. No hard dependency on purchases_flutter -- uses duck typing.

import 'package:purchases_flutter/purchases_flutter.dart';

// Connect after RevenueCat is configured
RevenueCat.connect(Purchases.instance);

// Optionally track individual package purchases
final offerings = await Purchases.instance.getOfferings();
final package = offerings.current?.availablePackages.first;
if (package != null) {
  RevenueCat.trackPurchase(package);
}

Superwall Integration #

Track paywall events from your existing Superwall setup. No hard dependency on superwall_flutter -- uses duck typing.

// Track paywall presentation
Superwall.instance.setPaywallPresentationHandler(
  PaywallPresentationHandler()
    ..onPresent((info) {
      LayersSuperwall.trackPresentation(info);
    })
    ..onDismiss((info) {
      LayersSuperwall.trackDismiss(info);
    })
    ..onSkip((reason) {
      LayersSuperwall.trackSkip(null, reason.toString());
    }),
);

Error Handling #

Register an onError callback to receive SDK errors. Errors are always logged via dart:developer regardless of this callback.

Layers.onError = (error) {
  // Forward to your crash reporter, logging service, etc.
  print(error);
};

await Layers.init(LayersConfig(
  apiKey: 'your-api-key',
  appId: 'your-app-id',
));

The SDK also provides typed exceptions:

import 'package:layers_flutter/layers_flutter.dart';

// LayersException — base type with message and optional code
// LayersNotInitializedException — thrown when calling methods before init
// LayersQueueFullException — thrown when the event queue is at capacity

Debug Mode #

Enable debug logging to see SDK activity in the console and dart:developer logs:

await Layers.init(LayersConfig(
  apiKey: 'your-api-key',
  appId: 'your-app-id',
  enableDebug: true,
));

When enabled, the SDK logs track, screen, and identify calls with their arguments.

Print the full SDK state at any time:

Layers.debugPrintState();
// [Layers] === SDK Status ===
// [Layers] Initialized: true
// [Layers] Session ID: abc-123
// [Layers] Queue Depth: 5
// [Layers] User ID: user-42
// [Layers] Consent: analytics=true, advertising=unset
// [Layers] Debug Mode: true
// [Layers] Environment: production
// [Layers] App ID: your-app-id
// [Layers] Base URL: (default)
// [Layers] === End Status ===

Testing #

Use enableTestMode to inject a mock bindings implementation so tests run without the native Rust library:

import 'package:layers_flutter/layers_flutter.dart';

void main() {
  late MockLayersBindings mock;

  setUp(() {
    mock = MockLayersBindings();
    Layers.enableTestMode(mock);
  });

  tearDown(() {
    Layers.resetForTesting();
  });

  test('tracks events', () {
    Layers.track('button_tap', properties: {'screen': 'home'});
    expect(mock.trackedEvents, hasLength(1));
    expect(mock.trackedEvents.first['event'], 'button_tap');
  });
}
0
likes
135
points
20
downloads

Publisher

unverified uploader

Weekly Downloads

Layers SDK for Flutter. Analytics with ATT, SKAN, and deep link integrations.

Documentation

API reference

License

MIT (license)

Dependencies

ffi, flutter, path_provider

More

Packages that depend on layers_flutter

Packages that implement layers_flutter