If Proguard is enabled in the app, please add the following rule in the build.gradle file to ensure smooth working of CustomerGlu SDK.
buildTypes { release {// TODO: Add your own signing config for the release build.// Signing with the debug keys for now, so `flutter run --release` works. signingConfig signingConfigs.debug proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),'proguard-rules.pro' }}
Create a Proguard rules file if not present and add the following rule in Proguard Rules file:
-keep classcom.customerglu.sdk.Modal.*{*;}
CustomerGlu iOS SDK supports IOS 11.0+ and requires Xcode 12 or above to build.
CustomerGlu Android SDK supports API 21 and above. Please ensure the minSDKVersion in the app's build.gradle file reflects the same.
Note:
If Proguard is enabled in the app, please add the following rule in Proguard Rules file to ensure smooth working of CustomerGlu SDK:
-keep classcom.customerglu.sdk.Modal.*{*;}
Permissions
Add the following permissions to the AndroidManifest.xml file
WriteKey - Mandatory (WriteKey/API Key is provided by CustomerGlu)
Add your WriteKey/API Key in meta-data of the AndroidManifest.xml file like this:
<meta-dataandroid:name="CUSTOMERGLU_WRITE_KEY"android:value="YOUR_WRITE_KEY" /> //Don't Change Name
WriteKey - Mandatory (WriteKey/API Key is provided
To initialize the SDK the initialization method must be called at every app launch before using any other method from the CG SDK. use it in index.js at entry point of the app
import { initCGSDK } from '@customerglu/react-native-customerglu';
initCGSDK("in");
WriteKey - Mandatory (WriteKey/API Key is provided
To initialize the SDK the initialization method must be called at every app launch before using any other method from the CG SDK. use it in index.js or App.js at entry point of the app
import { initCGSDK } from '@customerglu/react-native-customerglu';
initCGSDK("in");
Register User (Mandatory)
Registering a user of your platform with CustomerGlu is mandatory to be able to show any CG powered UIs and experiences to the user. Users need not be registered on your platform. You can check out the flow to handle non-logged/guest users here.
As the same registration method can also be used to update user attributes, it is recommended to use this method on every app launch, after signing in/up and reaching the app home page.
This method is now used to register the user with CG. Make sure to call it on every App launch. In SDK v3.0.0 or above we are not accepting CustomAttributes here in the registerDevice:
customerGlu.registerDevice(this, registerData,newDataListner() {//this method register your device with CG and load the campaigns @OverridepublicvoidonSuccess(Boolean success) {Toast.makeText(getApplicationContext(),"Registered",Toast.LENGTH_SHORT).show(); } @OverridepublicvoidonFail(String message) {Toast.makeText(getApplicationContext(),""+ message,Toast.LENGTH_SHORT).show(); } });
Note: The Register function is used to generate token only
Function Parameters:
Context: this/getApplicationContext()
userData: A HashMap that holds user information
Sample UserData object
Map<String,Object> userData =newHashMap<>();String user_id="testUser_1";String fcmToken="FCM_TOKEN_OF_DEVICE";userData.put("userId",user_id); // Mandatory:any identifier to uniquely identify a user of your platformuserdata.put("firebaseToken",fcmToken); // for enabling Firebase Notificationsuserdata.put("referredBy":"userAId"); // for referralsuserdata.put("referralCode":"userAReferralCode"); // for referrals
Note: You can check out the complete userData object payload here.
This method is now used to register the user with CG. Make sure to call it on every App launch. In SDK v3.0.0 or above we are not accepting CustomAttributes here in the registerDevice:
Note: The Register function is used to generate Token only
Function Parameters:
userData: A Dictionary that holds user information
Sample UserData object
var userData = [String:AnyHashable]() userData["userId"]="testUser_1"// Mandatory:any identifier to uniquely identify a user of your platform userData["userName"]="John Doe" userData["firebaseToken"]= CustomerGlu.getInstance.fcmToken // for enabling Firebase Notifications userData["apnsDeviceToken"]= CustomerGlu.getInstance.apnToken // for enabling APNS Notifications userdata["referredBy":"userAId"]; // for referrals userdata["referralCode":"userAReferralCode"]; // for referrals
Note: You can check out the complete userData object payload here
Use the given function to register a user with CustomerGlu :
Note: The Register function is also used to update the user attributes
Sample UserData object
var userData = {'userId': user_id, // Mandatory:any identifier to uniquely identify a user of your platform'firebaseToken':"FCM_TOKEN_OF_DEVICE", // for enabling Firebase Notifications'referredBy':"userAId", // for referrals'referralCode':"userAReferralCode", // for referrals'customAttributes':{ // any custom key-value pairs, which may be used for targeting can be sent as customAttributes// segments can be created by applying filters on these customAttributes// campaigns can be launched on specific segments"orderCount":5,"city":"Mumbai" }'profile':{"firstName":"JaneDoe" }}
Note: You can check out the complete userData object payload here.
Use the given function to register a user with CustomerGlu :
import { RegisterDevice } from '@customerglu/react-native-customerglu';var ok =awaitRegisterDevice(userData);if (ok ==true) {// Success }else { // fail}
Note: The Register function is also used to update the user attributes
Sample UserData object
let userData = {'userId': user_id, // Mandatory:any identifier to uniquely identify a user of your platform'firebaseToken':"FCM_TOKEN_OF_DEVICE", // for enabling Firebase Notifications'apnsDeviceToken':"APN_TOKEN_OF_DEVICE", // for enabling APN Notifications only for IOS'referredBy':"userAId", // for referrals'referralCode':"userAReferralCode", // for referrals'customAttributes':{ // any custom key-value pairs, which may be used for targeting can be sent as customAttributes// segments can be created by applying filters on these customAttributes// campaigns can be launched on specific segments"orderCount":5,"city":"Mumbai" }'profile':{"firstName":"JaneDoe" }}
Note: You can check out the complete userData object payload here.
UpdateUser Attributes
This method is used to update the user custom Attributes to add users to the respective segments
import {dataClear} from '@customerglu/react-native-customerglu';dataClear();
Handling Webview Events
CG Webviews send the following types of events to the app:
Deeplink redirection Events (OPEN_DEEPLINK): Redirect to a given screen on click of buttons from CustomerGlu UIs Example: Clicking on "Go To Cart" should redirect to the Cart Screen
Analytics Events (ANALYTICS): Send click analytics events on CG UI directly from the app to your servers/CDP Platform
Example: coupon code copied event
Note: Analytics events need to be explicitly enabled
Enable Analytics Events
If click analytics are to be captured directly via the app, you can enable the analytics events by using the given function:
For handling Deeplink or Analytics events triggered by the webview, you need to register a broadcast receiverand handle the logic for the respective event:
BroadcastReceiver mMessageReceiver;mMessageReceiver =newBroadcastReceiver() { @OverridepublicvoidonReceive(Context context,Intent intent) {try {if(intent.getAction().equalsIgnoreCase("CUSTOMERGLU_DEEPLINK_EVENT")) {String data =intent.getStringExtra("data");JSONObject jsonObject =newJSONObject(data);String message =jsonObject.getString("deepLink");// Add the logic to redirect to appropriate pageToast.makeText(getApplicationContext(), message,Toast.LENGTH_SHORT).show(); }/* If you want to listen analytics event */if(intent.getAction().equalsIgnoreCase("CUSTOMERGLU_ANALYTICS_EVENT")) {String data =intent.getStringExtra("data");JSONObject jsonObject =newJSONObject(data);Toast.makeText(getApplicationContext(),jsonObject.toString(),Toast.LENGTH_LONG).show();//This Event can be forwarded to your Servers/CDP tool } }catch (Exception e) {System.out.println(e); } }};registerReceiver(mMessageReceiver,new IntentFilter("CUSTOMERGLU_DEEPLINK_EVENT"));/* If you want to listen analytics event register the below reciever*/registerReceiver(mMessageReceiver,new IntentFilter("CUSTOMERGLU_ANALYTICS_EVENT"));
Note: Do not unregister the broadcast receiver in the app lifecycle.
Deeplink Events
For handling Deeplink events triggered by the webview, you need to add a notification observer:
NotificationCenter.default.addObserver( self, selector: #selector(self.catchDeeplinkNotification), name: Notification.Name("CUSTOMERGLU_DEEPLINK_EVENT"), object:nil)@objcprivatefunccatchDeeplinkNotification(notification: NSNotification) {//do stuff using the userInfo property of the notification objectiflet userInfo = notification.userInfo as? [String:Any] // or use if you know the type [AnyHashable : Any] {print(userInfo) } }
Analytics Events
For handling analytics events triggered by the webview, you need to a notification observer:
Nudge Configuration is an object that can be passed as an optional parameter to the openWallet, loadCampaignById and openNudge methods to configure the layout, height, and other related properties for the webview.
Relative Height - It accepts an integer value from 1 to 100 as Percentage(%) of device screen height. Default value: 70
Absolute Height - It accepts an integer value greater than 0. It follows native units like px (iOS) and dp (android) to adjust height. Default value: 0
Provide either relative or absolute dimensions for height. Priority is given to relative height in case of both being defined.
3. Layout - Set the layout of nudge. Possible values: [full-default, middle-popup, bottom-popup, bottom-slider] | Refer here to see al supported layouts. Default value : full-default
4. closeOnDeepLink - If set to true , the Webview will be dismissed automatically if the user is redirected to an app screen from a button in the UI. Default value: false
5. Opacity - For any of the layouts except for fullscreen, set the background opacity of the screen not covered by content. It can take values between 0 to 1, where 0 means fully transparent and 1 means fully opaque background. Default value: 0.5
Open Wallet
CustomerGlu offers a fully customisable wallet page which contains challenges, games, rewards and other user specific information as shown below:
Use the following function to open the wallet screen powered by CustomerGlu:
Note: If the value of campaignId/tag provided is empty/invalid, wallet will be opened by default. To handle this case in a custom manner, CG_INVALID_CAMPAIGN_ID event can be consumed
Verify CampaignId
You can verify the campaignId before opening the campaign using the below method
customerGlu.isCampaignValid("campaignId");
customerGlu.isCampaignValid("campaignId");
Above method returns the boolean value is the campaign valid or not.
Function Parameters
CampaignId/Tag : Unique Identifier assigned to a campaign, can be copied from the dashboard.
Entry Points
Entry Points are the various ways how users can discover and explore experiences like games, challenges, rewards, nudges, wallet, etc.
Thefollowing entry points are supported by CustomerGlu Mobile SDKs:
Banner
Floating Button/Launcher
Popup
Embed View
Banner Floating Button/Launcher
Popup
Enable Entry Points
Use the given function to enable Entry Points in the app (should be called on every app launch):
Banners need elements with unique ids to be pre-defined in the app screens. These components need to be added at all the places where banners need to show up- that is why it is important to add these elements generously, covering all possible use cases where a banner might be needed, as an app release will be required to edit them.
Note: These components will not take any screen space and will remain hidden in the background unless the banners configured are activated explicitly from the dashboard.
Add the following component, wherever a banner might be needed, in the Activity’s layout file (XML):
<com.customerglu.sdk.entrypoints.Bannerandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/someUniqueIdentifier"/> //same id should be configured on the dashboard
Banners can be set up in the following ways:
1. Storyboard / XIB
Drag and drop an empty UIView on the ViewController in which a banner might be needed, and adjust it to the correct position.
Under identity inspector add BannerView as the class name.
Under attribute inspector add a unique value for BannerId.
Height constraint can be added in the same view.
2. SwiftUI
If the app screens are developed using SwiftUI, add the following banner component, wherever a banner might be needed:
// Add code where a banner might be neededSpacer()VStack {AddBannerView()}.padding(.horizontal, 10)Spacer()//Struct for adding banner viewstructAddBannerView:UIViewRepresentable {funcupdateUIView(_uiView: BannerView, context: Context) { }funcmakeUIView(context: Context) -> BannerView {let view =BannerView(frame: CGRect(x:0, y:0, width: UIScreen.main.bounds.width-30, height:0), bannerId:"Add unique bannerId ID here") view.setContentHuggingPriority(.required, for: .horizontal) view.setContentHuggingPriority(.required, for: .vertical)return view }}
Add the following banner component, wherever a banner might be needed, in the flutter layout :
Note : The id or bannerId is mandatory and the exact same id needs to be set on the dashboard as the bannerId in the entry point configuration section. Please follow a semantic nomenclature like screenName_banner_1 for the ids for ease of configuration on the dashboard.
ℹ️ Banner Loaded Callback:
The banner will be hidden automatically in cases like the banner being disabled, user not eligible to see the banner (not in segment/campaign already completed).
If the status of banner components is also needed by the app, for use cases like changing the parent container size, depending on visibility of the banner, the following method can be used to check the banner availability:
Register a Broadcast Receiver, listen for the banner load event and handle the logic:
BroadcastReceiver mMessageReceiver; mMessageReceiver =newBroadcastReceiver() { @OverridepublicvoidonReceive(Context context,Intent intent) {// Extract data included in the Intenttry {if (intent.getAction().equalsIgnoreCase("CUSTOMERGLU_BANNER_LOADED")) {String data =intent.getStringExtra("data"); JSONObject jsonObject =newJSONObject(data);System.out.println(jsonObject.toString());// Output - {"banner1":2,"banner2":0}// Key is the bannerId and value is number of banners in the Banner Component } } catch (Exception e) {System.out.println(e); } } };registerReceiver(mMessageReceiver,new IntentFilter("CUSTOMERGLU_BANNER_LOADED"));
Add a Notification Observer, listen for the banner load event and handle the logic:
// Add Observer to listen Notification with name CUSTOMERGLU_BANNER_LOADEDNotificationCenter.default.addObserver( self, selector: #selector(self.getBannersCount), name: Notification.Name("CUSTOMERGLU_BANNER_LOADED"), object:nil)// Method to listen notification with name CUSTOMERGLU_BANNER_LOADED@objcprivatefuncgetBannersCount(notification: NSNotification) {iflet userInfo = notification.userInfo as? [String:Any] {// Output - ["banner1":2,"banner2":0]// Key is the bannerId and value is number of banners in the Banner Componentprint(userInfo) } }
Create a MethodChannel, listen for the banner load event and handle the logic:
Embed views can be used to embed CustomerGlu campaigns and screens directly in your native screens. Embed view works similar to Banners and needs elements with unique ids to be pre-defined in the app screens. These components need to be added at all the places where Embed view need to show up- that is why it is important to add these elements generously, covering all possible use cases where a Embed view might be needed, as an app release will be required to edit them.
Note: These components will not take any screen space and will remain hidden in the background unless the embed views configured are activated explicitly from the dashboard.
Add the following component, wherever a banner might be needed, in the Activity’s layout file (XML):
<com.customerglu.sdk.entrypoints.CGEmbedViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/someUniqueIdentifier"/> //same id should be configured on the dashboard
Banners can be set up in the following ways:
1. Storyboard / XIB
Drag and drop an empty UIView on the ViewController in which a banner might be needed, and adjust it to the correct position.
Under identity inspector add CGEmbedView as the class name.
Under attribute inspector add a unique value for embedId.
Height constraint can be added in the same view.
2. SwiftUI
If the app screens are developed using SwiftUI, add the following banner component, wherever a banner might be needed:
// Add code where a banner might be neededSpacer()VStack {CGEmbedView(frame: CGRect(x:0, y:0, width: UIScreen.main.bounds.width, height:0), embedId:"embedded1")}.padding(.horizontal, 10)Spacer()//Struct for adding embed viewstructEmbedViewAdd:UIViewRepresentable {funcupdateUIView(_uiView: CGEmbedView, context: Context) { }funcmakeUIView(context: Context) -> CGEmbedView {let view =CGEmbedView(frame: CGRect(x:0, y:0, width: UIScreen.main.bounds.width, height:0), embedId:"embedded1") view.setContentHuggingPriority(.required, for: .horizontal)// << here !! view.setContentHuggingPriority(.required, for: .vertical)// the same for compression if neededreturn view }}
Add the following embed component, wherever a embed view might be needed, in the flutter layout :
Note : The id or bannerId is mandatory and the exact same id needs to be set on the dashboard as the bannerId in the entry point configuration section. Please follow a semantic nomenclature like screenName_banner_1 for the ids for ease of configuration on the dashboard.
Setting up Floating Buttons and Popups and PIP
As Floating Buttons and Popups are overlays, they need no special components to be predefined like Banners. They only need to be added on all screens/activities of the app and each screen should be assigned a name/identifier which can then be used to configure these entrypoints via the dashboard.
The given function should be used on every Activity'sonResume Method to support adding the floating button/popup entry points on the activity via the dashboard:
The given function should be used on each ViewController's viewWillAppear() method to support adding the floating button/popup entry points via the dashboard:
The given function should be used in MainActivity , inside the onResume method to support adding the floating button/popup entry points on the activity via the dashboard:
The given function should be used on every Activity's useFocusEffect() Method to support adding the floating button/popup entry points on the activity via the dashboard:
The push and in-app nudges sent via CustomerGlu need to be handled by the app.
Add the displayCustomerGluNotification method in the Firebase onMessageRecieved callback to handle nudges, as shown below:
@RequiresApi(api =Build.VERSION_CODES.M)@OverridepublicvoidonMessageReceived(@NonNullRemoteMessage remoteMessage) { super.onMessageReceived(remoteMessage);JSONObject data =null;JSONObject json =newJSONObject(remoteMessage.getData());customerGlu.displayCustomerGluNotification(this,json,R.drawable.icon,0.5,true); }
Function Parameters:
context : this/getApplicationContext()
json : The json object of the remote message.
icon : The App Icon to be displayed for the push notifications.
opacity: For any of the layouts except for fullscreen, set the background opacity of the screen not covered by content. Can take values between 0 to 1, where 0 means fully transparent and 1 means fully opaque background. (Default value is 0.5)
autoclosewebview : If set to true , the webview will be dismissed automatically if the user is redirected to an app screen from a button in the UI
Note: App icon should be in PNG format with size less than 100KB.
Add it in the PushNotification library onNotification callback, as shown below:
import PushNotification from"react-native-push-notification";PushNotification.configure({// (required) Called when a remote is received or opened, or local notification is openedonNotification:function (notification) {console.log("NOTIFICATION----:", notification);if (notification.foreground) {if (notification.data.glu_message_type) {//ios notification open from forgroundDisplayCGNotification(notification.data,true) } else {DisplayCGNotification(notification.data.data,true) } } else {//ios notification open from Background if(Platform.OS==='android'){DisplayCGBackgroundNotification(notification.data,true) }else{DisplayCGNotification(notification.data,true) } } },});
For Android -
Add your Notification icon in meta-data of the AndroidManifest.xml file like this:
Update the pod file as shown below and and install it again:
//Reference URLs//https://rnfirebase.io/install-ios//https://rnfirebase.io/messaging/usage/installation/ios//Add Following linespod 'RNFBApp', :path => '../node_modules/@react-native-firebase/app'pod 'RNFBMessaging', :path => '../node_modules/@react-native-firebase/messaging'use_frameworks!:linkage =>:staticpod 'Firebase/Messaging'$RNFirebaseAsStaticFramework =true// Remove the following line if it existsflipper_configuration => FlipperConfiguration.enabled
Configure Notification Type
Set the sender of the nudge (Firebase/APNS)
customerGlu.isFcmApn(fcmApn:"fcm")//or "apn"
Function Parameter
fcmApn: It accepts a string value out of "fcm" or "apn" depending on the notification service being used by the app.
Set FCM/APNS Token
Add following code in didFinishLaunchingWithOptions()
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{NSLog(@"cgUserNotificationCenter");completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge);}- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{ [RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];}// Required for the notification event. You must call the completion handler after handling the remote notification.- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfofetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{ [RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];}// Required for the registrationError event.- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{ [RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];}// Required for localNotification event- (void)userNotificationCenter:(UNUserNotificationCenter *)centerdidReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler{ [RNCPushNotificationIOS didReceiveNotificationResponse:response];}
Supported Layouts
The following layouts are supported by CustomerGlu Mobile SDKs for various functionalities like opening wallet, campaigns, nudges, etc.
Fullscreen Middle Popup
Bottom Popup Bottom Slider (Draggable)
Handling Dark Mode/Light Configuration
The dark mode settings in the CustomerGlu SDK (only v2.2.0+) can be configured using the following Methods
Handling Configuration Changes
For handling configuration changes like dark/light mode, orientation, etc., Flutter and React-Native apps need to implement this method in android MainActivity
CustomerGlu provides Universal Deeplinks to access particular campaigns and wallet page. To support these deeplinks in the app and redirection to playstore/appstore in case the app is not installed, please follow the given steps:
Step 1
Put the intent-filter inside the activity tag in Android Manifest as below to handle navigation to that activity
User events which may lead to rewards via a campaign need to be sent to CG. These events can be sent directly via the SDKs using the sendEventData method:
Note: Check out all available options to send events here