Flutter SDK
Reflect SDK for Flutter — a thin Dart + native bridge over the shared ReflectCore engine. Mobile attribution, event tracking, deep linking, and SKAN for iOS and Android.
ReflectCore engine — the same Kotlin (reflect-android) and Swift (reflect-ios) core the React Native and Unity SDKs use. All logic (durable on-disk queue, HMAC-signed ingest, batching, response-driven retry, device signals, deferred deep links, attribution, SKAN, ATT) lives in the core; the Dart layer only forwards each call over a method channel. 1.6.0 and earlier were a standalone re-implementation that posted unsigned events — 1.7.0 is a native rewrite, but the public Dart API stays backward-compatible and gains new methods. Yourinstall_uuid is preserved across the upgrade.Installation
Add the dependency to your pubspec.yaml, pinned to a release tag:
dependencies:
reflect_sdk:
git:
url: https://github.com/bablu147/reflect-sdk-flutter.git
ref: v1.7.0Then run flutter pub get. Because the plugin pulls its native core as a versioned dependency, a consumer app needs two one-time additions so the published cores resolve.
Android — add the JitPack repo in your app's android/settings.gradle:
dependencyResolutionManagement {
repositories {
maven { url 'https://jitpack.io' } // com.github.bablu147:reflect-android
}
}The AAR brings its transitive dependencies (Play Install Referrer, App Set ID, ads-identifier) and R8 keep-rules automatically.
iOS — run cd ios && pod install. If the ReflectCore pod is not yet on CocoaPods trunk, add it to your ios/Podfile:
pod 'ReflectCore', :git => 'https://github.com/bablu147/reflect-ios.git', :tag => '1.0.0'Requirements
- Dart >=3.0.0, Flutter >=3.10.0
- Android: minSdkVersion 21
- iOS: 12+
- Pulls the shared
ReflectCorenative engine (JitPack AAR on Android, theReflectCorepod on iOS) — no other third-party dependencies
Quick start
import 'package:reflect_sdk/reflect_sdk.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Reflect.initialize(ReflectConfig(
appKey: "app_live_...",
companyKey: "co_live_...",
baseUrl: "https://api.reflect.cloud",
// signingSecret: "sec_...", // optional — HMAC-signs ingest + surfaces attribution
));
runApp(MyApp());
}With a signingSecret set, every event batch is HMAC-signed and posted to the authenticated /event endpoint; without one the SDK falls back to the unsigned /event/batch path.
API reference
| Method | Description |
|---|---|
Reflect.initialize(config) | Initialize the SDK (call once at app start) |
Reflect.trackEvent(name, properties?) | Track a named event with optional properties |
Reflect.trackRevenue(params) | Track a revenue event |
Reflect.trackPurchase(params) | Track a purchase event with optional receipt |
Reflect.trackSubscription(params) | Track a subscription event |
Reflect.verifyPurchase(params) | Verify a receipt server-side and return a typed result |
Reflect.verifyAndTrackPurchase(params) | Verify a receipt AND track the purchase |
Reflect.trackAdRevenue(params) | Track mediated ad revenue (fires ad_impression) |
Reflect.setUserId(userId) | Set user ID for cross-device attribution |
Reflect.clearUserId() | Clear user ID (e.g. on logout) |
Reflect.setEmail(email) | Attach the user's RAW email to future events (server hashes it; consent-gated) — enables email attribution |
Reflect.clearEmail() | Clear the stored email (e.g. on logout) |
Reflect.setUserProperties(props) | Set properties attached to all future events |
Reflect.setGlobalProperty(key, val) | Set a property merged into every event |
Reflect.unsetGlobalProperty(key) | Remove a global property |
Reflect.clearGlobalProperties() | Remove all global properties |
Reflect.setPartnerParameter(key, val) | Set a global partner parameter forwarded to integrations |
Reflect.setPartnerSharing(map) | Per-partner third-party-sharing overrides |
Reflect.setThirdPartySharing(enabled) | Opt in/out of partner data sharing |
Reflect.setConsent(state) / getConsent() | Set/read data-collection consent (attached as consent_state) |
Reflect.setAdvertisingConsent(granted) | Grant/revoke IDFA/GAID consent |
Reflect.setExternalDeviceId(id) | Attach a customer-owned device identifier |
Reflect.requestIosTracking() | Request iOS ATT permission (returns status) |
Reflect.getInstallUuid() | Get the persistent install UUID |
Reflect.getAttribution() | Get current attribution data |
Reflect.getAttributionWithTimeout(ms) | Force a fresh attribution check, resolving early or after the timeout |
Reflect.onAttributionChanged | Stream firing when the server resolves/changes attribution |
Reflect.updateConversionValue(...) | Update SKAN conversion value (iOS only) |
Reflect.getInitialDeepLink() | Get the deep link that opened the app |
Reflect.getLastDeepLink() | The last deep link handled (cold/warm/deferred) |
Reflect.onDeepLink | Stream of deep link events while running |
Reflect.resolveDeepLink(url) | Unshorten/resolve a branded tracking URL via the server |
Reflect.handleDeepLink(url) | Feed the SDK a link the app captured itself |
Reflect.registerPushToken(token, provider) | Register a push token (fires _push_token) |
Reflect.setPushToken(token) | Sticky push token stamped on every event |
Reflect.setIntegrityToken(token) | Supply a Play Integrity / App Attest token (anti-fraud) |
Reflect.setAudience(tags) | Tag the install for audience segmentation |
Reflect.deleteUserData() | GDPR — delete all user data |
Reflect.setEnabled(enabled) / isEnabled() | Enable/disable the SDK at runtime |
Reflect.setOfflineMode(offline) | Pause/resume sending (keeps tracking + queuing on-device) |
Reflect.flush() | Force-flush buffered events |
Reflect.debugSnapshot() | PII-safe snapshot of SDK state (drives ReflectDebugOverlay) |
Event tracking
// Simple event
await Reflect.trackEvent("level_complete", properties: {
"level": 5,
"score": 12340,
});
// Revenue event
await Reflect.trackRevenue(RevenueParams(
amount: 4.99,
currency: "USD",
productId: "gems_500",
transactionId: "txn_abc123",
));
// Attribute installs/revenue to an email (pass it RAW — the server hashes it;
// only sent while consent is not denied).
await Reflect.setEmail("[email protected]");
await Reflect.clearEmail(); // on logoutThe SDK sends the event property bag on the wire as properties; the server maps it to its canonical props field, so props.email reaches attribution. See Privacy & consent for the consent gate and hashing details.
Deep linking
// Get the link that launched the app (incl. server-resolved deferred links)
final initial = await Reflect.getInitialDeepLink();
if (initial != null) {
navigateTo(initial.path);
}
// Listen for links while running (isDeferred = true for deferred links)
Reflect.onDeepLink.listen((data) {
navigateTo(data.path);
});SKAN (iOS)
final result = await Reflect.updateConversionValue(
42,
coarseValue: "high",
lockWindow: false,
);
if (!result.success) print("SKAN error: ${result.error}");Standard events
Pre-built helpers with typed parameters:
import 'package:reflect_sdk/reflect_sdk.dart';
ReflectStandardEvents.signUpWith("google");
ReflectStandardEvents.levelCompleted(5, score: 12340);
ReflectStandardEvents.addedToCart("gems_500", 4.99, "USD");
ReflectStandardEvents.adShown("admob", "interstitial", revenue: 0.02, currencyCode: "USD");Global properties
await Reflect.setGlobalProperty("ab_group", "variant_b");
await Reflect.unsetGlobalProperty("ab_group");
await Reflect.clearGlobalProperties();Purchase & subscription
await Reflect.trackPurchase(PurchaseParams(
productId: "gems_500",
price: 4.99,
currency: "USD",
receiptData: "<base64-receipt>",
));
await Reflect.trackSubscription(SubscriptionParams(
productId: "pro_monthly",
price: 9.99,
currency: "USD",
isTrial: true,
));
// Verify a receipt server-side AND track it in one call
final result = await Reflect.verifyAndTrackPurchase(PurchaseParams(
productId: "gems_500",
transactionId: "txn_abc123",
receiptData: "<base64-receipt>",
));Privacy (GDPR)
final deleted = await Reflect.deleteUserData();
// Clears local state + sends deletion request to serverReflectCore, the SDK now HMAC-signs ingest, and gains server-side receipt verification (verifyPurchase/verifyAndTrackPurchase), mediated ad revenue (trackAdRevenue), partner parameters & sharing controls, attestation tokens (setIntegrityToken), link resolution (resolveDeepLink/handleDeepLink), offline-mode toggles, and a live debug snapshot — on top of the existing track, consent, deep-link, ATT, and SKAN API. All APIs are async (Future<T>); deep links and attribution use streams.