localytics_flutter_sdk 0.0.1
localytics_flutter_sdk: ^0.0.1 copied to clipboard
Flutter plugin for the Localytics analytics, push, and engagement SDK on Android and iOS.
localytics_flutter_sdk #
Flutter plugin that wraps the official Localytics native SDKs:
- Android —
com.localytics.androidx:library:7.1.0from the Localytics public Maven repo. - iOS —
Localytics-swiftpm7.1.1(pinned) via Swift Package Manager.
Published on pub.dev as localytics_flutter_sdk (the localytics_flutter name is
held by a legacy package we do not control).
Requirements #
| Minimum | |
|---|---|
| Flutter | 3.22.0 (with SPM enabled) |
| Dart | 3.5.0 |
| Android | minSdk 21 |
| iOS | 12.0 |
Enabling Swift Package Manager #
The plugin ships iOS support via SPM only — there is no .podspec.
SPM has been available in Flutter since 3.22 but is not always on by
default. Enable it once per machine:
flutter config --enable-swift-package-manager
You can verify it's on with flutter config (look for
enable-swift-package-manager: true).
Installation #
Add the plugin to your app's pubspec.yaml:
dependencies:
localytics_flutter_sdk: ^0.0.1
Then run:
flutter pub get
iOS — Swift Package Manager #
The plugin declares its dependency on the official Localytics SPM package directly. Make sure SPM is enabled in your Flutter install (see Enabling Swift Package Manager above).
The first iOS build will fetch and compile Localytics-swiftpm from
GitHub — expect a couple of extra minutes on the first run; subsequent
builds are cached.
Android — Maven repository #
The plugin's build.gradle already adds the Localytics Maven repository.
However, your app-level android/build.gradle (or the consuming app's
settings.gradle dependencyResolutionManagement block) must also expose it
because Gradle resolves dependencies from the consuming app's repositories,
not the plugin's:
// android/build.gradle (project level) OR settings.gradle
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url 'https://maven.localytics.com/public' }
}
}
You also need to add a localytics.xml file to your app at
android/app/src/main/res/values/localytics.xml containing your Localytics app
key. See the official Localytics Android docs
for the full template.
Google Play Services Ads Identifier
The Localytics SDK reflectively resolves AdvertisingIdClient at runtime
to attach the device ADID to analytics payloads. Without that class on the
classpath the SDK crashes at the first session open with:
java.lang.NoClassDefFoundError: Failed resolution of:
Lcom/google/android/gms/ads/identifier/AdvertisingIdClient;
This plugin already pulls in com.google.android.gms:play-services-ads-identifier
as an api dependency, so it's transitively available in your app — no
extra action needed for typical Play-store builds.
If you target stores that forbid Google Play Services (Huawei AppGallery,
Amazon Appstore, F-Droid, etc.), exclude it explicitly in your app's
android/app/build.gradle:
dependencies {
implementation('com.localytics.flutter') {
exclude group: 'com.google.android.gms',
module: 'play-services-ads-identifier'
}
}
The SDK swallows the resulting ClassNotFoundException and proceeds
without an ADID attached.
Initialization #
The native SDK is initialized via the standard Localytics Builder /
autoIntegrate flow on each platform. This plugin does not wrap the
initialization step — you should keep that in your platform-native code
(Application.kt for Android, AppDelegate.swift for iOS) so you get the
exact behavior described in the Localytics docs.
Android: MainActivity must extend FlutterFragmentActivity #
The Localytics Android SDK requires a FragmentActivity subclass to
host the dialog fragment that renders in-app messages. Flutter's
default FlutterActivity extends androidx.core.app.ComponentActivity,
not FragmentActivity — so triggering an in-app message with the
default scaffold fails with:
In-app messages can only appear in Activities subclassing
FragmentActivity, which includes ActionBarActivity and AppCompatActivity.
Switch your MainActivity to Flutter's first-class
FlutterFragmentActivity instead. It's a drop-in replacement — same
lifecycle, same plugin behavior, same manifest setup:
package com.example.app
import io.flutter.embedding.android.FlutterFragmentActivity
class MainActivity : FlutterFragmentActivity()
No AndroidManifest.xml changes are needed (the activity entry stays
the same).
Library version tagging #
The plugin automatically tags itself with the native SDK during
onAttachedToEngine / register(with:), so every uploaded event
reports a library identifier like:
androida_7.1.0:Flutter_0.0.1 # Android
iosa_7.1.1:Flutter_0.0.1 # iOS
This matches the convention used by the Localytics Xamarin/MAUI and React Native wrappers, and lets Localytics' analytics dashboards break down traffic by wrapper SDK. The tagging is best-effort — if the call fails for any reason the SDK simply continues with its default identifier.
The version string is defined once in pubspec.yaml and propagated to
Dart, Kotlin, Swift, and android/build.gradle by:
dart run tool/sync_plugin_version.dart
Run that command after every version: bump. For native SDK bumps
(Android Maven / iOS SPM) and coordinated release checklists, see
VERSIONING.md.
After native initialization, all Dart code interacts with the SDK through
the Localytics class:
import 'package:localytics_flutter_sdk/localytics_flutter_sdk.dart';
await Localytics.setLoggingEnabled(true);
await Localytics.tagEvent('Onboarding Completed');
await Localytics.setCustomerId('3neRKTxbNWYKM4NJ');
await Localytics.upload();
Public API #
The plugin exposes the following surface. Each row maps to one or more
methods on the Localytics facade.
| Area | Methods |
|---|---|
| Privacy / logging | setLoggingEnabled, setOptedOut, isOptedOut, setPrivacyOptedOut, isPrivacyOptedOut |
| Session / upload | openSession, closeSession, upload, pauseDataUploading, setSessionTimeoutInterval (no-op; configure at init) |
| Test mode / theme | setTestModeEnabled, isTestModeEnabled, enableDarkMode |
| Diagnostics | getCustomerId, getIdentifier, getPushRegistrationId, getInstallId, getAppKey, getLibraryVersion, Localytics.pluginVersion |
| Events | tagEvent, tagScreen, setCustomDimension, getCustomDimension, setIdentifier |
| Ecommerce | tagPurchased, tagAddedToCart, tagStartedCheckout, tagCompletedCheckout |
| Content | tagContentViewed, tagSearched, tagShared, tagContentRated |
| Customer identity | setCustomerId, setCustomerIdWithPrivacyOptedOut, setCustomerEmail, setCustomerFirstName, setCustomerLastName, setCustomerFullName, tagCustomerRegistered, tagCustomerLoggedIn, tagCustomerLoggedOut, tagInvited |
| Profile | setProfileAttribute, deleteProfileAttribute, addProfileAttributesToSet, removeProfileAttributesFromSet, incrementProfileAttribute, decrementProfileAttribute |
| In-app | triggerInAppMessage, dismissCurrentInAppMessage, setInAppMessageDismissButtonLocation, triggerSessionStartInAppMessages |
| Location / Places | setLocationMonitoringEnabled, persistLocationMonitoring |
| Push (cross-platform) | setPushRegistrationId, handleTestModeURL |
| Push (Android-only) | registerPush, handleFirebaseMessage, tagPushReceivedEvent |
| Push (iOS-only) | didReceiveNotificationResponse, handleNotification, handleNotificationReceived, didRequestUserNotificationAuthorization, didRegisterNotificationSettings |
| Inbox | getInboxCampaigns, refreshInboxCampaigns, getAllInboxCampaigns, refreshAllInboxCampaigns, getInboxCampaignsUnreadCount, setInboxCampaignRead, deleteInboxCampaign, inboxListItemTapped |
Models / enums #
Customer— used withtagCustomerRegisteredandtagCustomerLoggedIn.InboxCampaign— read-only descriptor returned by inbox queries.ProfileScope—application(default) ororganization.InAppDismissButtonLocation—leftorright.
Platform-only methods #
The Android-only and iOS-only push entries are still callable from any
platform — the opposite platform implements them as a graceful no-op so
your cross-platform Dart code never throws MissingPluginException. This
lets you keep a single push pipeline in shared Dart code:
if (Platform.isAndroid) {
final handled = await Localytics.handleFirebaseMessage(message.data);
} else {
await Localytics.didReceiveNotificationResponse(
userInfo: message.data,
actionIdentifier: response.actionIdentifier,
);
}
Location / Places #
setLocationMonitoringEnabled and persistLocationMonitoring tell the
native SDK to use location for geofence / Places campaigns. They do
not show the system permission dialog — request location access in
your Flutter app first (for example with
permission_handler or
geolocator), then call these
once the user has granted the authorization level you need.
You still need the usual platform setup in the host app (AndroidManifest
location permissions, iOS Info.plist usage strings, background modes
if required). On iOS, some flows also require a native
LLLocationMonitoringDelegate for permission prompts — see the
Localytics iOS integration guide.
// Example: after your app has obtained location permission
await Localytics.setLocationMonitoringEnabled(true);
await Localytics.persistLocationMonitoring(true);
Not covered (yet) #
- Advanced geofencing / Places (
setLocation,triggerRegion,geofencesToMonitor, region enter/exit listeners) — requiresEventChanneland richer native delegate wiring. LocationListener/CallToActionListenercallbacks — requireEventChannel.
Architecture #
The plugin uses a plain MethodChannel (com.localytics.flutter/methods).
A future revision may migrate to Pigeon
for type-safe codegen — the existing API is structured to make that swap
mechanical.
Production readiness #
See PRODUCTION_READINESS.md for an integration
audit, known limitations, host-app requirements, and a pre-ship checklist
(excluding pub.dev deployment).
Releasing & testing the published artifact #
The bundled example/ app exercises the plugin via a same-
repo path: dependency, which is great for day-to-day iteration but
won't catch every "ships broken" issue. Before tagging a release, walk
through the validation workflow documented in
RELEASING.md — it covers pub publish --dry-run,
pana scoring, consumer-app testing via git ref, release-mode builds,
and the version-sync checklist that keeps the four pluginVersion
constants and the two native SDK pins in lockstep.
Secrets and the example app #
Real Localytics app keys must never be committed or published.
| Location | What ships publicly |
|---|---|
| pub.dev package | Plugin only — example/ is excluded via .pubignore |
| Git | .env and LocalyticsEnv.xcconfig are gitignored; only .env.example with placeholders may be committed |
| Your machine | Copy .env.example → .env locally and add your keys (see example/README.md) |
The pub.dev tarball does not include your .env, generated xcconfig files, or
the tool/sync_sample_env.dart helper. Clone the repository to run the example
app.
License #
This plugin’s source code is licensed under the Apache License, Version 2.0.
Use of the Localytics platform and native Android/iOS SDKs remains subject to your Localytics customer agreement and the separate terms that govern those SDKs.