Custom message handling

With the Xtremepush SDK you, as a developer, have a unified callback to all the user interactions with messages. You can use it to implement any business logic if having the standard deeplinking mechanism is not enough.

iOS

Objective-C

User interaction is described with the XPMessageResponse model. It contains:

  • XPMessage *message
  • XPAction *action

XPMessage contains:

  • XPMessageType *type - message type, one of:
    • XPMessageType_Push
    • XPMessageType_Inapp
    • XPMessageType_Inbox
  • NSString *identifier - message ID
  • NSString *campaignIdentifier - campaign ID
  • NSString *title - message title
  • NSString *text - message text
  • NSDictionary *data - custom payloads
  • NSDictionary *payload - raw message payload

XPAction contains:

  • XPActionType *type - response type, one of:
    • XPActionType_Click
    • XPActionType_Dismiss
    • XPActionType_Present
  • NSString *identifier - action identifier (like button ID, optional)

Here is how to register the handler:

[XPush registerMessageResponseHandler:^(XPMessageResponse *response) {
    switch (response.action.type) {
        case XPActionType_Click:
            // Logic when message is clicked
            break;
        case XPActionType_Dismiss:
            // Logic when message is dismissed
            break;
        case XPActionType_Present:
            // Logic when message is received in foreground
            break;
    }
}];

📘

If you use interactive notifications and want to handle button clicks in the background you need to make sure to use a method with completion handler instead:

[XPush registerMessageResponseHandlerWithCompletion:^(XPMessageResponse * _Nonnull x, XPMessageCompletionBlock  _Nonnull completionHandler) {
    if (response.action.type == XPActionType_Click) {
            if (response.action.identifier == @"like") {
                   // Like article asynchronously and call completionHandler when finished
                   [self likeArticle: response.message.data[@"articleId"] completionHandler: completionHandler];
                   return;
            }
    }

    // If nothing to be done
    completionHandler();
}];

Below is a complete example of custom notification handling. It does multiple things:

  • Shows a custom dialog when a push message is received in the foreground
  • Opens an article page when a message is clicked
  • Saves information when one of the message buttons is clicked
[XPush registerMessageResponseHandlerWithCompletion: ^(XPMessageResponse * _Nonnull response, XPMessageCompletionBlock  _Nonnull completionHandler) {        
        switch (response.action.type) {

            // When message is received in foreground
            case XPActionType_Present:
                // Show an article dialog with "View" button
                [self showArticleDialog: response.message viewButtonCallback: ^{
                    // Report message as clicked
                    [XPush reportMessageClicked:response.message];
                    // Navigate to article page
                    [self openArticle: x.message.data[@"articleId"]];
                }];
                break;
                
            // When message is clicked
            case XPActionType_Click:
                // Default click action
                if (response.action.identifier == nil) {
                    // Navigate to the article page
                    [self openArticle: response.message.data[@"articleId"]];
                } 

                // Action for a certain button click
                else {
                    switch(response.action.identifier) {
                        case "like":
                              // Like article asynchronously and call completionHandler when finished
                              [self likeArticle: response.message.data[@"articleId"] completionHandler: completionHandler];
                              return;
                    }
                }
                break;
        }
    
        completionHandler();
}];

Mark a message as opened

ThereportMessageOpenedand reportMessageClickedfunction are additions to the SDK that enable developers to implement the feature of marking a message as opened or clicked when a user opens or clicks on it within their application. This function is particularly useful for enhancing user engagement and providing real-time feedback on message interactions. When called, it triggers an event within the SDK that records the message as opened or clicked, depending on the function used, for tracking and analytics purposes. Developers can easily integrate this function into their application's message-handling workflow to improve user experience and gain insights into user engagement patterns.

+ (void)reportMessageOpened:(XPMessage *)message context:(NSDictionary *)context
                                                          
+ (void)reportMessageOpened:(XPMessage *)message actionIdentifier:(NSString*)actionIdentifier
                                                          
reportMessageOpened(_ message: XPMessage!, actionIdentifier: String!)

reportMessageOpened(_ message: XPMessage!, context: [AnyHashable : Any]!)
+ (void)reportMessageClicked:(XPMessage *)message context:(NSDictionary*)context;

+ (void)reportMessageClicked:(XPMessage *)message actionIdentifier:(NSString*)actionIdentifier;
reportMessageClicked(_ message: XPMessage!, actionIdentifier: String!)

reportMessageClicked(_ message: XPMessage!, context: [AnyHashable : Any]!)

👍

Messages clicked will be considered opened

Marking a message as clicked using the described method automatically marks it as open, as a user cannot click on the message without first opening it. However, marking a message as opened will not automatically update the click value, as a user may open a message and then not engage with any of the CTAs within it.

Swift

User interaction is described with the XPMessageResponse model. It contains:

  • message: XPMessage
  • action: XPAction

XPMessage contains:

  • type: XPMessageType- message type, one of:
    • XPMessageType_Push
    • XPMessageType_Inapp
    • XPMessageType_Inbox
  • identifier: String - message ID
  • campaignIdentifier: String - campaign ID
  • title: String - message title
  • text: String - message text
  • data: [AnyHashable : Any]? - custom payloads
  • payload: [AnyHashable : Any] - raw message payload

XPAction contains:

  • type: XPActionType - response type, one of:
    • XPActionType_Click
    • XPActionType_Dismiss
    • XPActionType_Present
  • identifier: String - action identifier (like button ID, optional)

Here is how to register the handler:

XPush.registerMessageResponseHandler({(_ response: XPMessageResponse) -> Void in
    switch response.action.type {
        case XPActionType_Click:
            // Logic when message is clicked

        case XPActionType_Dismiss:
            // Logic when message is dismissed

        case XPActionType_Present:
            // Logic when message is received in foreground

    }
})

📘

If you use interactive notifications and want to handle button clicks in background you need to make sure to use a method with completion handler instead:

XPush.registerMessageResponseHandler(withCompletion: {(_ x: XPMessageResponse, _ completionHandler: XPMessageCompletionBlock) -> Void in
    if response.action.type == XPActionType_Click {
        if response.action.identifier == "like" {
            // Like article asynchronously and call completionHandler when finished
            self.likeArticle(response.message.data["articleId"], completionHandler: completionHandler)
            return
        }
    }
    // If nothing to be done
    completionHandler()
})

Below is a complete example of custom notification handling. It does multiple things:

  • Shows a custom dialog when a push message is received in the foreground
  • Opens an article page when a message is clicked
  • Saves information when one of the message buttons is clicked
XPush.registerMessageResponseHandler(withCompletion: {(_ x: XPMessageResponse, _ completionHandler: XPMessageCompletionBlock) -> Void in
   if response.action.type == XPActionType_Present {
                showArticleDialog(response.message, viewButtonCallback: {() -> Void in
                    // Report message as clicked
                    XPush.reportMessageClicked(response.message)
                    // Navigate to article page
                    self.openArticle(x.message.data["articleId"])
                })
            }
            else if response.action.type == XPActionType_Click {
                // Default click action
                if response.action.identifier == nil {
                    // Navigate to the article page
                    openArticle(response.message.data["articleId"])
                }
                    // Action for a certain button click
                else {
                    if response.action.identifier == "like" {
                        // Like article asynchronously and call completionHandler when finished
                        self.likeArticle(response.message.data["articleId"], completionHandler: completionHandler)
                    }
                }
            }
            
            // If nothing to be done
            completionHandler()
})

Android

User interaction is described with the objects 

  • Message messagePayload
  • HashMap<String, String> responsePayload

Message contains:

  • String type - message type, one of:
    • "push"
    • "inapp"
    • "inbox"
  • String id- message ID
  • String campaignId - campaign ID
  • String title - message title
  • String text- message text
  • HashMap<String, String> data - custom payloads

the responsePayload HashMap contains:

  • String type - response type, one of:
    • "present"
    • "click"
    • "dismiss"
  • String action- action identifier (like button ID, optional)

Implement the MessageResponseListener in your Application.java class

public class YOUR_APPLICATION_CLASS extends Application implements MessageResponseListener {

Then implement the method

@Override
    public void messageResponseReceived(Message messagePayload,
            HashMap<String, String> responsePayload,
            WeakReference uiReference) {
        
    }

Then add the setMessageResponseListener option to your initialisation of the PushConnector:

new PushConnector.Builder(XPUSH_APP_KEY, GOOGLE_PROJECT_NUMBER)
            .setMessageResponseListener(this)
            ...
            .create(this);

Below is a complete example of custom notification handling. It does multiple things:

  • Shows a custom dialog when a push message is received in the foreground
  • Opens an article page when a message is clicked
  • Saves information when one of the message buttons is clicked
@Override
    public void messageResponseReceived(final Message messagePayload,
            HashMap<String, String> responsePayload,
            final WeakReference uiReference) {

        switch (responsePayload.get("type")) {

            // When app is received in the foreground show a custom notification
            case "present":
                if (uiReference != null && uiReference.get() != null) {
                    ((Activity) uiReference.get()).runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            AlertDialog.Builder builder = new AlertDialog.Builder((Activity) uiReference.get());
                            builder.setPositiveButton("View", new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int id) {
                                    //go to article id
                                    openArticle(messagePayload.data.get("articleId"));
                                }
                            });
                            builder.setMessage(messagePayload.text);
                            builder.setTitle(messagePayload.title);
                            AlertDialog dialog = builder.create();
                            dialog.show();
                        }
                    });
                }
                break;

            //when message is clicked
            case "click":
                //default click action
                if (!(responsePayload.containsKey("action"))) {
                    //navigate to article
                    openArticle(messagePayload.data.get("articleId"));
                }
                //action for a certain button click
                else {
                    switch (responsePayload.get("action")) {
                        case "like":
                            //like article
                            likeArticle(messagePayload.data.get("articleId"));
                            break;
                    }
                }
                break;
        }
    }

Mark a message as opened

As with iOS, thereportMessageOpenedand reportMessageClickedfunction are additions to the SDK that enable developers to implement the feature of marking a message as opened or clicked when a user opens or clicks on it within their application. This function is particularly useful for enhancing user engagement and providing real-time feedback on message interactions. When called, it triggers an event within the SDK that records the message as opened or clicked, depending on the function used, for tracking and analytics purposes. Developers can easily integrate this function into their application's message-handling workflow to improve user experience and gain insights into user engagement patterns.

reportMessageOpened(message, action, null);

reportMessageOpened(Message message, String action, JSONObject message_context)
reportMessageClicked(message, action, null);
 
reportMessageClicked(Message message, String action, JSONObject message_context) 

👍

Messages clicked will be considered opened

Marking a message as clicked using the described method automatically marks it as open, as a user cannot click on the message without first opening it. However, marking a message as opened will not automatically update the click value, as a user may open a message and then not engage with any of the CTAs within it.