var stuff = ["bags", "shoes"];
var profile = {
'Name': 'John Wick',
'Identity': '100',
'DOB': '22-04-2000',
//Key always has to be "DOB" and format should always be dd-MM-yyyy
'Email': '[email protected]',
'Phone': '14155551234',
'props': 'property1',
'stuff': stuff
};
CleverTapPlugin.profileSet(profile);
var values = ["value1", "value2"];
CleverTapPlugin.profileSetMultiValues("props", values);
var values = ["value1", "value2"];
CleverTapPlugin.profileRemoveMultiValues("props", values);
var values = ["value1", "value2"];
CleverTapPlugin.profileAddMultiValues("props", values);
CleverTapPlugin.profileIncrementValue("score", value);
CleverTapPlugin.profileDecrementValue("score", value);
var stuff = ["bags", "shoes"];
var profile = {
'Name': 'Captain America',
'Identity': '100',
'Email': '[email protected]',
'Phone': '+14155551234',
'stuff': stuff
};
CleverTapPlugin.onUserLogin(profile);
CleverTapPlugin.getCleverTapID().then((clevertapId) {})
var lat = 19.07;
var long = 72.87;
CleverTapPlugin.setLocation(lat, long);
Locale locale = Locale('en', 'IN');
CleverTapPlugin.setLocale(locale);
The custom proxy domain feature allows to proxy all events raised from the CleverTap SDK through your required domain, ideal for handling or relaying CleverTap events and Push Impression events with your application server. Refer following steps to configure the custom proxy domain(s) in the manifest file:
- Add your CleverTap Account credentials in the Manifest file against the
CLEVERTAP_ACCOUNT_ID
andCLEVERTAP_TOKEN
keys. - Add the CLEVERTAP_PROXY_DOMAIN key with the proxy domain value for handling events through the custom proxy domain.
- Add the CLEVERTAP_SPIKY_PROXY_DOMAIN key with proxy domain value for handling push impression events.
<meta-data
android:name="CLEVERTAP_ACCOUNT_ID"
android:value="YOUR ACCOUNT ID" />
<meta-data
android:name="CLEVERTAP_TOKEN"
android:value="YOUR ACCOUNT TOKEN" />
<meta-data
android:name="CLEVERTAP_PROXY_DOMAIN"
android:value="YOUR PROXY DOMAIN"/> <!-- e.g., analytics.sdktesting.xyz -->
<meta-data
android:name="CLEVERTAP_SPIKY_PROXY_DOMAIN"
android:value="YOUR SPIKY PROXY DOMAIN"/> <!-- e.g., spiky-analytics.sdktesting.xyz -->
- Add your CleverTap Account credentials in the Info.plist file against the
CleverTapAccountID
andCleverTapToken
keys. - Add the
CleverTapProxyDomain
key with the proxy domain value for handling events through the custom proxy domain e.g., analytics.sdktesting.xyz. - Add the
CleverTapSpikyProxyDomain
key with proxy domain value for handling push impression events e.g., spiky-analytics.sdktesting.xyz. - Import the CleverTap SDK in your AppDelegate file and call the following method in the
didFinishLaunchingWithOptions:
method.CleverTap.autoIntegrate()
var eventData = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves'
};
CleverTapPlugin.recordEvent("Flutter Event", eventData);
var item1 = {
// Key: Value
'name': 'thing1',
'amount': '100'
};
var item2 = {
// Key: Value
'name': 'thing2',
'amount': '100'
};
var items = [item1, item2];
var chargeDetails = {
// Key: Value
'total': '200',
'payment': 'cash'
};
CleverTapPlugin.recordChargedEvent(chargeDetails, items);
_clevertapPlugin.setCleverTapInAppNotificationButtonClickedHandler(inAppNotificationButtonClicked);
void inAppNotificationButtonClicked(Map<String, dynamic> map) {
this.setState(() {
print("inAppNotificationButtonClicked called = ${map.toString()}");
});
}
_clevertapPlugin.setCleverTapInAppNotificationDismissedHandler(inAppNotificationDismissed)
void inAppNotificationDismissed(Map<String, dynamic> map) {
this.setState(() {
print("inAppNotificationDismissed called");
});
}
CleverTapPlugin.suspendInAppNotifications();
CleverTapPlugin.discardInAppNotifications();
CleverTapPlugin.resumeInAppNotifications();
CleverTapPlugin.initializeInbox();
var styleConfig = {
'noMessageTextColor': '#ff6600',
'noMessageText': 'No message(s) to show.',
'navBarTitle': 'App Inbox'
};
CleverTapPlugin.showInbox(styleConfig);
_clevertapPlugin.setCleverTapInboxNotificationMessageClickedHandler(inboxNotificationMessageClicked);
void inboxNotificationMessageClicked(Map<String, dynamic>? data, int contentPageIndex, int buttonIndex) {
this.setState(() {
print("App Inbox item: ${data.toString()}");
print("Content Page index: $contentPageIndex");
print("Button index: $buttonIndex");
});
}
_clevertapPlugin.setCleverTapInboxNotificationButtonClickedHandler(inboxNotificationButtonClicked);
void inboxNotificationButtonClicked(Map<String, dynamic>? map) {
this.setState(() {
print("inboxNotificationButtonClicked called = ${map.toString()}");
});
}
CleverTapPlugin.dismissInbox();
int total = await CleverTapPlugin.getInboxMessageCount();
print("Total count = " + total.toString());
int unread = await CleverTapPlugin.getInboxMessageUnreadCount();
print("Unread count = " + unread.toString());
List messages = await CleverTapPlugin.getAllInboxMessages();
List messages = await CleverTapPlugin.getUnreadInboxMessages();
var messageForId = await CleverTapPlugin.getInboxMessageForId(messageId);
await CleverTapPlugin.deleteInboxMessageForId(messageId);
var messageList = await CleverTapPlugin.getUnreadInboxMessages();
if (messageList == null || messageList.length == 0) return;
Map<dynamic, dynamic> itemFirst = messageList[0];
if (Platform.isAndroid) {
await CleverTapPlugin.markReadInboxMessageForId(itemFirst["id"]);
} else if (Platform.isIOS) {
await CleverTapPlugin.markReadInboxMessageForId(itemFirst["_id"]);
}
await CleverTapPlugin.pushInboxNotificationViewedEventForId(messageId);
await CleverTapPlugin.pushInboxNotificationClickedEventForId(messageId);
CleverTapPlugin.setDebugLevel(3);
Register a setCleverTapPushClickedPayloadReceivedHandler
handler to get a notification click callback along with the entire payload.
_clevertapPlugin.setCleverTapPushClickedPayloadReceivedHandler(pushClickedPayloadReceived);
void pushClickedPayloadReceived(Map<String, dynamic> notificationPayload) {
print("pushClickedPayloadReceived called with notification payload: " + notificationPayload.toString());
// You may perform UI operation like redirecting the user to a specific page based on custom key-value pairs
// passed in the notificationPayload. You may also perform non UI operation such as HTTP requests, IO with local storage etc.
handleNotificationClick(notificationPayload);
}
Note:
Please note that the
pushClickedPayloadReceived
handler is triggered in Android platform only when the app is in the foreground or background states, and not when it has been terminated(killed). However, in the case of iOS platform, this handler is supported regardless of whether the app is in the foreground, background, or has been terminated (killed).
[Android Platform] Handle Notification Trampoline Restrictions to support pushClickedPayloadReceived
handler in Android 12 and Above
Due to notification trampoline restrictions, Android 12 and above do not directly support the pushClickedPayloadReceived
callback.
Hence, apps need to add manual handling for Android 12 and above to inform the CleverTap SDK about the notification click and get the pushClickedPayloadReceived
callback.
Add the following code in the onNewIntent()
method of the Launcher FlutterActivity
class in android:
class MainActivity : FlutterActivity() {
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
// On Android 12 and above, inform the notification click to get the pushClickedPayloadReceived callback on dart side.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
cleverTapDefaultInstance?.pushNotificationClickedEvent(intent!!.extras)
}
}
}
The CleverTap Plugin provides two ways to handle user interactions with notifications, depending on whether the app needs to perform UI or non-UI operations.
The default behavior on Android is to launch the application if the application is terminated(killed).
Use CleverTapPlugin.getAppLaunchNotification()
to get a Future containing a notification-payload of Map
type if the application is opened from a terminated(killed) state.
Depending on the content of a notification-payload, you may perform UI operation like redirecting the user to a specific page.
class Application extends StatefulWidget {
@override
State<StatefulWidget> createState() => _Application();
}
class _Application extends State<Application> {
void _handleKilledStateNotificationInteraction() async {
// Retrieve the notification-payload in a 'CleverTapAppLaunchNotification' class object
// which caused the application to open from a terminated state.
CleverTapAppLaunchNotification appLaunchNotification = await CleverTapPlugin
.getAppLaunchNotification();
if (appLaunchNotification.didNotificationLaunchApp) {
//App is launched from a notification click which was rendered by the CleverTap SDK.
Map<String, dynamic> notificationPayload = appLaunchNotification.payload!;
_handleDeeplink();
}
}
void _handleDeeplink() {
// It is assumed that all notifications contain a data field with the key 'type' but you may also have
// a different key for deeplink handling.
var type = notificationPayload["type"];
if (type != null) {
print(
"_handleKilledStateNotificationInteraction => Type: $type");
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
DeepLinkPage(type: type)));
}
}
@override
void initState() {
super.initState();
// Run CleverTapPlugin.getAppLaunchNotification in an async function
// as initState() must not be async
if (Platform.isAndroid) {
_handleKilledStateNotificationInteraction();
}
}
@override
Widget build(BuildContext context) {
return Text("...");
}
}
Note:
The notification needs to be generated by the CleverTap SDK to get the notification payload from the
CleverTapPlugin.getAppLaunchNotification()
API.
There are two steps to setup the onKilledStateNotificationClicked
handler:
- Your
Application
class should extend theCleverTapApplication
class instead of theFlutterApplication
class. - Register the
onKilledStateNotificationClicked
handler to get a notification click callback along with the entire payload. When notification is clicked, an isolate is spawned (Android only) allowing you to handle notification click even when your application is not running. There are a few things to keep in mind about youronKilledStateNotificationClicked
handler:
- It must not be an anonymous function.
- It must be a top-level function (e.g. not a class method which requires initialization).
- When using Flutter version 3.3.0 or higher, the
onKilledStateNotificationClicked
handler must be annotated with@pragma('vm:entry-point')
right above the function declaration (otherwise it may be removed during tree shaking for release mode).
Add the following method to your main.dart
file, right after the import statements, and outside any Widget class declaration, to process push notifications in the killed state via a Flutter background isolate:
@pragma('vm:entry-point')
void _onKilledStateNotificationClickedHandler(Map<String, dynamic> map) async {
print("Notification Payload received: " + map.toString());
}
void main() {
CleverTapPlugin.onKilledStateNotificationClicked(_onKilledStateNotificationClickedHandler);
runApp(MyApp());
}
Note:
Since the
_onKilledStateNotificationClickedHandler
handler runs in its own isolate outside your applications context, it is not possible to update application state or execute any UI operation from the handler itself. You can, however, perform HTTP requests, IO operations with local storage etc.
CleverTapPlugin.createNotificationChannel("fluttertest", "Flutter Test", "Flutter Test", 3, true);
Starting from CleverTap Plugin v1.8.0 we have introduced a new feature that allows developers to define a default notification channel for their app. This feature provides flexibility in handling push notifications. Please note that this is only supported for clevertap core notifications. Support for push templates will be released soon. To specify the default notification channel ID, you can add the following metadata in your app's manifest file:
<meta-data android:name="CLEVERTAP_DEFAULT_CHANNEL_ID" android:value="your_default_channel_id" />
By including this metadata, you can define a specific notification channel that CleverTap will use if the channel provided in push payload is not registered by your app. This ensures that push notifications are displayed consistently even if the app's notification channels are not set up.
In case the SDK does not find the default channel ID specified in the manifest, it will automatically fallback to using a default channel called "Miscellaneous". This ensures that push notifications are still delivered, even if no specific default channel is specified in the manifest.
This enhancement provides developers with greater control over the default notification channel used by CleverTap for push notifications, ensuring a seamless and customizable user experience.
CleverTapPlugin.deleteNotificationChannel(“channelId”);
CleverTapPlugin.createNotificationChannelGroup(“groupId”, “groupName”);
CleverTapPlugin.deleteNotificationChannelGroup(“channelId”);
CleverTapPlugin.setPushToken(“value”);
CleverTapPlugin.setBaiduPushToken(“value”);
CleverTapPlugin.setHuaweiPushToken(“value”);
CleverTapPlugin.createNotification(data);
CleverTapPlugin.processPushNotification(data);
void onDisplayUnitsLoaded(List<dynamic> displayUnits) {
this.setState(() {
print("Display Units = " + displayUnits.toString());
});
}
void onDisplayUnitsLoaded(List<dynamic> displayUnits) {
this.setState(() async {
List displayUnits = await CleverTapPlugin.getAllDisplayUnits();
print("Display Units = " + displayUnits.toString());
});
}
CleverTapPlugin.pushDisplayUnitViewedEvent(“unitId”);
CleverTapPlugin.pushDisplayUnitClickedEvent(“unitId”);
void productConfigInitialized() {
print("Product Config Initialized");
this.setState(() async {
await CleverTapPlugin.fetch();
});
}
void fetch() {
CleverTapPlugin.fetch();
// CleverTapPlugin.fetchWithMinimumIntervalInSeconds(0);
}
void activate() {
CleverTapPlugin.activate();
}
void fetchAndActivate() {
CleverTapPlugin.fetchAndActivate();
}
CleverTapPlugin.setMinimumFetchIntervalInSeconds(interval);
CleverTapPlugin.getProductConfigBoolean(“key”);
CleverTapPlugin.getLastFetchTimeStampInMillis();
void featureFlagsUpdated() {
this.setState(() async {
bool booleanVar = await CleverTapPlugin.getFeatureFlag("BoolKey", false);
});
}
CleverTapPlugin.enablePersonalization();
CleverTapPlugin.disablePersonalization();
CleverTapPlugin.pushInstallReferrer("source", "medium", "campaign");
CleverTapPlugin.setOptOut(false); ///Will opt in the user to send data to CleverTap
CleverTapPlugin.setOptOut(true); ///Will opt out the user to send data to CleverTap
// Will opt out the user to send Device Network data to CleverTap
CleverTapPlugin.enableDeviceNetworkInfoReporting(false);
// Will opt in the user to send Device Network data to CleverTap
CleverTapPlugin.enableDeviceNetworkInfoReporting(true);
// Will set the user online
CleverTapPlugin.setOffline(false);
// Will set the user offline
CleverTapPlugin.setOffline(true);
Follow the Push Primer integration doc.
PII data is stored across the SDK and could be sensitive information. From CleverTap Flutter SDK v1.9.0 onwards, you can enable encryption for PII data wiz. Email, Identity, Name and Phone.
Currently 2 levels of encryption are supported i.e None(0) and Medium(1). Encryption level is None by default. None - All stored data is in plaintext Medium - PII data is encrypted completely.
Add encryption level in the AndroidManifest.xml
as following:
<meta-data
android:name="CLEVERTAP_ENCRYPTION_LEVEL"
android:value="1" />
Add the CleverTapEncryptionLevel
String key to info.plist
file where value 1 means Medium and 0 means None. Encryption Level will be None if any other value is provided.