Skip to content

Player Messaging and Gifting

Player Messaging and Gifting via Facebook

This tutorial will show you how to allow players to send messages and gifts to their friends from within your game. This is often a key feature to help drive engagement. ChilliConnect has a messaging API that is closely integrated with the Economy feature. You can use this API alongside Cloud Code and the Facebook SDK to allow your users to send gifts to friends.

In this example you will use the messaging API to send messages between users. The Cloud Code feature is required to add some extra security when sending gifts and the Facebook SDK is used to manage our users friends. Finally, the project uses SAMKeychain as a convenience wrapper for saving user credentials to the device keychain. You can find SAMKeychain on GitHub.

The sample code is provided as an Xcode project written in Objective-C but the same features are provided for Unity and HTTP. You will need Xcode 8 or later. As the sample project is a standard iOS application it relies on Storyboards to control the app flow between views. Storyboards are outside of the scope of the tutorial (and they are likely of little importance to game developers) so we won't be going into any details how Storyboard creation or use. Suffice to say if you would like to find out more you can read about it on the Apple Developer Connection.

The full XCode project for this tutorial is available on the ChilliConnect GitHub samples repository under the folders "Objective-CSamples", "PlayerMessaging. To run the project under your own ChilliConnect game you should change the value of the <YOUR GAME TOKEN HERE> string in ChilliConnectController.m.

 Download Sample Code

Creating a Facebook App

The first step is to create and App on Facebook. There is already a tutorial to help you with this step so please refer to the Facebook Tutorial tutorial. As this sample uses Objective-C you can follow the Facebook iOS getting started guide. To update the sample project to your own Facebook App, update the relevant values in the Info.plist file.

ChilliConnect Setup

You will also need to create a ChilliConnect game on the dashboard. Conveniently there is already a Setup tutorial to guide you through this.

Project Setup

OK, now that you have created your Facebook app it's time to create a new Xcode project. For the purposes of this tutorial you should clone the sample project as we will use this as reference. You will see that the sample project has Frameworks and library code needed for Chilli Connect, Facebook and Keychain in the 'Frameworks' folder and 'SAMKeychain' folder.

The project needs the following frameworks:

  • ChilliConnect.framework
  • Bolts.framework
  • FBSDKCoreKit.framework
  • FBSDKLoginKit.framework
  • FBSDKShareKit.framework

SAMKeychain contains SAMKeychain.m, SAMKeychain.h, SAMKeychainQuery.h, SAMKeychainQuery.m and LICENSE.

Finally you need to add Security.framework via project settings in General->Linked Frameworks and Libraries -> +. It is worth noting the SAMKeychainQuery.m has a bug fix in the + (NSError *)errorWithCode:(OSStatus) code method at line 250.

Logging In Part I: Facebook

When it comes to logging in using ChilliConnect you have flexibility to choose from a few different models. As this project relies on Facebook for the purposes of accessing a list of friends the logging in model is based on linking the users ChilliConnect Id to their Facebook account.

So as a first step you will need to ask the user to login using Facebook. You can find this in the LaunchViewController class.

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    if([FBSDKAccessToken currentAccessToken])
    {
        NSLog(@"FB App ID %@", [FBSDKAccessToken currentAccessToken].appID);
        NSLog(@"FB Access Token %@", [FBSDKAccessToken currentAccessToken].tokenString);
        [self performSegueWithIdentifier:@"CCMainSegue" sender:self];
    }
    else
    {
        [self performSegueWithIdentifier:@"FBLoginSegue" sender:self];
    }
}

See Full Code 

This is the entry point for the sample app and, as you can see, it is very simple. Upon launch we simply check if the user has a Facebook access token i.e. the user has allowed their Facebook account to connect to the Facebook app you created in the step 'Creating a Facebook App'. If we do not have a token this mean the user has not done this, so we need to present the Facebook login flow. You can see the Facebook login code in the FBViewController class. FBViewController simply creates a Facebook login button and sets read permissions.

Logging In Part II: ChilliConnect

After the user has logged in with Facebook control is handed to MainViewController. This is the primary class that drives the rest of the application. The first thing we do here is log the user into ChilliConnect:

- (void) login
{
    AppDelegate *app = (AppDelegate*)[[UIApplication sharedApplication] delegate];
    ChilliConnectController* chilliConnectController = [app getChilliConnectController];

    if([chilliConnectController hasCredentials])
    {
        if([chilliConnectController getLoginState] == kLoggedOut)
        {
            ChilliConnectControllerCallback loginUsingFacebookCallback = ^(BOOL success, NSString* errorDescription)
            {
                if(success)
                {
                    NSLog(@"Logged in using Facebook.");
                    [self updateLoggedInAsLabel:chilliConnectController];
                    [self updatePlayerBalance:chilliConnectController];
                    [self show:YES];
                }
                else
                {
                    NSLog(@"%@",errorDescription);
                }
            };
            // You want to login here, try with Facebook and if it fails then loading with saved CC credentials.
            [chilliConnectController loginUsingFacebook:loginUsingFacebookCallback];
        }
        else if([chilliConnectController getLoginState] == kLoggedInFacebook)
        {
            [self updateLoggedInAsLabel:chilliConnectController];
            [self updatePlayerBalance:chilliConnectController];
            [self show:YES];
        }
    }
    else
    {
        // Try to login using Facebook. If successful, login otherwise create a new user.
        [self tryLoginUsingFacebook:chilliConnectController];
    }
}

See Full Code 

You will find all of the code that uses the ChilliConnect SDK in the ChilliConnectController class. Calls for logging in can be found under the 'Login and User Creation' section.

During this process we need to either create a new ChilliConnect user, or login and existing user. The ChilliConnect account also needs to be linked to the users Facebook account. This is where SAMKeychain comes in. We use this to save our ChilliConnect credentials to device securely. This allows our app to quickly load saved credentials on launch and we can use this to decide which flow we need to follow, either creating a new account or logging in with the saved credentials.

However, there is one further consideration here. You will notice in the sample code that the login step does not create a new ChilliConnect user straight away if there are no saved credentials. Instead the code tries to log the user in using Facebook. The reason for this is that we want to preserve user data, namely our users economy data (which is COINS for our sample app). This allows the user the option to login to the same account even after they logout or even uninstall the app. We can do this by using ChilliConnect Player API which will return the ChilliConnect user credentials if a Facebook access token has already been linked to a ChilliConnect account. This is really a developer decision. If you wanted to you could abandon the old ChilliConnect account and link the users Facebook to a new ChilliConnect account if the user were to come back after logging out or uninstalling. It is up to you. The sample code shows you the flow of logging in and linking a ChilliConnect account as well as retrieving credentials from a linked Facebook account.

Sending a Gift Using Cloud Code

Now we are ready to send a message with a gift to a friend. Remember we will not be able to see all our our Facebook friends, but only those friends who have also given access to our Facebook app. Login to your ChilliConnect dashboard and click on your Player Messaging game. Next, select API Access Control. This shows you a list of the APIs that you will have access to. You can edit each options as you see fit but for this example we are going to leave everything as is. Scroll down to the Messaging section and you note that Send Message and Send Message From Player are disabled. This is due to security reasons as it would not take a tremendous amount of effort for a determined party to to send spoof messages. Ideally we want to be able to allow sending of messages but to do so securely. To achieve this we can use Cloud Code.

Within the dashboard select Connect on the left menu and then select Cloud Code. Next click Add Script. Enter SendMessageGift for Name and SENDMESSAGEGIFT for Key. Add two params, GiftValue as Numeric set as required and To as String also set as required.

Copy/Paste code from the listing below and click Save and the Publish.

// Sends a gift to the specified player using the PlayerMessaging API.
try
{
    var sdk = ChilliConnect.getSdk("2.0.0");

    /* The recipient of our gift */
    var toPlayer = ChilliConnect.Request.To;
    if(!toPlayer || toPlayer.length < 1) {
        return { "Error" : "Invalid ChilliConnectID for recipient." };
    }

    /* Currently logged in player. */
    var loggedInPlayer = sdk.PlayerAccounts.getPlayerDetails();

    /* Number of seconds until the message expires. */
    var expiry = 7776000;

    /**
     * CCMessageGifts object.
     * https://docs.chilliconnect.com/api/?system=ios#SendMessage-ios-CCMessageGifts
     */
    var gifts = {
        "Currencies" : [
            {
                "Key" : "COINS",
                "Amount" : ChilliConnect.Request.GiftValue
            }   
        ]
    };

    try {
            sdk.Messaging.sendMessage(toPlayer,
                                                loggedInPlayer.ChilliConnectID,
                                                "", // A title or summary for the message.
                                                "", // The message body to send.
                                                {}, // Custom data to be sent with the message.
                                                [], // An array list of Tags.
                                                expiry,
                                                gifts);
    }
    catch(e) {
        ChilliConnect.Logger.error(e.toString());
        return { "Error": true }
    }
}
catch(e){
    ChilliConnect.Logger.error(e.toString());
    return { "Error": true }
}

return { "Sent" : ChilliConnect.Request.GiftValue };

You can also use the Run tab to test your script. This is a really powerful feature to help you debug your scripts before you deploy them.

Next we need to add a currency to our catalog so that we have somewhere to store our gifts. Click on Catalog on the left (in the Connect section). Click Add Item at the top right and select Currency. Give it the Name Coins and Key COINS and click Add Currency

Now our ChiliConnect game is ready to go and we can add code to send a gift of Coins to a friend. Switch back to Xcode and open ChilliConnectController.m. Scroll down to the Messaging and Cloud Code section. The first method in this section allows use to send a message to a friend using the CCCloudCode API :

/* Sends a message */
- (void) sendMessageWithScriptKey:(NSString*)scriptKey dictionary:(NSDictionary*)dictionary callback:(ChilliConnectControllerCallback)callback
{
    CCCloudCode* cloudCode = self.chilliConnect.cloudCode;

    CCRunScriptRequestDesc* requestDesc = [CCRunScriptRequestDesc runScriptRequestDescWithKey:scriptKey];
    requestDesc.params = dictionary;

    CCRunScriptResponseCallback successCallback = ^(CCRunScriptRequest* request, CCRunScriptResponse* response)
    {
        NSLog(@"Message sent successfully.");
        callback(YES, nil);
    };

    CCRunScriptErrorCallback errorCallback = ^(CCRunScriptRequest* request, CCRunScriptError* error)
    {
        callback(NO, error.errorDescription);
    };

    [cloudCode runScriptWithDesc:requestDesc successCallback:successCallback errorCallback:errorCallback];
}

See Full Code 

We pass in the key for the script to call and a dictionary describing our recipient and key/values for the params we setup in our script. In our case the params are GiftValue and To. It is worth noting that the dictionary must contain SCMultiTypeValue to String entries. You can see this in the - (void) sendGift:(NSString*)recipientChilliConnectId value:(int)value in SendViewController.m. This will allow use to send a gift to a friend using Cloud Code.

Receive a Gift Using Messaging

The final part of our app allows our user to received gifts sent to them from their friends. We use the CCMessaging API for this. There are three methods in total GetMessages, which returns a list of messages for the user, RedeemMessage which redeems a reward from a specific message and MarkMessageAsRead which marks a specific message as read if we received a CCRedeemMessageRewardsErrorCodeMessageRewardsAlreadyRedeemed error.

First off we need to find out if we have any messages. For this we use the - (void) getMessages:(ChilliConnectControllerGetMessagesCallback)callback method in ChilliConnectController.m:

- (void) getMessages:(ChilliConnectControllerGetMessagesCallback)callback
{
    CCMessaging* messaging = self.chilliConnect.messaging;

    CCGetMessagesRequestDesc* requestDesc = [[CCGetMessagesRequestDesc alloc] init];
    // We are going to stick with default values for CCGetMessagesRequestDesc apart from requesting full message data which includes rewards.
    requestDesc.fullMessages = [NSNumber numberWithBool:YES];

    CCGetMessagesResponseCallback successCallback = ^(CCGetMessagesRequest *request, CCGetMessagesResponse *response)
    {
        NSLog(@"Getting messages returned successfully.");
        callback(YES, nil, response.messages);
    };

    CCGetMessagesErrorCallback errorCallback = ^(CCGetMessagesRequest *request, CCGetMessagesError *error)
    {
        NSLog(@"Getting messages failed.");
        callback(NO, error.errorDescription, nil);
    };

    NSLog(@"Requesting messages...");
    [messaging getMessagesWithDesc:requestDesc successCallback:successCallback errorCallback:errorCallback];
}

See Full Code 

This returns a list of the messages available for this user. A user can have multiple messages but ChilliConnect will not return all available messages. Instead the API returns a group of messages as a page. The API offers controls to request different pages however this tutorial does not cover that. Please refer to the documentation if you require further information on Getting Messages.

Each message has a unique id and this is what we use to work with individual messages. In the sample project you will see this in InboxViewController.m in the - (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath method:

- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
    static NSString* cellIdentifier = @"inboxTableCell";

    InboxViewCell* cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if(cell == nil)
    {
        cell = [[InboxViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    }

    // Find matching Facebook friend for this message
    CCMessage* message = [self.messages objectAtIndex:[indexPath row]];

    for(CCFacebookPlayerWithProfileImage* friend in self.friends)
    {
        if([friend.chilliConnectId isEqualToString:message.from.chilliConnectId])
        {
            [cell.message setText:friend.facebookName];

            NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:friend.facebookProfileImage]];
            [cell.imageView setImage:[UIImage imageWithData:imageData]];
        }
    }

    return cell;
}

See Full Code 

This method is called when adding entries to our inbox view i.e. received message. Here we pull out each message from the messages array and check if the ChilliConnect Id attached to the Facebook account of a friend matches the ChilliConnect Id in a message. If a match if found then we can add a message to the inbox view. When the user taps on this entry the - (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath method is called. Here we show an alert to ask the user to confirm if they want to redeem the gift.

Selecting Redeem will start the process of redeeming the reward. To do this we call - (void) redeemMessageReward:(NSString*)messageId callback:(ChilliConnectControllerCallback)callback:

- (void) redeemMessageReward:(NSString*)messageId callback:(ChilliConnectControllerCallback)callback
{
    CCRedeemMessageRewardsRequestDesc* redeemMessageRewardsDesc = [CCRedeemMessageRewardsRequestDesc redeemMessageRewardsRequestDescWithMessageId:messageId];
    redeemMessageRewardsDesc.markAsRead = [NSNumber numberWithBool:YES];

    CCRedeemMessageRewardsResponseCallback successCallback = ^(CCRedeemMessageRewardsRequest *request, CCRedeemMessageRewardsResponse *response)
    {
        // You should do more checks here to ensure the redeemed amount(s) in the response match the value(s) you expected to redeem.
        callback(YES, nil);
    };

    CCRedeemMessageRewardsErrorCallback errorCallback = ^(CCRedeemMessageRewardsRequest *request, CCRedeemMessageRewardsError *error)
    {
        if(error.errorCode == CCRedeemMessageRewardsErrorCodeMessageRewardsAlreadyRedeemed)
        {
            [self markMessageAsRead:messageId];
        }
        callback(NO, error.description);
    };

    CCMessaging* messaging = self.chilliConnect.messaging;
    [messaging redeemMessageRewardsWithDesc:redeemMessageRewardsDesc successCallback:successCallback errorCallback:errorCallback];
}

See Full Code 

This method uses the CCMessaging API to redeem the message. This is all done by ChilliConnect so when our app receives a successful callback the reward in the message has already been credited to the users economy and the message is marked as read since we specified this in the description: redeemMessageRewardsDesc.markAsRead = [NSNumber numberWithBool:YES];.

Next Steps

You should now be familiar with Cloud Code and Player Messaging. If you want to explore more of what ChilliConnect has to offer you could try expanding you games catalog and allowing players to purchase items or currency using In-App Purchases. You could also experiment with more bespoke gifts.