Loyalty & Retention
The Loyalty Icon can be used by the user to access his/her Loyalty Profile Card. The following options can be used to handle the Loyalty Icon and User Profile in your game.
Showing/hiding the wappier Icon
You can add the Loyalty Icon programmatically or with .xml in your layout. When the user taps the icon, his Loyalty Profile card is shown.
Find the method of every framework in the tabs below:
- Android(Java)
- iOS(obj-C)
- Unity(C#)
- C++
//Programmatically
WappierButton mCustomButton= new WappierButton();
<!--Xml-->
<wappier.sdk.wappier.com.loyalty.ui.WappierButton
android:id="@+id/wappier_button"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"/>
To present the wappier Loyalty Icon at any time, use the following line:
- Android(Java)
- iOS(obj-C)
- Unity(C#)
- C++
mCustomButton.showLoyIcon("REFERRER");
[WappierSDK showLoyIconWithCompletionBlock:^(BOOL success, NSString *error){}
referrer:@"referrer"];
Wappier.Instance.showLoyaltyButton(width, height, x, y, "REFERRER");
WappierSDKWrapper::getInstance()->showLoyaltyButton(width, height, x, y, "REFERRER");
REFERRER
is a free text parameter describing the screen that the Icon has shown.
To hide the wappier Loyalty Icon at any time, use the following line:
- Android(Java)
- iOS(obj-C)
- Unity(C#)
- C++
mCustomButton.hideLoyIcon();
[WappierSDK hideLoyIcon];
Wappier.Instance.hideLoyaltyButton();
To set the wappier Loyalty Icon position at any given in-game screen, use one of the following lines:
- Android(Java)
- iOS(obj-C)
- Unity(C#)
- C++
mCustomButtom.setPosition(200,200) // setPosition(xPoint,yPoint)
mCustomButton.setPosition(Position.Top,Position.Left)
mCustomButton.setPosition(10,Position.Top,Position.Left)
[WappierSDK setLoyIconPosition:position];
[WappierSDK setLoyIconPosition:position margin:margin];
[WappierSDK setLoyIconFrame:frame];
Missing documentation
Missing documentation
One of the following constants can also be used in order to set the wappier Loyalty Icon position:
- Android(Java)
- iOS(obj-C)
- Unity(C#)
- C++
Constant | Position |
---|---|
Position.DEFAULT | Icon displays default position |
Position.LEFT | Icon displays at left of the screen |
Position.RIGHT | Icon displays at right of the screen |
Position.TOP | Icon displays at top of the screen |
Position.BOTTOM | Icon displays at bottom of the screen |
Constant | Position |
---|---|
WappierLoyIconPositionDefault | Icon displays at the bottom right of the screen |
WappierLoyIconPositionTopLeft | Icon displays at the top left of the screen |
WappierLoyIconPositionTopRight | Icon displays at the top right of the screen |
WappierLoyIconPositionBottomLeft | Icon displays at bottom left of the screen |
WappierLoyIconPositionBottomRight | Icon displays at bottom left of the screen |
You can use setLoyIconFrame: to set the icon’s height equal to its width in order to keep the correct aspect ratio.
Showing/hiding the custom Icon
In case you implement your custom Loyalty button you make sure that it will be visible only to the users that have active loyalty status. You can register a listener to receive updates with the current end-user’s loyalty status by adding the following lines:
- Android(Java)
- iOS(obj-C)
- Unity(C#)
- C++
WappierSDKWrapper::getInstance()->setLoyaltyListener([](bool enabled){
//do something with the status
//e.g. control whether the Wappier loyalty icon is visible
});
[WappierSDK addLoyaltyStatusListener:^(BOOL status){
}];
Wappier.Instance.setLoyaltyStatusDelegate(flag =>
{
//do something with the status
//e.g. control whether the Wappier loyalty icon is visible
});
WappierSDKWrapper::getInstance()->setLoyaltyListener([](bool status) {
//do something with the status
//e.g. control whether the Wappier loyalty icon is visible
});
The custom loyalty button can be hidden by adding the following attributes:
controlGroupFlag = true
or status = false
or flag = false
.
Tracking Custom Icon Impression
When a custom Loyalty Icon is displayed add the following code:
- Android(Java)
- iOS(obj-C)
- Unity(C#)
- C++
Wappier.getInstance().trackLoyIconDisplay("REFERRER");
[WappierSDK trackLoyaltyIconImpression:@"referrer"];
Wappier.Instance.trackLoyaltyIconImpression("REFERRER");
WappierSDKWrapper::getInstance()->trackLoyaltyIconImpression("REFERRER");
REFERRER
is a free text parameter describing the screen the user is on when the Loyalty Profile card was presented.Showing Loyalty User Profile
To display the Loyalty User Profile/ Loyalty Card, you should add the following line:
- Android(Java)
- iOS(obj-C)
- Unity(C#)
- C++
Wappier.getInstance().showLoyaltyView("REFERRER");
[WappierSDK showLoyViewWithCompletionBlock:^(BOOL success, NSString *error){}
referrer:@"referrer"];
Wappier.Instance.showLoyaltyView("REFERRER");
WappierSDKWrapper::getInstance()->showLoyaltyView("REFERRER");
REFERRER
is a free text parameter describing the screen that the user is on when the Loyalty Profile card was presented.Loyalty Profile Orientation
You can control the orientation of the Loyalty Profile depending on the app needs:
- Android(Java)
- iOS(obj-C)
- Unity(C#)
- C++
Wappier.getInstance()
.startSession(this, YOUR_APPLICATION_KEY, new Locale("en"), userName, kvpMap);
.setLOYOrientation(PREFERRED_ORIENTATION);
Wappier.Instance().setLoyaltyViewOrientation(PREFERRED_ORIENTATION);
WappierSDKWrapper::getInstance()->setLoyaltyViewOrientation(PREFERRED_ORIENTATION);
The PREFERRED_ORIENTATION
can take one of the following options:
- Android(Java)
- iOS(obj-C)
- Unity(C#)
- C++
Constant | Result |
---|---|
Orientation.PORTRAIT | Lock orientation to portrait |
Orientation.LANDSCAPE | Lock orientation to landscape |
Orientation.OPEN | Loyalty card will rotate depending on device orientation |
Constant | Result |
---|---|
Orientation.PORTRAIT | Lock orientation to portrait |
Orientation.LANDSCAPE | Lock orientation to landscape |
Orientation.OPEN | Loyalty card will rotate depending on device orientation |
Constant | Result |
---|---|
Orientation.PORTRAIT | Lock orientation to portrait |
Orientation.LANDSCAPE | Lock orientation to landscape |
Orientation.OPEN | Loyalty card will rotate depending on device orientation |
Loyalty Sfx Sounds
By default the Sfx sounds in the Loyalty User Profile are disabled. In order to enable the Sfx sounds in the Loyalty User Profile, please add the following code:
Wappier.Instance.setLoySounds(true);
You can select specific sounds for various actions in the Loyalty User Profile:
- When the end-user opens-closes the Loyalty User Profile
- When a popup is displayed
- When a button is clicked
- When the "Claim" button is clicked
- When a reward redemption is successful
- When an error occurred
Loyalty App Fonts Customization
The wappier Optimization SDK can display the texts with the same fonts as the app uses in the Loyalty User Profile. First of all you should provide us the font files in order to upload them on the wappier Back-End and you have to store them in specific folders in Android and iOS version of your app:
- Android: All font files should be stored in a folder with name "Assets"
- iOS: All font files should be added in the app’s info.plist. Furthermore please make sure that the fonts are added to a folder in the same level with the app’s info.plist in the Xcode hierarchy. Also they must be included in your app by checking it in the "Target Membership" list For instance, please check the screenshots below:
Getting Control/Target Group Status
To get Control/Target Group Status, add the following code:
bool controlFlag = Wappier.Instance.isUserControlGroup();
Getting User Status
You can get the end-user status for each wappier service. In the response, you can find if the end-user is included in the control or target group, for the wappier service that you are asking for. To get User Status, add the following code:
// tags is a string[] and can take values "all" | "loyalty" | "pricing" | "campaign"
string[] tags = new string[] {"loyalty","pricing","campaign"}
Wappier.Instance.GetUserStatus(tags, UserStatusCallback);
void UserStatusCallback(string response)
{
//Handle response json
}
OR
Wappier.Instance.GetUserStatus(tags, response => {
//Handle response json
});
which takes a list of tags as an argument and returns a JSON response as a String.
Example response:
"{
\"loyalty\" : {
\"population\" : 0.67220987,
\"control\" : false,
\"enabled\" : false
},
\"campaign\" : {
\"population\" : 0.36149076,
\"control\" : false,
\"enabled\" : false
},
\"pricing\" : {
\"population\" : 0.34617529,
\"control\" : false,
\"enabled\" : true,
\"billingCountry\": \"GR\",
\"isInScope\": true
}
}"
In the response, you may find if the user is included in the control or target group per each service. If the end-user is included in the control group for the requested service if the {{service}}.control:true and {{service}}.enabled:false If the end-user is included in the target group for the requested service if the {{service}}.control:false and {{service}}.enabled:true
Loyalty Status Update
You can register a listener to receive updates about the current loyalty status:
Wappier.Instance.setLoyaltyStatusDelegate(flag =>
{
...
});
Loyalty Notifications Count Update
The wappier Optimization SDK provides you a callback that informs you about the current number of notifications. For instance, if there are notifications you can show their count on your custom button by adding the following lines:
Wappier.Instance.setLoyaltyNotificationsCountDelegate(count =>
//do something with the count of loyalty notifications
//e.g. show some icon over the loyalty icon
});
Loyalty Unlocked Reward Update
You can register a listener to receive updates for unlocked rewards:
Wappier.Instance.setRewardUnlockDelegate((eventName, redeemableItems) =>
{
...
});
Loyalty Balance Increase Update
You can register a listener to receive updates for balance increases:
Wappier.Instance.setBalanceIncreaseDelegate((eventName, redeemableItems) =>
{
...
});
Loyalty Inventory Update
You may get the items that the end-user has redeemed. The below callback must be called occasionally based on when you should be informed for the end-user’s inventory. Ιndicatively, it may be called when a new session starts and ends in your application. In the items, you can find the title, description and images of rewarded items along with the current state of the rewards.
int[] invTypes = { 0 };
int[] statuses = { 0, 1 };
Wappier.Instance.getInventoryRequest(invTypes, statuses, (inventoryItems) =>
{
...
});
Arguments invTypes and itemStatuses are arrays of integers that can contain the following values:
Note 1: You can pass in each parameter a combination of more than one of the above values. Note 2: If you pass wrong params in the callback, you will not be informed and the response listener will never be called. Note 3: Response example:
{
"inventories": [
{
"type": 0, // INVENTORY_TYPE
"balance": {
"WP_POINTS": { // Loyalty Points
"total": 20000, // Total Loyalty Points
"current": 12200 // Current Loyalty Points
}
},
"redeemed": [ // Redeemed In-app Rewards
{
"amount": 2, // Reward Amount
"redeemable": {
"sku": "WP_20_COINS", // wappier Redeemable Identifier
"type": "INAPP", // redeemable type - "INAPP" for in-app rewards
"amount": 10, // redeemable amount
"refCode": "com.package.coin" //publisher's in-app reward identifier
}// The redeemed reward is 20 coins because the end-user got 2 WP_20_COINS. The WP_20_COINS redeemable is 10 com.package.coin
},...
],
"unlocked": [ // Unlocked In-app Rewards
{
"amount": 2, // Reward Amount
"redeemable": {
"sku": "WP_1_GEM", // wappier Redeemable Identifier
"type": "INAPP", // redeemable type - "INAPP" for in-app rewards
"amount": 1, // redeemable amount
"refCode": "com.package.gem" // publisher's in-app reward identifier
}// The unlocked reward is 2 gems because the end-user got 2 WP_1_GEM. The WP_1_GEM redeemable is 1 com.package.gem
},...
]
}
],
"total": 1 // number of user inventory
}
Get Loyalty Notifications Count
You can get the current number of notifications on demand by using this method:
- Android(Java)
- iOS(obj-C)
- Unity(C#)
- C++
int notificationsCount = Wappier.getInstance().getNotificationsCount();
NSInteger notificationsCount =[WappierSDK getNotificationsCount];
int count = Wappier.Instance.getNotificationsCount();
int notificationsCount = WappierSDKWrapper::getInstance()->getNotificationsCount();
In-App Products Setup & Redemption Flow
In order to reward in-app items through the wappier Optimization SDK, each of these items should be matched with a unique and custom name.
When the user attempts to spend points to redeem an item, the wappier Optimization SDK should be informed whether that redemption is successful in order to subtract the respective points.
You can receive the redemption notifications by adding the following code:
- Android(Java)
- iOS(obj-C)
- Unity(C#)
- C++
Use one of the following code snippets in your activity:
Wappier.registerRedeemCallback(new RedeemListener() {
@Override
public void redeemCallback(final Redeemable redeemable, final String redemptionId, final long quantity) {
...
}
});
//or
RedeemListener redeemListener = new RedeemListener() {
@Override
public void redeemCallback(final Redeemable redeemable, final String redemptionId, final long quantity) {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (redeemable.getRefCode().equals("SKU1") || redeemable.getRefCode().contains("test_sku_")) {
...
}
}
}, 3000);
}
};
@Override
protected void onStart() {
super.onStart();
Wappier.getInstance().registerRedeemCallback(redeemListener);
}
@Override
protected void onStop() {
super.onStop();
Wappier.getInstance().unregisterRedeemCallBack();
}
Add a delegate conforming to the XNRedemptionDelegate protocol, or add an XNRedemptionCallback block:
[WappierSDK setRedemptionDelegate:[you delegate]];
[WappierSDK setRedemptionBlock:^(WappierRedeemedReward* reward){
NSLog(@"Got some reward to redeem");
}];
where
@protocol XNRedemptionDelegate <NSObject>
- (void)redeem:(WappierRedeemedReward *)redeemable;
@end
Add the following code in your app’s delegate didFinishLaunchingWithOptions
method:
Wappier.Instance.startSession(APP_KEY, userName, "uiLocale", attributes, flag =>
{
if(flag==true)
{
Wappier.Instance.registerRedeemCallback(WPRedeemDelegate);
}
}
Your delegate must conform to the following prototype:
public delegate void WPRedeemDelegate(XNRedeemableItem redeemable, string redemptionId, int quantity);
Add the following code in your app’s delegate didFinishLaunchingWithOptions
method:
WappierSDKWrapper::getInstance()->setRedemptionCallback(WPRedemptionCallback);
The method registerRedeemCallback must be called if the flag boolean listener of the startSession has the value true
.
Callback block type:
typedef void(*WPRedemptionCallback)(WPRedemption* redemption);
When the transaction is completed and the user receives the reward you can call the following line to complete the redemption flow:
- Android(Java)
- iOS(obj-C)
- Unity(C#)
- C++
Please don’t forget to call redemptionIsCompleted method as soon as possible!
Wappier.registerRedeemCallback(new RedeemListener() {
@Override
public void redeemCallback(final Redeemable redeemable, final String redemptionId, final long quantity) {
// added delay to emulate a transaction
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (redeemable.getRefCode().equals("SKU1") || redeemable.getRefCode().contains("test_sku_")) {
Wappier.getInstance().redemptionIsCompleted(true, redemptionId);
} else {
Wappier.getInstance().redemptionIsCompleted(false, redemptionId);
}
}
}, 3000);
}
});
Posssible responses
// Failed redemption due to a missing item ID
Error buffer(com.android.okhttp.internal.http.Http1xStream$FixedLengthSource@8a15e97).inputStream() Message :{"error": "Reward is not found, is locked or claimed","code":916} Code :400
// Failed redemption due to a game error
Redeem sending demo.sku.com with Quantity : 5 to server
Redeem Item found. 5000 will committed
Calling mother app callback with SKU : demo.sku.com
Redemption is Completed :false
Redeem – Status: 1000
Points restored
// Successful redemption
Redeem sending demo.sku.com with Quantity : 5 to server
Redeem Item found. 5000 will committed
Calling mother app callback with SKU : demo.sku.com
Redemption is Completed :true
Redeem – Status: 200
Transaction Completed
Don’t forget to call the completeRedemptionWithID method as soon as possible.
#import "WappierRedeemedReward.h"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[WappierSDK startSessionWithApiKey:@"YOUR_API_KEY"
username:@"YOUR_USER_NAME"
andLocale:@"en-US"];
[WappierSDK setRedemptionDelegate:self];
}
- (void)redeem:(WappierRedeemedReward *)reward {
BOOL didRedeemSkuSuccessfully = YES;
NSString *sku = reward.redeemable.sku;
NSNumber *quantity = reward.quantity;
if ([sku isEqualToString:@"com.wappier.shield"]) {
// Reward player with item shield
// if reward is successful, didRedeemSkuSuccessfully = YES;
// else didRedeemSkuSuccessfully = NO;
}
else if ([sku isEqualToString:@"com.wappier.sword"]) {
// Reward player with item sword
// if reward is successful, didRedeemSkuSuccessfully = YES;
// else didRedeemSkuSuccessfully = NO;
}
else if ([sku isEqualToString:@"com.wappier.diamonds"]) {
// Reward player with item diamonds
// if reward is successful, didRedeemSkuSuccessfully = YES;
// else didRedeemSkuSuccessfully = NO;
}
else {
didRedeemSkuSuccessfully = NO;
}
[WappierSDK completeRedemptionWithID: reward.redemptionId
andResult: didRedeemSkuSuccessfully];
};
The following code snippet suggests a way to set up your redemption selector:
public void redeemDelegate(XNRedeemableItem redeemable, string redemptionId, int quantity) {
Wappier.Instance.redemptionIsCompleted(true, redemptionId);
}
Don’t forget to call the completeRedemption
method as soon as possible:
WappierSDKWrapper::getInstance()->setRedemptionCallback([](WPRedemption* redemption ){
WappierSDKWrapper::getInstance()->completeRedemption(redemption->redemptionId,true);
});
Find an explanatory diagram of the redemption flow below: