Skill Level: Intermediate

One of our recommended practices is to set up a way to obtain SDK debug information from your app to help when getting technical support. Specifically, it’s very common for our support team to request mobile user ID and SDK versions, though there are a number of other items you may want to include in a debug screen such as OS version and platform, build version of your app, channel ID, app key and so on. If you have this information easily available from devices in the field, it becomes significantly easier to resolve problems. Most customers prefer to keep this information hidden until it’s needed. We recommend that as well. Thus the question arises: how can one make a secret trigger that can be used to report SDK information, but make it relatively easy to access when needed. This is one possible solution. You may want to use a different way to trigger the way to open the screen, and consider issues with accessibility.


Not what you’re looking for? Check out all our available tutorials for mobile app messaging here.


  1. Make changes to the sample app

    The following changes will be made to the sample app. Changes to your app will be similar.

    1. Decide where you’ll invoke a trigger

    You will need to find an appropriate place in your app from which a user invokes the trigger. Often this is the Configuration screen, but if you have a lot of elements on that screen, another view may be preferable. It’s best if it’s a screen where you’re not already collecting gesture events.

    A view that has a text entry field offers slightly more security than one that doesn’t (described later).

    In this case, we will be adding the event to the “Send User Attributes” screen in the sample app.

    2. Add the changes

    Add the following variables to AttributesVC.m in the @implementation section:


    // Secret diagnostics
    // Variables required
    // Change pattern to indicate the sequence of triple-clicks required to activate
    // the secret action.
    // Note that 1=upper left, 2=upper right, 3=lower left, 4=lower right
    static int pattern[] = {1, 2, 3, 4, 3, 2, 3, 2};
    int patternIndex = 0;


    The “pattern” static variable represents the quadrants on the screen where the user must triple-tap to trigger the event. In this case, we require the user to triple-tap in the upper left, then the upper right, then the lower left, then the lower right, then again in the upper right, then lower left, then upper right. When that happens, the event will be triggered. Any deviation from the pattern resets it back to the beginning.

    We strongly recommend you change the sample pattern. You might want to use a different pattern for each app, or even each major revision of the app. Remember, however, that your support reps will need to be able to tell people how to trigger the diagnostic event. If it’s too complicated, you may need to adjust it.

    Add the following three methods to the bottom of the view controller before @end (AttributesVC.m in the sample):

    // Secret diagnostics
    // Detect triple-taps in various quadrants of the screen
    // Change the values of fieldString and requiredString to your choice
    // Underlying algorithm from https://stackoverflow.com/questions/48441348/whats-the-best-way-to-implement-hidden-debug-options
    - (void) tryKey: (UITapGestureRecognizer *)sender {
        NSString *fieldString = self.nameTextField.text;
        NSString *requiredString = @"text";
        if (![fieldString isEqualToString: requiredString]) {
        CGPoint touchLocation = [sender locationInView:sender.view];
        [self checkPatternAndOpen:[self mapTouchLocationToInt:touchLocation]];
    - (void)checkPatternAndOpen: (int)nextValue {
        NSLog(@"Next value is %d", nextValue);
        if (pattern[patternIndex] == nextValue) {
            // progressing
            if (patternIndex == sizeof(pattern)/sizeof(pattern[0])) {
                // triggered, show debug screen
                patternIndex = 0;
                [self showDebugScreen];
        } else {
            // reset
            patternIndex = 0;
    - (int) mapTouchLocationToInt: (CGPoint)touchLocation {
        // Upper left of screen is 1, upper right is 2
        // Lower left is 3, lower right is 4
        // If screen is rotated, things get confusing
        float midX = self.view.bounds.size.width / 2;
        float midY = self.view.bounds.size.height / 2;
        if(touchLocation.y < midY) {
            if(touchLocation.x < midX) {
                return 1;
            } else {
                return 2;
        } else {
            if(touchLocation.x < midX) {
                return 3;
            } else {
                return 4;
    - (void) showDebugScreen {
        // Take an appropriate action - display the information, or perhaps mail it to
        // your support team.
        RegistrationVC *registrationVC = [self.storyboard instantiateViewControllerWithIdentifier:@"Registration"];
        [self presentViewController:registrationVC animated:YES completion:nil];


    Next, connect the tryKey: method to the triple-tap gesture. In the viewDidLoad method, add the following before the call to [super viewDidLoad]:

    // Secret diagnostics
        // Connect triple-tap gesture to tryKey:
        UITapGestureRecognizer * gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tryKey:)];
        gesture.numberOfTapsRequired = 3;
        gesture.cancelsTouchesInView = false;
        [self.view addGestureRecognizer:gesture];
        self.view.userInteractionEnabled = true;

    Since the showDebugScreen in this example opens RegistrationVC, we need to include its header to the imports of AttributesVC.m:


    // Secret diagnostics
    // reporting screen
    #import "RegistrationVC.h"


    The action that is executed when the event is triggered is in showDebugScreen. In the case of the sample app, it already has a screen which reports mobile user ID, channel ID and app key. If the touch events are appropriately triggered, we invoke it.

    Note the test for fieldString in tryKey:. In our example, the sample app will never invoke an action (even if the trigger triple-taps happen) unless the “nameTextField” field contains the value “text”. We chose that value because it’s already present in the class, so it will be reused from the class pool. Doing so obscures the code slightly from those who decompile the class. Similarly, you might want to change method names so people who decompile will not think to look further, or change how pattern is stored (perhaps by encoding it or constructing it via computation). Ultimately, your code may be extracted and examined. Because of this, keep passwords out of your diagnostics.

    Another option (rather than opening a screen) is to create an email message addressed to your support group. In general, this is done by calling MFMailComposeViewController.

    No matter how you do it, we recommend that you give users some way to get diagnostic information at the direction of your support team. This will make problem resolution much more efficient both within your company and when interacting with our mobile support team.

Expected outcome

Expected Outcome: Need more help? Check out all of our available tutorials for mobile app messaging here.


Join The Discussion

Your email address will not be published. Required fields are marked *