This library is the official Flutter SDK of Related Digital.
pubspec.yaml
file:dependencies:
relateddigital_flutter: ^0.5.9
Run flutter pub get
Import the package:
import 'package:relateddigital_flutter/relateddigital_flutter.dart';
android/build.gradle
file's both repositories
sections.maven {url 'https://jitpack.io'}
dependencies
section in project/build.gradle
classpath 'com.google.gms:google-services:4.3.10'
app/build.gradle
apply plugin: 'com.google.gms.google-services'
Change your minSdkVersion to 21.
Change your targetSdkVersion and compileSdkVersion to 32.
Add the following services to your AndroidManifest.xml
, within the <application></application>
tags.
<service
android:name="euromsg.com.euromobileandroid.service.EuroFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
- Add `google-services.json` file to your application’s `app` directory.
- If your app supports `HMS` add `agconnect-services.json` file to your application’s `app` directory.
### iOS
- Change the ios platform version to 11.0 or higher in `Podfile`
```ruby
platform :ios, '11.0'
In your project directory, open the file ios/Runner.xcworkspace
with Xcode.
Enable Push Notifications
and Background Modes->Remote Notifications
capabilities.
In Xcode, add a new Notification Service Extension target and name it NotificationService. NotificationServiceExtension allows your iOS application to receive rich notifications with images, videos, and badges. It's also required for Related Digital's analytics features and to store and access notification payloads of the last 30 days.
In your podfile, add below section and then run pod install
.
target 'NotificationService' do
use_frameworks!
pod 'Euromsg'
end
post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) target.build_configurations.each do |config| config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'No' end end end
- Set **NotificationService** target's deployment target to iOS 11.
- Replace **NotificationService.swift** file content with the code below.
```swift
import UserNotifications
import Euromsg
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
Euromsg.configure(appAlias: "ios-app-alias", enableLog: true)
Euromsg.didReceive(bestAttemptContent, withContentHandler: contentHandler)
}
override func serviceExtensionTimeWillExpire() {
guard let contentHandler = self.contentHandler else {
return;
}
guard let bestAttemptContent = self.bestAttemptContent else {
return;
}
contentHandler(bestAttemptContent)
}
}
Enable App Groups
Capability for your targets. App Groups allow your app to execute code when a notification is recieved, even if your app is not active. This is required for Related Digital's analytics features and to store and access notification payloads of the last 30 days.
Signing & Capabilities > All
. + Capability
if you do not have App Groups in your app yet.+
button.App Groups
container to be group.BUNDLE_ID.relateddigital
where BUNDLE_ID
is the same as set in Bundle Identifier
.Signing & Capabilities > All
+ Capability
if you do not have App Groups in your app yet.Signing & Capabilities
> All`.+ Capability
.+
button.App Groups
container to be group.BUNDLE_ID.relateddigital
where BUNDLE_ID
is the same as your Main App Target Bundle Identifier
. Do Not Include NotificationServiceExtension
and NotificationContentExtension
.<key>NSUserTrackingUsageDescription</key>
<string>We use advertising identifier!</string>
Import the library
import 'package:relateddigital_flutter/relateddigital_flutter.dart';
import 'package:relateddigital_flutter/request_models.dart';
import 'package:relateddigital_flutter/response_models.dart';
Initialize the library
final RelateddigitalFlutter relatedDigitalPlugin = RelateddigitalFlutter();
@override
void initState() {
super.initState();
initLib();
}
Future<void> initLib() async {
var initRequest = RDInitRequestModel(
appAlias: Platform.isIOS ? 'ios-app-alias' : 'android-app-alias',
huaweiAppAlias: 'huawei-app-alias', // pass empty String if your app does not support HMS
androidPushIntent: 'com.test.MainActivity', // Android only
organizationId: 'ORG_ID',
siteId: 'SITE_ID',
dataSource: 'DATA_SOURCE',
maxGeofenceCount: 20, // iOS only
geofenceEnabled: true,
inAppNotificationsEnabled: true,
logEnabled: true,
isIDFAEnabled: true, // iOS only
);
await relatedDigitalPlugin.init(initRequest, _readNotificationCallback);
}
void _readNotificationCallback(dynamic result) {
print(result);
}
Add the lines below to request push notification permission and retrieve token.
isProvisional
parameter of requestPermission
method to true
.String token = '-';
void _getTokenCallback(RDTokenResponseModel result) {
if(result != null && result.deviceToken != null && result.deviceToken.isNotEmpty) {
setState(() {
token = result.deviceToken;
});
}
else {
setState(() {
token = 'Token not retrieved';
});
}
}
Future<void> requestPermission() async {
await relatedDigitalPlugin.requestPermission(_getTokenCallback, isProvisional: true);
}
To be able to receive push notifications with carousel, follow the steps below.
pod install
.
target 'NotificationContent' do
use_frameworks!
pod 'Euromsg'
end
import UIKit
import UserNotifications
import UserNotificationsUI
import Euromsg
@objc(EMNotificationViewController) class EMNotificationViewController: UIViewController, UNNotificationContentExtension {
let carouselView = EMNotificationCarousel.initView()
var completion: ((_ url: URL?, _ bestAttemptContent: UNMutableNotificationContent?) -> Void)?
var notificationRequestIdentifier = ""
func didReceive(_ notification: UNNotification) {
notificationRequestIdentifier = notification.request.identifier
Euromsg.configure(appAlias: "relateddigital-flutter-example-ios", launchOptions: nil, enableLog: true)
carouselView.didReceive(notification)
}
func didReceive(_ response: UNNotificationResponse, completionHandler completion: @escaping (UNNotificationContentExtensionResponseOption) -> Void) {
carouselView.didReceive(response, completionHandler: completion)
}
override func loadView() {
completion = { [weak self] url, bestAttemptContent in
if let identifier = self?.notificationRequestIdentifier {
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [identifier])
UNUserNotificationCenter.current().getDeliveredNotifications(completionHandler: { notifications in
bestAttemptContent?.badge = NSNumber(value: notifications.count)
})
}
if let url = url {
if #available(iOSApplicationExtension 12.0, *) {
self?.extensionContext?.dismissNotificationContentExtension()
}
self?.extensionContext?.open(url)
} else {
if #available(iOSApplicationExtension 12.0, *) {
self?.extensionContext?.performNotificationDefaultAction()
}
}
}
carouselView.completion = completion
carouselView.delegate = self
self.view = carouselView
}
}
/* Add if you want to track which carousel element has been selected / extension EMNotificationViewController: CarouselDelegate {
func selectedItem(_ element: EMMessage.Element) {
// Add your work...
print("Selected element is => \(element)")
}
}
- In your **NotificationContent/Info.plist** add below section
```xml
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>UNNotificationExtensionCategory</key>
<string>carousel</string>
<key>UNNotificationExtensionDefaultContentHidden</key>
<false />
<key>UNNotificationExtensionInitialContentSizeRatio</key>
<real>1</real>
<key>UNNotificationExtensionUserInteractionEnabled</key>
<true />
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.usernotifications.content-extension</string>
<key>NSExtensionPrincipalClass</key>
<string>NotificationContent.EMNotificationViewController</string>
</dict>
You can only call setNotificationPermission
method to enable or disable push notifications for the application.
relatedDigitalPlugin.setNotificationPermission(true);
You can access payload list of last 30 days if you have completed iOS NotificationServiceExtension
and App Groups
setup. Using getPushMessages
method you can access these payloads
PayloadListResponse payloadListResponse = await relatedDigitalPlugin.getPushMessages();
Related Digital uses events to collect data from mobile applications. The developer needs to implement the methods provided by SDK. customEvent
is a generic method to track user events. customEvent
takes 2 parameters: pageName and properties.
Some of the most common events:
String userId = 'userId';
// optional
Map<String, String> properties = {
'OM.b_sgnp':'1'
};
await relatedDigitalPlugin.signUp(userId, properties: properties);
String userId = 'userId';
// optional
Map<String, String> properties = {
'OM.b_login':'1'
};
await relatedDigitalPlugin.login(userId, properties: properties);
Use the following implementation of customEvent
method to record the page name the visitor is currently viewing. You may add extra parameters to properties Map or you may leave it empty.
String pageName = 'Page Name';
Map<String, String> parameters = {};
await relatedDigitalPlugin.customEvent(pageName, parameters);
Use the following implementation of customEvent
when the user displays a product in the mobile app.
String pageName = 'Product View';
Map<String, String> parameters = {
'OM.pv' : productCode,
'OM.pn' : productName,
'OM.ppr' : productPrice,
'OM.pv.1' : productBrand,
'OM.inv': inventory // Number of items in stock
};
relatedDigitalPlugin.customEvent(pageName, parameters);
Use the following implementation of customEvent
when the user adds items to the cart or removes.
String pageName = 'Cart';
Map<String, String> parameters = {
'OM.pbid' : basketID,
'OM.pb' : 'Product1 Code;Product2 Code',
'OM.pu' : 'Product1 Quantity;Product2 Quantity',
'OM.ppr' : 'Product1 Price*Product1 Quantity;Product2 Price*Product2 Quantity'
};
relatedDigitalPlugin.customEvent(pageName, parameters);
Use the following implementation of customEvent
when the user buys one or more items.
String pageName = 'Purchase';
Map<String, String> parameters = {
'OM.tid' : transactionID,
'OM.pp' : 'Product1 Code;Product2 Code',
'OM.pu' : 'Product1 Quantity;Product2 Quantity',
'OM.ppr' : 'Product1 Price*Product1 Quantity;Product2 Price*Product2 Quantity',
'OM.exVisitorID' : userId
};
relatedDigitalPlugin.customEvent(pageName, parameters);
When the user views a category list page, use the following implementation of customEvent
.
String pageName = 'Category View';
Map<String, String> parameters = {
'OM.clist': '12345',
};
relatedDigitalPlugin.customEvent(pageName, parameters);
If the mobile app has a search functionality available, use the following implementation of customEvent
.
String pageName = 'In App Search';
Map<String, String> parameters = {
'OM.OSS': searchKeyword,
'OM.OSSR': searchResult.length,
};
relatedDigitalPlugin.customEvent(pageName, parameters);
You can monitor banner click data using the following implementation of customEvent
.
String pageName = 'Banner Click';
Map<String, String> parameters = {
'OM.OSB': 'Banner Name/Banner Code',
};
relatedDigitalPlugin.customEvent(pageName, parameters);;
When the user adds a product to their favorites, use the following implementation of customEvent
.
String pageName = 'Add To Favorites';
Map<String, String> parameters = {
'OM.pf' : productCode,
'OM.pfu' : '1',
};
relatedDigitalPlugin.customEvent(pageName, parameters);
When the user removes a product from their favorites, use the following implementation of customEvent
.
String pageName = 'Add To Favorites';
Map<String, String> parameters = {
'OM.pf' : productCode,
'OM.pfu' : '-1',
};
relatedDigitalPlugin.customEvent(pageName, parameters);
To remove all the user related data from local storage, use the method below.
await relatedDigitalPlugin.logout();
In-app messages are notifications to your users when they are directly active in your mobile app. To enable In-App Messaging feature you need to set the value of inAppNotificationsEnabled
parameter to true
when calling init
to initialize the SDK.
The existence of a relevant in-app message for an event controlled by after each customEvent
call. You can create and customize your in-app messages on https://intelligence.relateddigital.com/#Target/TargetingAction/TAList page of RMC administration panel.
There are 9 types of in-app messages:
Pop-up - Image, Header, Text & Button | Mini-icon&text | Full Screen-image |
---|---|---|
Full Screen-image&button | Pop-up - Image, Header, Text & Button | Pop-up-Survey |
Pop-up - NPS with Text & Button | Native Alert & Actionsheet | NPS with numbers |
Follow the step below to add a countdown to your stories.
iOS
Add below lines to your project target's Build Phases
->Copy Bundle Resources
section. Select Create folder references
when prompted.
Pods/VisilabsIOS/Sources/TargetingAction/Story/Views/timerView/timerView.xib
Android
No special installation required
Usage
To add story view to your app, import RDStoryView
and use as below:
import 'package:relateddigital_flutter/rd_story_view.dart';
...
...
RDStoryView(
actionId: '975', // Story actionid created from panel
relatedDigitalPlugin: widget.relatedDigitalPlugin,
onItemClick: (Map<String, String> result) {
print(result);
}
)
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<service android:name="com.visilabs.android.gps.geofence.GeofenceTransitionsIntentService"
android:enabled="true"
android:permission="android.permission.BIND_JOB_SERVICE" />
<receiver android:name="com.visilabs.android.gps.geofence.GeofenceBroadcastReceiver" android:enabled="true" android:exported="false"/>
### Recommendation
Use **getRecommendations** method as below to retrieve product recommendations. This method takes mandatory **zoneId** and **productCode** parameters with optional **filters** parameter.
```dart
import 'package:relateddigital_flutter/recommendation_filter.dart';
Future<void> getRecommendations() async {
String zoneId = '6';
String productCode = '';
// optional
Map<String, Object> filter = {
RDRecommendationFilter.attribute: RDRecommendationFilterAttribute.PRODUCTNAME,
RDRecommendationFilter.filterType: RDRecommendationFilterType.like,
RDRecommendationFilter.value: null
};
List filters = [
filter
];
// optional
Map<String, String> properties = {
'OM.cat':'84'
};
List result = await widget.relatedDigitalPlugin.getRecommendations(zoneId, productCode);
// List result = await relatedDigitalPlugin.getRecommendations(zoneId, productCode, properties:properties, filters: filters);
print(result.toString());
}
{
"recommendations": [
{
"attr1": "420494",
"attr10": "",
"attr2": "",
"attr3": "",
"attr4": "",
"attr5": "",
"attr6": "",
"attr7": "",
"attr8": "",
"attr9": "",
"brand": "Related Digital",
"code": "1159092",
"comment": 0,
"cur": "TRY",
"dcur": "TRY",
"dest_url": "https://relateddigital.com/example-product?OM.zn=You%20Viewed-w60&OM.zpc=1159092",
"discount": 0,
"dprice": 5.25,
"freeshipping": false,
"img": "https://cdn.relateddigital.com/example.png",
"price": 5.25,
"qs": "OM.zn=You Viewed-w60&OM.zpc=1159092",
"rating": 0,
"samedayshipping": false,
"title": "Titiz TP-115 Yeşil Ayakkabı"
}
],
"title": "Display You Viewed"
}
After clicking on each product, run the following function with the qs
parameter. This parameter is included in the response returned from the widget.relatedDigitalPlugin.getRecommendations
function.
widget.relatedDigitalPlugin.trackRecommendationClick(qs);
(Android Only) Use sendTheListOfAppsInstalled method to track installed apps on android.
await widget.relatedDigitalPlugin.sendTheListOfAppsInstalled();
Add one of the sections below to your AndroidManifest.xml in order to use this feature.
Option 1
<manifest package="com.example.myApp">
<queries>
<package android:name="com.example.app1" />
<package android:name="com.example.app2" />
</queries>
</manifest>
Option 2
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />