PAM Flutter SDK
A Flutter plugin for integrating PAM (Personalized Advertising Management) into your mobile applications.
Table of Contents
- Installation
- Migrating from 2.x
- Configuration
- Initialization
- Core Features
- API Reference
- Examples
- Troubleshooting
- License
Installation
Prerequisites
- Flutter SDK version 3.3.0 or later
- Dart SDK version 3.6.0 or later
Adding pam_flutter to Your Project
Open a terminal and run the following command to add pam_flutter to your Flutter project:
dart pub add pam_flutter
Migrating from 2.x
Version 3 contains breaking identity and push-helper API changes. Follow the 2.x to 3.0 migration guide before upgrading an existing application.
Configuration
Create lib/pam_config.dart in your project and add the following code:
import 'package:pam_flutter/pam.dart';
class PamConfigProvider {
static PamConfig getConfig() {
// Replace the following values with your configuration
const endpoint = "https://[YOUR-DOMAIN]pams.ai";
const publicDBAlias = "[PAM-PUBLIC-DB-FROM-PAM-CMS]";
const loginDBAlias = "[PAM-LOGIN-DB-FROM-PAM-CMS]";
const trackingConsentMessageID = "[CONSENT-MESSAGE-ID-FROM-PAM-CMS]";
const debugMode = true; // Enable logs
return PamConfig(
endpoint,
publicDBAlias,
loginDBAlias,
trackingConsentMessageID,
debugMode,
identityMatcher: PamIdentityMatcher.primary(
PamPrimaryIdentityKey.customer,
),
);
}
}
Initialization
In your main.dart file, add the following code to the main() function to initialize the PAM library:
import 'package:flutter/material.dart';
import 'package:pam_flutter/pam.dart';
import 'pam_config.dart';
void main() async {
// Initialize PAM
var pamConfig = PamConfigProvider.getConfig();
await Pam.initialize(pamConfig);
runApp(const MyApp());
}
Core Features
Consent Management
To handle user consent in compliance with PDPA or GDPR laws, you can use the following example code in your application:
Tracking Consent
Tracking Consent allows users to grant permission for tracking events or user behavior. Use the following example code to implement tracking consent in your application:
import 'package:pam_flutter/pam.dart';
Future<SubmitConsentResult?> allowTrackingConsent() async {
var trackingConsentMessageID = "[YOUR-TRACKING-CONSENT-MSG-ID]";
var trackingConsent = await Pam.loadConsentMessage(trackingConsentMessageID);
trackingConsent?.allowAll();
if (trackingConsent != null) {
var result = await Pam.submitConsent(trackingConsent);
return result;
}
return null;
}
Reminder: Replace
YOUR-TRACKING-CONSENT-MSG-IDwith your actual tracking consent message ID from your PAM CMS.
Contacting Consent
Contacting Consent allows users to grant permission for communication for marketing purposes. Use the following example code to implement contacting consent in your application:
import 'package:pam_flutter/pam.dart';
Future<SubmitConsentResult?> allowContactingConsent() async {
var contactingConsentMessageID = "[YOUR-CONTACTING-CONSENT-MSG-ID]";
var contactingConsent =
await Pam.loadConsentMessage(contactingConsentMessageID);
contactingConsent?.allowAll();
if (contactingConsent != null) {
var result = await Pam.submitConsent(contactingConsent);
return result;
}
return null;
}
Reminder: Replace
YOUR-CONTACTING-CONSENT-MSG-IDwith your actual contacting consent message ID from your PAM CMS.
Push Notifications
Saving Push Notification Token
If your application uses push notifications, it's essential to save the device's push notification token to PAM. Follow these steps to ensure proper integration:
import 'package:pam_flutter/pam.dart';
// Obtain the push notification token from your messaging service
var deviceToken = "[PUSH-NOTIFICATION-TOKEN]";
// Save the push notification token to PAM
Pam.setPushNotificationToken(deviceToken);
Note: Replace
PUSH-NOTIFICATION-TOKENwith the actual push notification token obtained from your messaging service.
By saving the push notification token to PAM, you enable the system to deliver personalized notifications to users.
Handling Push Notifications
The PAM SDK does not depend on Firebase. If your application uses Firebase Messaging, pass only its data map to the PAM helpers:
import 'package:flutter/material.dart'; // Required for Navigator example
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:pam_flutter/pam.dart';
// In your Firebase messaging handler
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
// Check if the push notification is from PAM
if (Pam.isPushNotiFromPam(message.data)) {
// Note: Forcing navigation from foreground notifications is generally not recommended
// as it can disrupt the user's current activity. This example only logs and tracks.
// Convert to PAM push message
var pamMessage = Pam.convertToPamPushMessage(message.data);
if (pamMessage != null) {
// Handle the PAM push message
// For example, show a custom notification or perform actions
print('Received PAM push: ${pamMessage.data}');
// Optionally track that the message was read
pamMessage.trackRead();
}
} else {
// Handle non-PAM notifications
}
});
The Firebase types remain entirely in the application. PAM receives only
Map<String, dynamic> through message.data.
Handling Notification Taps
When a user taps a notification in the system notification center, the app's behavior depends on its current state.
1. App Launched from Terminated State (Cold Start)
If the app is completely closed, use getInitialMessage() to check if it was opened via a notification.
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:pam_flutter/pam.dart';
void setupInteractedMessage() async {
// Get any messages which caused the application to open from a terminated state.
RemoteMessage? initialMessage =
await FirebaseMessaging.instance.getInitialMessage();
if (initialMessage != null) {
_handleMessage(initialMessage);
}
// Also handle messages when the app is in the background but still running.
FirebaseMessaging.onMessageOpenedApp.listen(_handleMessage);
}
void _handleMessage(RemoteMessage message) {
if (Pam.isPushNotiFromPam(message.data)) {
var pamMessage = Pam.convertToPamPushMessage(message.data);
if (pamMessage != null) {
// Track that the user clicked and opened the app from this notification
pamMessage.trackRead();
// Navigate to the specific screen based on pamMessage data
// Navigator.pushNamed(context, '/detail', arguments: pamMessage);
}
}
}
2. App Resumed from Background State
If the app is running in the background, FirebaseMessaging.onMessageOpenedApp will trigger a stream event when the notification is tapped.
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:pam_flutter/pam.dart';
@override
void initState() {
super.initState();
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
if (Pam.isPushNotiFromPam(message.data)) {
var pamMessage = Pam.convertToPamPushMessage(message.data);
pamMessage?.trackRead();
// Example: Navigate to a specific page
// print("User tapped notification: ${pamMessage?.title}");
}
});
}
Loading Notification History and Tracking Read Status
To load the notification history sent from the PAM system, follow these steps. Please note that the inbox data retrieved is only the raw data, and you'll need to implement the UI to display it.
Load Inbox Data by Email
import 'package:pam_flutter/pam.dart';
// Load inbox data using the user's email
var userInbox = await Pam.loadPushNotificationsFromEmail("[USER-EMAIL]");
Load Inbox Data by Mobile Number
import 'package:pam_flutter/pam.dart';
// Load inbox data using the user's mobile number
var userInbox = await Pam.loadPushNotificationsFromMobile("[USER-MOBILE]");
Reminder: Replace
USER-EMAILorUSER-MOBILEwith the actual user's email or mobile number to retrieve their respective inbox.
The userInbox variable will contain an array of messages sent from the PAM system.
Track Read Status
import 'package:pam_flutter/pam.dart';
// Track read status for the first message in the inbox
userInbox?[0].trackRead();
By calling trackRead(), you can keep track of whether the user has opened or read the specific message.
Note: Implement the UI to display the inbox messages as needed.
User Tracking
Signaling User Login
When a user logs into your application, it's important to signal this event to PAM. This helps in associating user activities with their identity for better analytics. Follow these steps to signal user login:
import 'package:pam_flutter/pam.dart';
// Login key, for example, if your PAM's database uses email to identify users, you can use the user's email
var userIdentity = "[YOUR-LOGIN-IDENTITY]";
// Signal user login to PAM
Pam.userLogin(userIdentity);
Note: Replace
YOUR-LOGIN-IDENTITYwith the actual login identity of the user, such as their email or any unique identifier.
By signaling user login to PAM, you ensure that user activities are tracked and associated with their identity for comprehensive analytics.
Signaling User Logout
When a user logs out of your application, it's important to signal this event to PAM. This helps in managing user sessions and ensures accurate analytics. Follow these steps to signal user logout:
import 'package:pam_flutter/pam.dart';
// Signal user logout to PAM
Pam.userLogout();
By signaling user logout to PAM, you contribute to the accurate tracking of user activities and ensure that the analytics reflect the user's session status.
Pam.userLogout() removes the notification token from the logged-in contact
and does not attach the saved token to the anonymous contact. A token previously
provided by the application remains available for the next explicit
Pam.userLogin() transition; the SDK never obtains a token by itself.
Optional Identity Cross-Check
You can provide the application's current authentication state as an optional
safety check. Pam.userLogin() and Pam.userLogout() remain the explicit
triggers that change the SDK session.
final config = PamConfig(
endpoint,
publicDBAlias,
loginDBAlias,
trackingConsentMessageID,
enableLog,
identityMatcher: PamIdentityMatcher.primary(
PamPrimaryIdentityKey.sms,
),
identityProvider: () {
final user = authRepository.currentUser;
if (user == null) {
return const PamUserState.anonymous();
}
return PamUserState.identified(user.mobile);
},
onIdentityMismatch: (mismatch) {
final identity = mismatch.newIdentity;
if (identity == null) {
Pam.userLogout();
} else {
Pam.userLogin(identity.value);
}
},
);
The identity matcher is fixed for the lifetime of the SDK configuration. Use one of the CDP primary keys:
identityMatcher: PamIdentityMatcher.primary(
PamPrimaryIdentityKey.customer,
)
identityMatcher: PamIdentityMatcher.primary(
PamPrimaryIdentityKey.email,
)
identityMatcher: PamIdentityMatcher.primary(
PamPrimaryIdentityKey.sms,
)
If your CDP is configured with a secondary matching key, configure it once:
identityMatcher: PamIdentityMatcher.secondary("line")
Pam.userLogin() accepts only the identity value. The SDK constructs the
correct primary or secondary identity payload from identityMatcher.
The identity provider must synchronously read cached application state. Return
PamUserState.unknown() while authentication state is still loading. When the
app and SDK identities do not match, the current tracking event is dropped and
the global mismatch handler is notified once for that mismatch state.
Migrating Identity Configuration from 2.x
Version 3 configures the CDP identity matcher once in PamConfig.
// 2.x
Pam.userLogin(
lineId,
LoginOptions(alternateKey: "line"),
);
// 3.x
final config = PamConfig(
endpoint,
publicDBAlias,
loginDBAlias,
trackingConsentMessageID,
enableLog,
identityMatcher: PamIdentityMatcher.secondary("line"),
);
Pam.userLogin(lineId);
LoginOptions and per-call alternate-key selection were removed in version
3.0.0.
Tracking User Events
To track user events and activities, follow these steps:
Send Event with Payload
Use the following example code to send an event with a payload:
import 'package:pam_flutter/pam.dart';
void trackEvent() {
var eventName = "purchase";
var payload = {
"product_name": "pizza",
"size": "big",
"price": 300
};
Pam.track(eventName, payload: payload);
}
In this example, the eventName is set to "purchase," and the payload contains additional data related to the purchase event. You can customize the event name and payload based on the specific user activity you want to track.
By calling Pam.track(), you send the event data to PAM for analytics.
App Attention
App Attention is a comprehensive solution for integrating custom promotional popups into your mobile applications. This feature allows you to display banners, videos, and promotional messages directly within your app, helping to increase user engagement, highlight special offers, and drive traffic to specific URLs.
Designed for flexibility, App Attention provides developers with the ability to customize popup behavior, such as displaying full-screen media or small promotional messages. It supports handling user interactions, such as opening external links or triggering custom app events, ensuring seamless integration into your app's user experience.
How to Use
To integrate App Attention into your Flutter application, follow the steps below:
Display App Attention
Call the Pam.appAttention method to display the App Attention popup. This function can be used to fetch and show banners, videos, or promotional messages based on the pageName you specify.
Here’s an example of how to implement it in your app:
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
// Display App Attention if it exists
Pam.appAttention(
context,
pageName: "home", // Specify the page name for dynamic banners
onBannerClick: (bannerData) {
// Handle banner click
print("CLICK LEARN MORE.");
print(bannerData.toString());
// Return true if you want to stop the default behavior (e.g., opening the URL)
// Return false to allow the default behavior (open URL in browser)
return false;
},
);
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
Explanation
context: The BuildContext of the current widget tree.pageName: A string that specifies the current page name, allowing dynamic banners tailored to specific app pages.onBannerClick: A callback function triggered when the user interacts with the banner. It receivesbannerDataas a parameter, which contains details about the clicked banner. The callback can:- Return
trueto stop the default behavior (e.g., open a custom page in your app). - Return
falseto proceed with the default behavior (e.g., open the provided URL in the browser).
- Return
API Reference
For detailed API documentation, please refer to the source code and inline comments in the lib/ directory.
Examples
Check the example/ directory for a complete sample application demonstrating the usage of pam_flutter.
Troubleshooting
- Configuration Issues: Ensure all values in
pam_config.dartare correct, including endpoint, database aliases, and consent message IDs. - Debugging: Set
debugMode = trueto enable logs in the console for debugging. - Network and Permissions: Check internet connection and required permissions (e.g., for push notifications on iOS/Android).
- PAM CMS Verification: Verify that keys, IDs, and settings in PAM CMS match your config.
- Error Checking: Look for error messages in the console or logs for more details.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Libraries
- api/consent_api
- api/crm_api
- api/push_notification_api
- api/tracker_api
- http/http_client
- pam
- pam_flutter
- pam_flutter_method_channel
- pam_flutter_platform_interface
- preferences
- response/allow_consent
- response/consent_message
- response/customer_consent_status
- response/pam_push_message
- response/pam_response
- response/user_consent_permissions
- tracker_queue_manager