iOS SDK Documentation

iOS SDK

iOS SDK v4.1.8

Released: Mar. 15, 2016

Download

File: [Download SDK v4.1.8]
SHA1: 2884c4f984884c139ec8ece79d998f0bae29630b
MD5: cbbc5f15a42c22a2c177354239d621ca

About

4.1.8 – Maintenance and performance release.

Features

  • None

Issues Resolved

  • None

Notes

  • Requires libsqlite3.dylib be added to project dependencies.
  • Requires iOS 5.1 or later.
  • Requires Xcode 5.1 or later.

Top ▲

iOS SDK Changelog

iOS SDK Version 4.1.8 – Released Mar. 15, 2016

Features

  • Maintenance and performance release. No new features. No issues addressed.

iOS SDK Version 4.1.7 – Released Dec. 1, 2015

Features

  • Resolved intermittent issue with Local Notifications that notify of Feedback response.

iOS SDK Version 4.1.5 – Released Sept. 17, 2015

Features

  • Resolved keyboard issue on long Mobile Surveys.

iOS SDK Version 4.1.4 – Released Aug. 14, 2015

Features

  • Removes the requirement in earlier builds of v4.1.x for a separate SDK to support Bitcode. This is no longer required.

iOS SDK Version 4.1.2 – Released July 16, 2015

Features

  • Rating Booster Improvements.
  • Feedback Widget Improved.
  • Customer Support Widget Added.
  • Local Notifications Added.

iOS SDK Version 4.0 – Released Feb. 13, 2015

Features

  • NEW standalone Feedback widget
  • Adds support for Rating Booster Request Feedback dashboard setting.

iOS SDK Version 3.1.1 – Released July 10, 2014

Features

  • Required when building Apps using Xcode 6/iOS 8 SDK.
  • Supports IOS 8.0.
  • Supports Swift language.

Bugs

  • Fixes issue with Show Ads at Tags in iOS 5.x.

iOS SDK Version 3.1 – Released May 7, 2014

Features

  • Supports the new Cross Promotion In-App Message type that displays Ad Creative.
  • Supports Other Monetization features to be announced soon.
  • Improved appearance of Rating Widget pop-up.
  • Improved animation of Rating Widget and In-App Messages.

Bugs

  • None known.

iOS iOS SDK Version 3.0.3 – Released Mar 3, 2014

Features

  • New Banner and Interstitial Ad Classes.
  • SDK can use Vendor ID as an alternative to Advertising ID.
  • Deprecates the AP prefix for AskingPoint function names, and replaces with ASKP.

Bugs

  • None known.

iOS SDK Version 2.3.2 – Released Dec. 13, 2013

Features

  • Added support for the 64 bit simulator (64 bit hardware IS ALREADY supported in previous SDKs).

Bugs

  • None known.

Top ▲

iOS Getting Started

SDK Overview

The AskingPoint SDK is a drop in library that is driven by Mobile App Analytics and which helps you Improve Ratings, Get Feedback, Support Users and Send Messages. It provides a complete range of services that you control in real-time from the Dashboard. Features include:

  • Rating Booster – a fully configurable, analytics controlled rating widget that finds your App’s fans and which you control in real-time from your Dashboard.
  • Cross Promotion – A tool that lets leverage your most valuable asset (your install base) to promote your other Apps or services to your customers.
  • Mobile Surveys – a native widget that displays Polls you create and launch from your Dashboard.
  • Push Messages – Push messaging for when you need to reach all your users.
  • Local Notifications – A form of In-App notification that can be used to remind users about your App or services in the future.
  • Payload – A tool for delivering JSON formatted data to deployed Apps from the Dashboard or your servers, based on Rules & Tags.

Great tools that help you improve ratings, improve your App, increase downloads and related revenue.

Top ▲

Quick Start

Follow these simple steps to get up and running with the AskingPoint SDK in just minutes:

  1. Register App – Click “Register New App” from the Dashboard and fill out the required information.
  2. Download SDKGet it Here.
  3. Add AskingPoint.framework – Unzip the SDK and add or drag the AskingPoint.framework folder to the Frameworks folder of your Xcode project.
  4. Add AdSupport.framework – AskingPoint uses the AdSupport framework for various reasons, add it to your projects:
    • Apps supporting iOS prior to 6.0 can set it as Optional or Weak Linked.
    • Apps supporting iOS 6.0 and up can set it as Required.
  5. Add libsqlite3.dylib as a Linked Library.
  6. Call [ASKPManager startup:] from the Application Delegate with your AppKey. AppKeys are located on an App’s Settings Panel. To see it, select an App in the sidebar and click the Settings button.
  1. Register App – Click “Register New App” on the Dashboard and fill out the required information.
  2. Do one of the following:
    • Download the SDK, unpack the JAR file and manually add it to your project.
    • Or, Add a Dependency to your Android Studio build.gradle: compile ‘com.askingpoint.android:askingpoint:+’
    • Or, Add a Maven Dependency to your Eclipse project.
  3. Add the Required Properties to the Android Manifest (See Android SDK: Add To Project for details).
  4. Call AskingPoint.onStart() from each Activities onStart() method where AskingPoint is needed.
    AppKeys are located on an App’s Settings Panel. To see it, select an App in the sidebar and click the Settings
    button.
  5. Call AskingPoint.onStop() in each Activity where you called AskingPoint.onStart(). Place the call in the Activities onStop() method.

Top ▲

Add SDK To Project

To add the SDK to an Xcode Project:

  1. Download it from the iOS SDK section of these Docs.
  2. Unzip it.
  3. Drag or add the AskingPoint.framework folder to the projects Frameworks folder.
  4. Add Apple’s AdSupport.framework to the project:
    • If the App is using In-App Messages for Cross Promotion and you want download tracking
      this step is required.
    • Apps supporting iOS before 6.0 set the framework as Optional or Weak Linked.
    • Apps supporting iOS 6.0 and up can set the framework as Required.
  5. Add libsqlite3.dylib as a Linked Library.

When you are finished the project will look something like this:

Screen Shot 2015-08-25 at 9.37.51 AM

Eclipse Project

To add the SDK to an Eclipse Project:

  1. Download the SDK from the Android SDK section of these Docs.
  2. Add To Project – Unzip the Jar file and add it to the projects libs folder.

When you are finished the project will look something like this:

Add SDK to Android Project

Android Studio Project

To add the SDK to an Android Studio Project, add a dependency to your build.gradle dependency section:

dependencies {
    compile 'com.askingpoint.android:askingpoint:+'
}

Android Manifest

Next add the following strings to the Android Manifest.

<!-- REQUIRED: Add this at the top level. -->
<uses-permission android:name="android.permission.INTERNET"/>

<!-- OPTIONAL: Helps AskingPoint optimize when data is sent. -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<!-- OPTIONAL: Improves Location Accuracy. -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

<!-- REQUIRED: Add to the Application Section -->
<activity
    android:name="com.askingpoint.android.AskingPointActivity"
    android:configChanges=
        "keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
    android:theme="@android:style/Theme.Translucent"/>

Top ▲

Initializing iOS SDK

The AskingPoint SDK must be initialized early in the Application launch process. To initialize, call [ASKPManager startup:] near the start of [applicationDidFinishLaunching:] in your application delegate. Do not call [ASKPManager startup:] more than once in an App’s lifecycle.

AskingPoint AppKey

Initialization requires the AskingPoint App Key assigned to Apps when they are added to the AskingPoint Dashboard. You will find each Apps’s AppKey on its DashBoard Settings panel.

#import <AskingPoint/AskingPoint.h>

@implementation yourApplicationDelegate
-(BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)options
{
    [ASKPManager startup:@"put_askingpoint_app_key_here"];
    ...
}

Keeping Production And Debugging Analytics Separate

To keep Production analytics free of test data and or to be able to do more realistic testing without interrupting production users, add another App to the Dashboard and use that AppKey during testing.

Manage which key is used at build time by following this example:

#import <AskingPoint/AskingPoint.h>@implementation yourApplicationDelegate
-(BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)options
{
#ifdef DEBUG
    [ASKPManager startup:@"put_test_askingpoint_app_key_here"]; // Test App Key
#else
    [ASKPManager startup:@"put_production_askingpoint_app_key_here"]; // Production App Key
#endif
...
}

To use the above approach configure Xcode’s “Build Settings” to define DEBUG for Debug builds, but NOT for production. Your build settings should look as follows:

Xcode Project

xcode-7-build-settings

Top ▲

iOS Basics

Basic App Metrics

Once the AskingPoint SDK is properly installed in your App, it starts collecting automatically collecting the following metrics:

Versions of YOUR App: This is extracted from your Application Bundle or Manifest. Great for determining how long to keep legacy code.

Usage Data: New devices seen using the app, average usage frequencies and times, etc. Great way to keep an eye on real-time sales and downloads.

OS Version: Counts users running the App on various versions of a native OS. Useful for determining when to drop support for particular OS versions.

Device Type: Counts users running on various device types: iPad, iPhone, etc.

Device Models: Counts user populations running on specific hardware models.

Native Languages: Counts user populations using a particular native Device Language. Great for deciding what languages to do localizations for.

Device Locale: Counts your users in various Locales. Useful for determining geographic distribution, effectiveness and reach of marketing efforts.

TimeZones: Counts distribution of users by TimeZone. This is useful for timing time sensitive marketing or Push Notifications.

Top ▲

Setting Localized App Name

The AskingPoint SDK sometimes needs to display the App name to End Users on one of the pop-up widgets. For example, the Rating Booster widget.

By default the iOS SDK uses the first value it gets from the Application Bundle, in this order:

  1. The localized CFBundleDisplayName
  2. The CFBundleDisplayName
  3. The localized CFBundleName
  4. The CFBundleName

If you prefer to explicitly set it, call the following function immediately after the call to [ASKPManager startup:] in the Application Delegate:

[ASKPManager setLocalizedAppName:]

To see what name the AskingPoint SDK is currently using, call:

[ASKPManager localizedAppName]

By default the Android SDK uses the value set for label in the AndroidManifest.xml. If you prefer to explicitly set it, call the following function from the Activity that runs first in the App. If more than one Activity can run first, call it from all of them:

public static void setApplicationName(String applicationVersion)

To see what name the AskingPoint SDK is currently using, call:

public static String getApplicationName()

public class MyActivity extends FragmentActivity
{
    @Override
    protected void onStart() {
        super.onStart();
        AskingPoint.onStart(this, "your_app_key");
        AskingPoint.setApplicationName("App Name");
        ...
        String theAppName = AskingPoint.getApplicationName();
    }
}

Top ▲

Get SDK Version

There are two ways to get the version of the AskingPoint SDK at runtime:

  1. On the Console: When the App is launched in the Simulator or on a connected device.
  2. Programmatically: via the ASKPVersion string constant, defined in AskingPoint.h.
  3. Programmatically: via the AskingPoint.VERSION property.

Top ▲

Set Reported App Version

AskingPoint uses CFBundleVersionversionName defined in AndroidManifest.xml to report the version of Apps running on devices. This value is displayed on the Dashboard in the Devices and Versions section.

If you wish to explicitly set the reported value to something else, use this function:

[ASKPManager setAppVersion:]
[ASKPManager getAppVersion]

public static void setApplicationVersion(String version)
public static String getApplicationVersion()

NOTE: If you use this function but fail to keep it properly updated, subsequent versions of your App will be reported under an out of date version number. We recommend this feature be used only with automated build systems.

Call this function right after [ASKPManager startup:] in the ApplicationDelegate:

@implementation yourApplicationDelegate
-(BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)options
{
    [ASKPManager startup:@"your_app_key"];
    [ASKPManager setAppVersion:@"1.3"];
    ....
}
Call setApplicationVersion() in the Activities onStart(), right after the call to AskingPoint.onStart():

public class MyActivity extends FragmentActivity
{
    @Override
    protected void onStart() {
        super.onStart();
        AskingPoint.onStart(this, "your_app_key");
        AskingPoint.setApplicationVersion("123");
        ...
    }
}

Discontinue Manual Reporting

To stop manually reporting a version number, remove the call and the SDK will revert to using the default value.

Top ▲

User Data

The AskingPoint Library provides several convenience methods for recording additional information that may be useful for supporting your App users and understanding usage and demographic factors.

When set, the following values are displayed for each Feedback or Customer Support conversation displayed on the on the App’s Dashboard Feedback tab: UserName, Email, UserId.

[ASKPManager setUserName:(NSString *)name]
[ASKPManager setEmail:(NSString *)email]
[ASKPManager setUserId:(NSString *)acctId] // Should be unique for a person
[ASKPManager setAge:(int)age]
[ASKPManager setGender:(NSString *)gender] // “M” = male; “F” = Female
[ASKPManager setLocation:(CLLocation *)location]

public static void setUserName(String userID)
public static void setEmail(String userID)
public static void setUserID(String userID) // Should be unique for a person
public static void setAge(int age)
public static void setGender(String gender) // “M” = male; “F” = Female

Note: The value provided to setUserId should be unique for the person owning the device you are setting it on. This value, if set, can be used for integration with Customer Support and Issue Tracking services.

Example

@implementation yourApplicationDelegate
-(BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)options
{
    [ASKPManager startup:@"your_app_key"];
 
    [ASKPManager setUserName:"John Smith"];
    [ASKPManager setEmailAddress:userEmail];
    [ASKPManager setUserId:userAcctId];
    
    [ASKPManager setAge:29];
    [ASKPManager setGender:@"M"];
    [ASKPManager setLocation:(CLLocation*)location];
    ...
}
public class MyActivity extends FragmentActivity
{
    @Override
    public void someFunction()
    {
        // Put someplace in your App that has access to this type of information
        AskingPoint.setUserName("a_user_name_you_know_somehow");
        AskingPoint.setEmail("an_email_address_you_know_somehow");
        AskingPoint.setUserId("a_unique_user_id");

        AskingPoint.setAge(29);
        AskingPoint.setGender("M");
    }
}

Top ▲

Tags

Tags mark specific locations or events in Apps so that they can be targeted by AskingPoint features from the Dashboard. All AskingPoint features can work with Tags.

Tag usage is not required for features to work, but we strongly recommend using them so as to be able to present AskingPoint widgets at a time and place in App or workflow that does not annoy users.

Some Usage Examples

Example 1: You want to Tag the places in your App where the user finishes a game level or completes an action. These are happy moments and are good times to show Rating Booster.

Example 2: Your App has a feature that can be enhanced by an In-App purchase. If the place where the user starts using that feature is Tagged, you could send an In-App Message offering the item the 1st and 5th times users hit the Tag.

Understanding Tags

Basic Tag concepts:

  • Tags indicate Where, When and What in App’s work flow.
  • Whereas, Rules & Conditions indicate Who and When from amongst the user population.
  • Tags work together with Rules & Conditions. For example, if Rating Booster is targeting a Tag, its Rules & Conditions determine which devices should see it, but only users that hit the specified Tag will actually see it.
  • You can use more than one Tag with an AskingPoint feature.
  • And, more than one AskingPoint feature can target the same Tag. AskingPoint ensures users see only one widget at a time.

Tags Are Easy To Use

To Tag places and actions in Apps, put one of the following calls in the code where those actions are controlled:

[ASKPManager requestCommandsWithTag:@”tag”]
[ASKPManager requestCommandsWithTag:@”tag” completionHandler:(ASKPManagerTagRequestComplete)h]

/**
  * Convenience Completion Handler TYPE to notify when a command request is complete.
  *
  * NSString *tag - the tag that was requested.
  * ASKPCommand *command - the command to execute, or nil when nothing fires.
  * 
  * return - YES if the command was processed, NO to use the default handler.
  */
typedef BOOL (^ASKPManagerTagRequestComplete)(NSString *tag, ASKPCommand *command);

public static void requestCommandsWithTag(Context c, String tag)
public static void requestCommandsWithTag(Context c, String tag, OnTagCommandListener l)

public static interface OnTagCommandListener {
    /**
     * Callback to notify when a command request is complete.
     *
     * @param requestedTag Tag that was requested.
     * @param command Command to execute, or null if there was nothing available.
     * @return true if the command was processed, false to use the default handler.
     */
    boolean onTagCommand(String requestedTag, Command<?> command);
}

Tags are globally unique strings (within an App). Active Tags are displayed on the Dashboard above a features Tag editor, so choose tags that will remind you what they mean when you see them.

Tag Everything Important

We suggest using Tags liberally, and placing them throughout Apps where users enter and leave important places, or initiate and complete important actions. This makes it possible to target a location or activity from the Dashboard anytime and without the need for software updates.

Note: We designed Tags to ensure that heavy usage does not negatively impact App performance. See the SDK Help topic: Tag Performance FAQ.

Tags Without Callback

When it is not important to know (in code) if a Tag will fire, use:

    [ASKPManager requestCommandsWithTag:@"my_tag_for_this_location_in_the_app"];
    AskingPoint.requestCommandsWithTag(this, "my_tag");

Tags With A Callback

When it is important to know if something on the Dashboard is or is not firing for a particular Tag, use the next set of functions. These have a Completion Handler on iOS or a Listener on Android and always call your code to let it know if anything is or is not going to fire. Our generic name for these callbacks is Command Handlers.

Command Handlers are always called with arguments indicating if something is or is not firing, and if so which Dashboard feature fired. This gives your code an opportunity to:

  • Know what is firing.
  • Do something else when an AskingPoint widget is not firing.
  • Customize look and feel.
  • Change behaviors.

For example, using Tags with Command Handlers you could find out if Rating Booster just fired and if not, show an Interstitial Ad.

Command Handlers on Tags are called with the following information:

  • A null Command object if nothing fired on it, or…
  • A Command object with the command that is firing for that Tag.
  • The Tag triggering it.

See the SDK Help Topic: Command Handlers for a detailed explanation.

In iOS you implement Command Handlers as Block functions.

    [ASKPManager requestCommandsWithTag:@"tag" completionHandler:(ASKPManagerTagRequestComplete)h];

In Java you implement Command Handlers as listeners which implement OnTagCommandListener Interface.

    AskingPoint.requestCommandsWithTag(this, "my_tag", myOnTagListener);

Example – Using A Completion Handler

[ASKPManager requestCommandsWithTag:@"tag" completionHandler:^BOOL(NSString *t, ASKPCommand *c)
{
    if(c) {
        // Something on the Dashboard is firing for a Command at the time of this request
        // Return: YES or NO as per the Command Handler documentation.
    }
    else {
        // Nothing on the Dashboard fired for this Tag at the moment. Ok to do something
        // else. Return YES or NO as per the Command Handler documentation.
    }
    // Anything not caught by one of the above goes to the default handlers
    return NO;
}];
public class MyActivity extends FragmentActivity
{
    protected void doStuff() {
        AskingPoint.requestCommandsWithTag(this,"tag",new AskingPoint.OnTagCommandListener() {
            public boolean onTagCommand(String requestedTag, Command<?> command) {
                if(command != null) {
                    // Something on the Dashboard fired a Command at the time of this request
                    // Return true or false as per the Command Handler documentation.
                }
                else {
                    // Nothing on the Dashboard fired for this tag now. Do something
                    // else here then return false.
                    return false;
                }
                // Anything not caught by one of the above goes to the default handlers
                return false;
            }
        });
    }
}

Testing Tags

Testing Tags is easy. After you’ve placed Tags in an App, select the App you’re testing
in the sidebar and follow these steps:

  1. Go to the App’s settings panel.
  2. Select the widget you want to test.
  3. Add that Tag to the widget’s Tag editor.
  4. Open its test panel and fire a test for the device or simulator you’re testing on.
  5. Perform the action associated with the Tag you’re testing.

Tests fire nearly immediately and should NOT require App restart.

Top ▲

Tag Performance

AskingPoint recommends liberal use of Tags. We worked hard to ensure this does not negatively impact App performance. We accomplish this by periodically informing Apps which Tags are actually targeted by something on your Dashboard. This enables the SDK to limit communication with  AskingPoint servers to only those Tags being targeted.

FAQ

  1. Does Tag usage negatively impact App performance? No. As discussed above, App’s only communicate with AskingPoint about the Tags currently used on their Dashboard by an AskingPoint feature.
  2. Does Tag usage slow down App launch or portions of of the user interface? No. The SDK communicates with AskingPoint asynchronously, and neither does it block the UI.
  3. How quickly do servers respond to requests for Tags? In most cases the interval between the the request for a Tag and the response is virtually instant. However, your results may vary as round trip communication is subject to the quality and latency of a device’s connection.
  4. Does Tag usage generate a lot of network traffic? No. Our network analysis shows that most Commands sent to Apps are approximately 1k in size. Most of that 1k is SSL overhead and could in future be optimized out.

Top ▲

Custom Events

AskingPoint provides 2 functions for defining Custom Events. Custom Events are useful for tracking the ways
in which Apps and App features are used. Eg, which features are used and/or what options are selected.

1) Event with Name

This is useful for tracking events where simply knowing that something happened is valuable. For example that a
particular feature or button was selected.

[ASKPManager addEventWithName:]

public static void addEvent(String name)

2) Event with Name And Data

This is useful for tracking events and also collecting additional data associated with the event. For
example what path a user took in a game and what weapons they had at the time.

[ASKPManager addEventWithName:andData:]

Data types allowed in the NSDictionary object are: NSNumber, NSString, CLLocation.

public static void addEvent(String name, Map<String, Object> data)

Data types allowed in the Map object are: java.lang.String, java.lang.Number and android.location.Location.

Anything else will get stringified and truncated to 500 characters.

Custom Event Length Limits

There are limits on the length of Custom Event properties, they are as follows:

  • Name – Custom Event names can have a maximum length of 200 characters.
  • Keys – Keys in Dictionaries/Maps can have a maximum length of 200 characters.
  • Values – Values Dictionaries/Maps can have a maximum length of 500 bytes/characters.
#import <AskingPoint/ASKPManager.h>

-(void)viewDidAppear:(BOOL)animated
{
    /* Named Custom Event */
    [ASKPManager addEventWithName:(NSString *)@"the_game_view_was_used"];
}

-(void)myGameFunction
{
    NSDictionary *dict = @{@"Game_Path":@"middle_way", @"Weapon":"blaster" };
        
    /* Named Custom Event with data */
    [ASKPManager addEventWithName:@"game_path" andData:dict];
}
public class MyActivity extends FragmentActivity
{
    public void myGameFeature()
    {
        // Named Custom Event
        AskingPoint.addEvent("the_game_featurew_was_used");
        
        //Named Custom Event with data
        HashMap<String, Object> data = new HashMap<String, Object>();
        data.put("Game_Path", "middle_path");
        data.put("Weapon", "blaster");
        AskingPoint.addEvent("the_game_featurew_was_used", data);
    }
}

Top ▲

Timing Usage

AskingPoint provides 4 methods for measuring user engagement and timing how long features, functions or parts of Apps are used:

1) Timed Event with Name

Calls to these should be placed at the point just before where the feature being timed starts and just after where it stops.

[ASKPManager startTimedEventWithName:]
[ASKPManager stopTimedEventWithName:]

public static void startTimedEvent(String name)
public static void stopTimedEvent(String name)

2) Timed Event with Name AND Data

These functions make it possible to include relevant data about the feature being timed.

[ASKPManager startTimedEventWithName:andData:]
[ASKPManager stopTimedEventWithName:andData:]

public static void startTimedEvent(String name, Map<String,Object> data)
public static void stopTimedEvent(String name, Map<String,Object> data)

Data types allowed in the NSDictionary object are: NSNumber, NSString, CLLocation.
Data types allowed in the Map object are: java.lang.String, java.lang.Number and android.location.Location.

Anything else will get stringified and truncated to 500 characters.

Note: You can begin timing with either start function and end timing using either stop function.

Custom Event Length Limits

There are limits on the length of Custom Event properties, they are as follows:

  • Name – Custom Event names can have a maximum length of 200 characters.
  • Keys – Keys in Dictionaries/Maps can have a maximum length of 200 characters.
  • Values – Values Dictionaries/Maps can have a maximum length of 500 bytes/characters.
#import <AskingPoint/ASKPManager.h>
-(void)viewDidAppear:(BOOL)animated
{
    // Start Timed Event
    [ASKPManager startTimedEventWithName:(NSString *)@"Application_Settings"];
}
-(void)viewDidDisappear:(BOOL)animated
{
    // Stop Timed Event
    [ASKPManager stopTimedEventWithName:(NSString *)@"Application_Settings"];
}

And / Or…

-(void)viewWillAppear:(BOOL)animated
{
    // Some data
    NSDictionary *dict = @{@"Feature_1":@"OFF", @"Feature_2":@"ON"};

    // Start Time Event with data
    [ASKPManager startTimedEventWithName:(NSString *)@"Application_Settings" andData:dict];
}
-(void)viewWillDisappear:(BOOL)animated
{
    // Some more data
    NSDictionary *dict = @{@"Feature_1":@"OFF", @"Feature_2":@"ON"};

    // Stop Timed Event and send some more data
    [ASKPManager startTimedEventWithName:(NSString *)@"Application_Settings" andData:dict];
}
public class MyActivity extends FragmentActivity
{
    public void gameFeatureX() {
        // Start timing how long this game feature is used
        AskingPoint.startTimedEvent("game_feature_x_timer");

        // Do stuff
        ...

        // Done doing stuff, stop timing it.
        AskingPoint.stopTimedEvent("game_feature_x_timer");
    }
    public void gameFeatureY() {
        // Start timing how long this game feature is used and which weapon
        HashMap<String, Object> data = new HashMap<String, Object>();
        data.put("weapon", "master_blaster");
        AskingPoint.startTimedEvent("game_feature_y_timer", data);

        // Do stuff
        ...

        // Done doing stuff, stop timing it.
        AskingPoint.stopTimedEvent("game_feature_y_timer");
    }
}

How Timing Durations Are Calculated

The timing functions don’t use any actual timers, they simply log time stamps for the start and stop of the named events. These are sent to our servers where the duration calculations are done.

The rules for determining duration are as follows:

  • If you start timing something but never fire stop, we don’t count it.
  • If you start timing something and do fire fire stop, but the App went into the background (iOS) or all Activities stopped (Android), between when start and stop are fired, we divide it into TWO events.
  • Timed events have no effect on other timed events. We assume concurrency.

Top ▲

Customer Support Widget iOS

Programming is NOT necessary to use Customer Support widget to collect feedback during the Rating Booster prompt sequence. That is controlled from the Dashboard Rating Booster settings.

The SDK provides functions that enable Customer Support to be integrated into Apps to provide sophisticated two way dialog capabilities and to allow end users to report issues or request features.

Note: We are happy to work with customers to integrate the Customer Support widget with other Issue tracking services. Contact AskingPoint Support for details.

About Customer Support Widget

Starting with SDK v4.1 Customer Support widget supports two way, chat style conversations. It includes Notifications that can be used to indicate to end users you’ve responded via badges and other visual queues.

ASKPCustomerSupportViewController – A standard UINavigationController that collects end user input and displays your responses from the Dashboard. It can be used in all the ways that any other Navigation Controller can be used. E.g. present it from a button or parent it in a view like a TabView.

Responses from Dashboard sent via Push Notifications (optional) – Push Notifications can be used to alert Apps which are not in the foreground, that you’ve responded from the Dashboard and also to facilitate live two way conversations via CustomerSupport widget. Their use is optional, but recommended for the best Customer Support experience.

ASKPFeedbackUnreadCountChangedNotification – An NSNotification from the NSNotificationCenter. These are sent by the SDK whenever responses are available from the App’s AskingPoint Dashboard. They’re triggered most immediately when Push is used to deliver your responses, but are also sent if the App is in the foreground and the SDK sees a new response while requesting Commands from AskingPoint.

[ASKPManager unreadFeedbackCount] – A convenience method that returns the count of un-read feedback.

 

Using Response Notifications

ASKPCustomerSupportViewController is a powerful tool enabling Apps to collect feedback from end users and offer advanced levels of support. To take full advantage of its capabilities, familiarize yourself with the various related Notifications:

  1. Push Notifications – When Apps register for Push Notifications and upload Push Certificates to the AskingPoint Dashboard, your responses are automatically Pushed back to the end user device (users must allow Push Notifications from your App). This has the following benefits and uses:
    • App users can be notified about responses more quickly when Apps are in the foreground and also when Apps are not in the foreground.
    • When Apps are opened in response to Pushed responses, the Customer Support widget is automatically opened to display them and allow further dialog.
    • Push messages also enable live two way conversations via the ASKPCustomerSupportViewController.
  2. NSNotifications – These are sent by the SDK while Apps are running. You can register to recieve them to provide visual indicators that responses are available or to show ASKPCustomerSupportViewController. Typical uses are:
    • To badge/unbadge a button that displays ASKPCustomerSupportViewController.
    • To badge/unbadge a tab or view that shows the ASKPCustomerSupportViewController.
    • To display ASKPCustomerSupportViewController on App launch when Push is not used or availble, and responses are available from the Dashboard.

Examples

Use Customer Support Widget In A View

ASKPCustomerSupportViewController is a NavigationController and can be used like any other view controller. This example shows how to add it to a Tab:

UITabBarController *tabBarController = [UITabBarController new];
tabBarController.viewControllers = @[ASKPCustomerSupportViewController new];

Present Customer Support Widget In Response To An Action

ASKPCustomerSupportViewController can be shown in response to an action, for example a button action, to offer App users a means of getting support, providing feedback or reporting bugs.

-(void)somefunction
{
    // Attach CustomerSupport widget to a button
    [b addTarget:self action:@selector(showCustomerSupportWidget) forControlEvents:UIControlEventTouchDown];
    ....

    // or, show CustomerSupport widget if there are some un-read
    // feedback responses sent from the Dashboard or other integrated service.
    if([ASKPManager unreadFeedbackCount] > 0)
        [self showCustomerSupportWidget];
}
-(void)showCustomerSupportWidget
{
    ASKPCustomerSupportViewController *fbController = [ASKPCustomerSupportViewController new];
    [self presentViewController:fbController animated:YES completion:NULL];
}

Use The Response Notifications

Register to recieve ASKPFeedbackUnreadCountChangedNotification from the Notification Center to be able to notify end users while they use your Apps that you have responded. This can be used in a variety of ways:

  • Badge a Tab or View to indicate there is a Feedback or Support response.
  • Show the widget when your response arrives.
  • Show an alert that your response has arrived.
// Register for the Un-read Feedback Notification
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myUnReadResponseHandler:)
    name:ASKPFeedbackUnreadCountChangedNotification object:nil];

// Get the un-read response count and use it.
-(void)myUnReadResponseHandler:(NSNotification *)note
{
    NSDictionary *data = note.userInfo;
    NSUInteger cnt = [(NSNumber *)[data objectForKey:ASKPFeedbackUnreadCountUserInfoKey] unsignedIntegerValue];

    // Provide visual queues
    [self badgeTabItemWithUnreadResponseCnt:cnt];
    [self badgeButtonWithUnreadResponseCnt:cnt];

    // Or, Show Feedback widget
    ASKPCustomerSupportViewController *csController = [ASKPCustomerSupportViewController new];
    [self presentViewController:csController animated:YES completion:NULL];
}

Top ▲

Rating Widget Standalone

In addition to being controlled automatically from the Dashboard, Rating Booster rating widget can be called directly from within Apps via the SDK anytime. The main reason you might want to do this is to make it available on a button to allow users to show their appreciation anytime they wish.

When used this way, Rating Booster will:

  1. Use any Custom Prompts you’ve added to the Dashboard.
  2. Use our default prompts for languages you didn’t customize.
  3. Obey the Rating Booster Dashboard setting to: Use Store Kit (iOS Only).

-(BOOL)canShowRatingPrompt
-(void)showRatingPrompt

public static boolean canShowRatingPrompt(Context context)
public static boolean showRatingPrompt(Context context)

canShowRatingPrompt – Returns a boolean indicating if the SDK is ready to show the Rating prompt. There is a very short period of time when Apps first launch where AskingPoint servers update the App with your Custom prompts or our default prompts for a devices language. And also, if you’ve set it to use Store Kit or not.

showRatingPrompt – shows the rating prompt. When the Rating Widget is shown in this way:

  • It does not include a Remind Me Later button.
  • It will ignore Dashboard settings to use the Feedback widget.

Example

UIButton *b = [UIButton buttonWithType:UIButtonTypeCustom];
[b addTarget:self action:@selector(rateAppAction) forControlEvents:UIControlEventTouchDown];
    
    ...
    
-(void)rateAppAction
{
    if([ASKPManager canShowRatingPrompt])
        [ASKPManager showRatingPrompt];
}
public class MyActivity extends FragmentActivity
{
    @Override
    public void someFunction()
    {
        if(AskingPoint.canShowRatingPrompt(context)
            AskingPoint.showRatingPrompt(context);
    }
}

Top ▲

Push Messaging iOS

To receive Push messages sent from the AskingPoint Dashboard follow the instructions provided in the Apple Documentation for Registering for Remote Notifications. Apps should Register for Remote Notifications after the call to initialize the AskingPoint SDK.

Example

The following example illustrates how to register for Remote Notifications on iOS 8.0 and later, as well as earlier versions of iOS:

#import <AskingPoint/AskingPoint.h>
@implementation yourApplicationDelegate
-(BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)options
{
    [ASKPManager startup:@"Place_your_App_Key_here"];
    ...
    
    //
    // Register for Remote Notifications. Place the call to Register near the end
    // of the [application:didFinishLaunchingWithOptions:] and after you initialize
    // the AskingPoint sdk.
    //
    // NOTE: Only call this once in an App. If already called for some other reason
    // no need to call it again.
    //
    if([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
        // iOS 8 and later
        UIUserNotificationType types = UIUserNotificationTypeAlert | UIUserNotificationTypeSound;
        [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:types categories:nil]];
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    }
    else {
        // Before iOS 8
        UIRemoteNotificationType types = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound;
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes:types];
    }

}

Note: Apps should Register for Remote Notifications only once. If your App already registers for some other service, it is not necessary to call this again.

  • If you’re not using Push and don’t want users to be prompted to allow Push Notifications, don’t call [registerForRemoteNotificationTypes:].
  • You must also upload the relevant Push Certificates to the App’s Push Message Dashboard. For help see the Dashboard documentation for Push Messages.
  • Custom Alert Sounds require either UIUserNotificationTypeSound or UIRemoteNotificationTypeSound, depending on the version of iOS.

For help trouble shooting Push Notifications, see the Dashboard documentation Push Trouble Shooting.

Top ▲

Overview – Handling Feedback Notifications

If your App uses Feedback widget during the Rating Booster prompt sequence or the Customer Support widget, there are a few things to be aware of with respect to handling notifications that inform Apps about replies from the dashboard.

Push Notifications

Feedback responses from the Dashboard are sent to Apps via Push messages when Push is enabled on the App’s Push settings tab. Push notifications with responses are seen when the App is in the background. When end-users tap the Push Notification the SDK automatically handles opening the App and presenting the response on the device.

Push notifications will also cause an NSNotification (iOS) or an OnUnreadFeedbackCountChangeListener to be fired within the App more quickly, and so that Apps in the foreground can handle Feedback responses.

NSNotifications/OnUnreadFeedbackCountChangeListener

NSNotifications (iOS) and OnUnreadFeedbackCountChangeListener (Android) are fired while Apps are in the foreground. You can register to get them or the callback to facilitate providing users with visual indicators that responses are available and to display them. Typical uses are:

  • To badge/unbadge something in the App and indicate a response to the end users feedback is available.
  • To automatically display your responses to feedback e.g. at App launch or some other time.

For complete documentation see the SDK help topic the Customer Support Widget.

Top ▲

Local Notifications

Starting with iOS v4.1.x Local Notifications can be created, localized, scheduled and sent from your Apps Dashboard. Local Notifications are great for re-enagement and other things. For complete details on the benefits and how to send them from the Dashboard see the Dashboard Documentation: Local Notifications.

Example

Versions of iOS prior to 8.x do not require Apps to Register to schedule Local Notifications. Versions of iOS 8.0 and later require Registration, the following example illustrates how to Register:

#import <AskingPoint/AskingPoint.h>
@implementation yourApplicationDelegate
-(BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)options
{
    [ASKPManager startup:@"Place_your_App_Key_here"];
    ...
    //
    // Register for Local Notifications. Place the call to Register near the end
    // of the [application:didFinishLaunchingWithOptions:] and after you initialize
    // the AskingPoint SDK.
    //
    // NOTE: Only call this once in an App. If already called for some other reason
    // no need to call it again.
    //
    if([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
        // iOS 8 and later
        UIUserNotificationType types = UIUserNotificationTypeAlert | UIUserNotificationTypeSound;
        [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:types categories:nil]];
    }
}

Note: Apps should Register for Local Notifications only once. If your App already calls registerUserNotificationSettings for some other service (including Push), it is not necessary to call this again.

Top ▲

iOS Advanced

Data Transmission

The AskingPoint SDK sends data when Apps start or come into the foreground, and when they shut down or go into the background. Most Apps are used for short periods of time and sending data at these times is sufficient.

If your App is used in the foreground for long periods of time and you wish to send data more frequently, use the following:

[ASKPManager sendIfNeeded]

AskingPoint.flush()

When called it sends as much cached data as possible. We do not recommend calling it too frequently.

Note: Calling this function has a limited effect on the appearance of analytics on the dashboard. Data received by our servers is cached and processed on various periodic cycles. Some in near real-time with others at end of day.

Top ▲

Payload

Payload makes it possible to deliver blobs of JSON data to Apps from the Dashboard or your servers, in real-time (contact sales about our serverside Payload API).

Payload uses Rules & Tags (like all other AskingPoint features) to enable you to send data to some or all users and at various places and times in App workflow. It makes it possible for Apps to be more flexible in the way they work for segments of the App user population and at Tagged places in Apps. And, you can do this while Apps are deployed in the field, without having to release software update.

Payload Command Handlers

Payload uses Command Handlers like other AskingPoint widgets. See the SDK Help topic: Command Handlers for a full discussion.

Return Values

Payload Command Handlers must return a boolean value of either YES or NO. When YES, the Command must be reported complete after the associated activity finishes.

Base your Command Handler return values on the following considerations:

  • YES / true: When the Payload Command Handler does UI and/or it is necessary to temporarily prevent other AskingPoint Commands that might pop-up an AskingPoint widget.
  • NO / false: When the Payload Command Handler is doing something in the background and/or it does not matter if other AskingPoint commands pop-up a widget.
  • NO / false: When Command Handlers set on Tags are passed nil/null command objects because nothing is firing for the Tag at that time.

When the Command Handler returns YES, use the following function on the Command object to report that
the Payload task is finished:

[command reportComplete];
command.complete();

Getting Your JSON Data In The App

The AskingPoint SDK parses JSON data sent from the Dashboard and hands it to Apps in an easy to use form.

On iOS the data is passed as an NSDictionary object containing any of the following data types: NSString, NSArray, NSNumber, NSDictionary.
On Android the data is passed as a JSONObject containing data in valid JSONObject form (See the JSONObject JavaDocs for details).

Example: A Payload Command Handler

#ifdef DEBUG
    [ASKPManager startup:@"my_test_app_key"]; // Test API_Key
#else
    [ASKPManager startup:@"my_production_app_key"]; // Release API_Key
#endif
[ASKPManager sharedManager].commandHandler = ^BOOL (ASKPCommand *command) {
    if(command.type == ASKPCommandPayload) {
        NSLog(@"A Payload");
        NSLog(@"It fired for Tag: %@", command.requestedTag);
        if([command.data isKindOfClass:[NSDictionary class]]) {
            NSLog(@"My data for key:%@",[command.data objectForKey:@"My_KEY"]);
            _myRemoteControlThingController.command = command;return YES; // Return YES to prevent other widgets showing
        }
        else
            NSLog(@"Data sent from the Dashboard not handled by this code.");
    }
    else
        NSLog(@"It's a Command for some other widget");return NO; // Return NO or YES as per the discussion above.
};
//
// MyPayloadController
//
-(void)viewDidDisappear:(BOOL)animated
{
    // The Command Handler returned YES, so must report the command complete
    [_command reportComplete];
}
public class MyActivity extends FragmentActivity {
    ...
    @Override
    protected void onStart() {
        super.onStart();
        AskingPoint.onStart(this, "app_key");
        AskingPoint.setOnCommandListener(new AskingPoint.OnCommandListener() {
            public boolean onCommand(Command<?> command) {
                if(command.type == Command.Type.PAYLOAD) {
                    System.out.println("Remote Control fired for Tag: " + command.requestedTag);
                    new MyPayloadHandler(command);
                    return true;
                }
                // Let the default handler process anything unknown
                return false;
            }
        });
    }
}
public class MyPayloadHandler {
    private void doMyRemoteControlThing() {
        // Get JSON data sent from Dashboard
        JSONObject jsonData = command.data;

        // Do stuff with it
        ...

        // Done handling Payload, report the command complete
        command.complete();
    }
}

Top ▲

Command Handlers

Command Handlers provide Apps an opportunity to customize AskingPoint widgets. They are blocks of code you can write and which get called when something on the Dashboard fires a command in the App. For example: Rating Booster or an In-App message is about to show. They can be useful when you want to know if something is about to happen (or not) so that you can do something else or change something.

Setting Command Handlers

Command Handlers are implemented as Block functions on iOS and Listeners on Android and there are two ways to set them:

  1. In-Line when Tagging locations in Apps.
  2. Globally on the SDK after initialization.
typedef BOOL (^ASKPManagerTagRequestComplete)(NSString *tag, ASKPCommand *command)
typedef BOOL (^ASKPManagerCommandHandler)(ASKPCommand *command)

// Inline
+(void)requestCommandsWithTag:(NSString *)t completionHandler:(ASKPManagerTagRequestComplete)h

// Global
@property(nonatomic,copy) ASKPManagerCommandHandler commandHandler
public static interface OnTagCommandListener
public static interface OnCommandListener

// Inline
public static void requestCommandsWithTag(Context c, String tag, OnTagCommandListener l)

// Global
public synchronized static void setOnCommandListener(OnCommandListener l)

Command Handler Calling Order

When something on the Dashboard fires and multiple Command Handlers are set in the App, they are called in the following order:

  1. First: those set inline on a Tag that is firing.
  2. Next: the global handler, if one was set on the SDK.
  3. Finally: the default (built-in) handlers if the previous two pass it through or are not set.

In-Line Command Handlers On Tags

The primary benefit of In-Line Command Handlers is:

  • They always get called and can be used to find out if something did or did not fire for a particular Tag.
  • They are called at the Tagged location in code where other data and variables which might be needed are available.

These are useful when you would like to do something else if a Dashboard widget does NOT fire at a Tag. For example: If Rating Booster or an In-App message is NOT going to show, let your Ad Provider show an interstitial Ad.

Global Command Handlers

If Global Command Handlers are set they will be called after In-Line Command Handlers. They are called only if a command fires and an In-Line Handler did not already process it.

They are useful when:

  • You don’t need to know that a command did not fire.
  • You want to provide a global customization for an AskingPoint widget, e.g. change the appearance of Rating Booster regardless of how triggered.

Default Command Handlers

Default Command handlers are built-in to the SDK by AskingPoint and are invoked automatically when you don’t set any of your own Command Handlers.

Command Handler Return Values

Command Handlers must return a boolean value. The rules for this are, return:

  • YES / true: When your Command Handler is processing a Command and does not want another Command Handler to process it. This stops processing for the Command at that point.
  • NO / false: When your Command Handler is not processing a particular Command. This passes the command to the next handler.
  • NO / false: When Command Handlers set on Tags are passed null command objects because nothing is firing for the Tag at that time.

Reporting Commands Complete

When Command Handlers return YES / true they are telling the AskingPoint default handlers that they are taking responsibility for presentation and button handling and not to show the default widget. In this case your Handler must notify AskingPoint when the user has completed the activity by calling the appropriate function on the Command object:

  • Commands without buttons – [command reportComplete]
  • Commands with buttons – [command reportCompleteWithButton:(ASKPAlertButton*)button]
  • Commands without buttons – command.complete()
  • Commands with buttons – command.complete(Button b)

Not all Commands have buttons that are accessible to your code. When they do, the Command object has a Button property that contains the Buttons you are responsible for handling. When buttons are present, pass the selected button with the call to report completion.

See the SDK Help Topic: Widget Customization for examples of Command Handlers performing the most commonly requested customizations.

Command Handler Object And Type References

For the most complete and current Objects and Type documentation, see the headers in the iOS SDK or the JavaDocs included with the Android version of the SDK.

Examples

These following illustrate a basic Command Handler template:

/*
 *   In-Line Command Handler on a Tag
 */
[ASKPManager requestCommandsWithTag:@"tag" completionHandler:^BOOL(NSString *t, ASKPCommand *c) {
    if(c != nil) {
        // Something on the Dashboard fired for this Tag.
        // Return YES if you want to stop processing and do something custom.
        // Return NO if you want the next or default handler to process it.
    }
    else {
        // Nothing on the Dashboard fired for this Tag.
        // Do something else here like show an Interstitial Ad
        return NO;
    }
    // Probably an error, something above did not return properly.
    // Return NO and let the default handle it.
    return NO;
}];
/*
 * Global Command Handler set on the AskingPoint SDK
 * The return value for each of the cases depends on what you are doing
 * see the heading Command Handler Return Values for details.
 */
[ASKPManager startup:@"my_app_key"];
[ASKPManager sharedManager].commandHandler = ^BOOL (ASKPCommand *command) {
    if(command.type == ASKPCommandAlert) {
        if(command.alertType == ASKPAlertRating) {
            NSLog(@"Rating Booster");
        }
        else if(command.alertType == ASKPAlertMessage) {
            NSLog(@"In-App Message");
        }
        else if(command.alertType == ASKPAlertFeedbackOrRatingIntro)
            // This is only sent when Request Feedback is turned on
            // for Rating Booster.
            NSLog(@"Show Rating/Feedback Do You Like App Intro");
        else
            NSLog(@"An AlertType this App does not know about.");
    }
    else if(command.type == ASKPCommandWeb)
        // Polls can't be customized and this is mainly
        // to notify thats what is firing.
        NSLog(@"A Poll");
         
    else if(command.type == ASKPCommandPayload)
        NSLog(@"A JSON Payload");
                
    else if(command.type == ASKPCommandFeedback)
        NSLog(@"The Feedback widget is about to show");
        
    else
        NSLog(@"An unknown widget fired");
    
    // Let the default handler process anything unknown
    return NO; 
};
//
// Some place in code Tagged with an In-Line Command Handler
//
AskingPoint.requestCommandsWithTag(this, "my_tag", new AskingPoint.OnTagCommandListener() {
    public boolean onTagCommand(String requestedTag, Command<?> command) {
        if(command != null) {
            // Something on the Dashboard fired for this Tag.
            // Return true if you want to stop processing and do something custom.
            // Return false if you want the next or default handler to process it.
        }
        else {
            // Nothing on the Dashboard fired for this Tag.
            // Do something else here like show an Interstitial Ad
            return false;
        }
        // Probably error, something above did return properly.
        // Return false and let the default handle it.
        return false;
    }
});
/*
 * Define a Global Command Handler inline or elsewhere.
 * The return value for each of the cases depends on what you are doing
 * see the heading Command Handler Return Values for details.
 */
public class MyGlobalCommandListener implements AskingPoint.OnCommandListener {
    public boolean onCommand(Command<?> command) {
        switch(command.type) {
            case WEB:
                // Polls can't be customized and this is mainly
                // to notify thats what is firing.
                System.out.println("A Poll");
                break;
            case ALERT:
                if(((AlertCommand)command).alertType == AlertCommand.AlertType.RATING) {
                    System.out.println("Rating Booster");
                }
                else if(((AlertCommand)command).alertType == AlertCommand.AlertType.MESSAGE) {
                    System.out.println("In-App Message");
                }
                break;
            case PAYLOAD:
                System.out.println("JSON Payload");
                break;
            default:
                System.out.println("An unknown widget fired");
                break;
        }
        // Let the default handler process anything unknown
        return false;
    }
}

/* Set the Global Command Listener on AskingPoint SDK:
 *    - After initialized
 *    - And before it is likely to be needed.
 *    - This only has to be done once in an App.
 */
MyGlobalCommandListener listener = new MyGlobalCommandListener();
AskingPoint.setOnCommandListener(listener);

Top ▲

Widget Customization

Customizing AskingPoint widgets primarily involves writing a simple Command Handler to process Commands for the feature being customized. When it gets called your App has an opportunity to make changes. See the SDK Help Topic: Command Handlers for details.

Using these capabilities it’s possible to customize various aspects of AskingPoint widgets and still continue to control them from the Dashboard.

What can be customized:

  • Rating Booster:
    • Appearance – Use AskingPoint translations in your own Rating Widget.
    • Prompts – Do this from Rating Booster Dashboard settings, rather than in code.
    • Get User Response – Get notified which button a user selected. See the SDK Help topic: Widget Button Selection.
  • Messages:
    • Look & Feel – Use the localized message text sent from your Dashboard in a message widget with your App’s look and feel.
    • Get User Response – Get notified which button was selected on a Message. See the SDK Help topic: Widget Button Selection.

Reporting Activities Complete

When writing Command Handlers for custom widgets that take responsibility for displaying messages or Rating Prompts, at the end of the operation you must report that a Command completed and also the button selection. See the SDK Help topic: Command Handlers for details.

Also, note the following:

  • Failure to report Commands complete will cause devices to be prompted again.
  • Failure to report Commands complete will prevent other types of Dashboard commands from being sent for up to 24 hours.
  • Custom controllers should NOT process URLs on buttons. E.g. take the user to an App Rating Page. The AskingPoint SDK processes all button URLs after Commands are reported complete.

Examples

The following examples illustrate the most common customization tasks.

Customizing Rating Booster Prompts

Use the Rating Booster dashboard prompt editor to customize Rating Booster prompt and button text.

Example 1: Customizing Rating Booster Appearance

Apps with a heavily themed look can control their own Rating Widget from the Dashboard and feed it the AskingPoint default prompts or ones that you customized using the dashboard prompt editor.

[ASKPManager startup:@"my_test_app_key"];         // Test API_Key
[ASKPManager sharedManager].commandHandler = ^BOOL (ASKPCommand *command) {
    if(command.type == ASKPCommandAlert) {
        if(command.alertType == ASKPAlertRating) {
            MyRatingWidget *ratingWidget = [[MyRatingWidget alloc] init:command];
            ratingWidget.delegate = self;                
            [ratingWidget show];
            return YES;                         // Displaying my widget 
        }
    }
    return NO;      // Display default widget for everything else
};

// Then in your rating widgets delegate you must report the process complete
-(void)myRatingWidgetDismissedWith:(ASKPAlertButton *)b forCommand:(ASKPCommandAlert *)c
{
    [c reportCompleteWithButton:b];
}
public class MyGlobalCommandListener implements AskingPoint.OnCommandListener {
    public boolean onCommand(Command<?> command)
    {
        if(command.type == Command.Type.ALERT) {
            AlertCommand c = (AlertCommand)command;
            if(c.alertType == AlertCommand.AlertType.RATING) {
                MyRatingWidget rw = new MyRatingWidget(c);
                return true;    // Don't show default widget, showing mine
                                // In your rating widget when called back with
                                // button selection, call complete on the Command
                                // Object and pass it the selected button
            }
        }
        return false;   // Show default widgets for everything else
    }
}

// Set the Global Command Handler on the AskingPoint SDK
MyGlobalCommandListener listener = new MyGlobalCommandListener();
AskingPoint.setOnCommandListener(listener);

IMPORTANT! Don’t forget to have custom widgets report Commands complete with button selection, as explained above and in the Help topic on Command Handlers.

The following code snippets illustrate one way a custom controller could handle button selection.

//
// MyRatingWidget Controller
//
-(id)init:(ASKPCommand *)command
{    
    // Your controller should associate the buttons in the Command object
    // with your own widgets buttons.
    
    _cmd = command;
    for(ASKPAlertButton *button in _cmd.buttons) {
        switch(button.ratingType){
            case ASKPAlertRatingNo: [myButtonArray addObject:myNoButton]; break;
            case ASKPAlertRatingRemindMe: [myButtonArray addObject:myRemindMeButton]; break;
            case ASKPAlertRatingYes: [myButtonArray addObject:myRateButton]; break;
        }
    }    
}
 
-(void)buttonSelected:(UIButton *)button
{
    // When a button is selected, call reportCompleteWithButton and pass it the
    // AskingPoint button object corresponding to the button selected on your widget.

    int i = [myButtonArray indexOfObject:button];
    [_cmd reportCompleteWithButton:[_cmd.buttons objectAtIndex:i]];
}
public class MyRatingWidget
{
    AlertCommand command;
    MyButton b_yes, b_no, b_remind;

    public MyRatingWidget(AlertCommand command) {
        this.command = command;
        for (AlertCommand.Button b : this.command.buttons) {
            switch (b.type) {
                case b.Type.RATING_YES:
                    b_yes.askingPointButton = b;
                    break;
                case b.Type.RATING_NO::
                        b_no.askingPointButton = b;
                    break;
                case b.Type.RATING_REMINDME::
                        b_remind.askingPointButton = b;
                    break;
            }
        }
    }
    public buttonSelected(MyButton b){
        // When a button is selected on your widget
        // report Command complete and notify of
        // Button selection
        this.command.complete(b.askingPointButton);
    }
}

Example 2: Using A Custom Widget To Display In-App Messages

The procedure for using a custom Message widget to display In-App Messages is similar to Example 1.

#ifdef DEBUG
    [ASKPManager startup:@"my_test_app_key"];         // Test API_Key
#else
    [ASKPManager startup:@"my_production_app_key"];   // Release API_Key
#endif
    [ASKPManager sharedManager].commandHandler = ^BOOL (ASKPCommand *command) {
        if(command.type == ASKPCommandAlert) {
            if(command.alertType == ASKPAlertMessage) {
                MyMessageWidget *messageWidget = [[MyMessageWidget alloc] init:command];
                messageWidget.delegate = self;
                [messageWidget show];
                return YES;                         // Displaying my widget 
            }
        }
        return NO;      // Display default widget
    };
public class MyGlobalCommandListener implements AskingPoint.OnCommandListener {
    public boolean onCommand(Command<?> command)
    {
        if(command.type == Command.Type.ALERT) {
            AlertCommand c = (AlertCommand)command;
            if(c.alertType == AlertCommand.AlertType.MESSAGE) {
                MyRatingWidget rw = new MyMessageWidget(c);
                return true;    // Don't show default widget, showing custom
                                // In your message widget when called back with
                                // button selection, call complete on the Command
                                // Object and pass it the selected button
            }
        }
        return false;   // Show default widgets for everything else
    }
}

// Set the Global Command Handler on the AskingPoint SDK
MyGlobalCommandListener listener = new MyGlobalCommandListener();
AskingPoint.setOnCommandListener(listener);

Remember to report the Command complete with the button users select. Also, custom widgets should NOT process button URLs, AskingPoint processes those after Commands are reported complete so that we can provide download tracking.

Top ▲

Widget Button Selection

If applications need to know (for their own purposes) how users responded to Rating Booster or an In-App Message, a Global Command Response Handler can be set to get notification of button selection. See the SDK Help topic for Command Handlers if you are unfamiliar with basic Command Handler concepts.

typedef void (^ASKPManagerAlertResponse)(ASKPCommand *command, ASKPAlertButton *pressed);

Set the Global Response Handler in the Application Delegate, immediately after the call to [ASKPManager startup:]. The following example outlines the technique for processing data passed to handlers:

#ifdef DEBUG
    [ASKPManager startup:@"my_test_app_key"];                     // Test API_Key
#else
    [ASKPManager startup:@"my_production_app_key"];               // Release API_Key
#endif

    [ASKPManager sharedManager].alertResponse = ^(ASKPCommand *cmd, ASKPAlertButton *pressed) {
        if(cmd.type == ASKPCommandAlert) {
            if(cmd.alertType == ASKPAlertRating) {                // Rating Widget
                if(pressed.ratingType == ASKPAlertRatingYes)
                    NSLog(@"User agreed to rate the App.");
                else if(pressed.ratingType == ASKPAlertRatingNo)
                    NSLog(@"User declined to rate the App");
                else
                    NSLog(@"User asked to be reminded to Rate it later.");
            }
            else if(cmd.alertType == ASKPAlertMessage) {          // Message Widget
                NSLog(@"Button Pressed on Message Widget");
                NSLog(@"  With This Text: %@", pressed.text);
                if(pressed.url != nil)
                    NSLog(@"  And This URL: %@", [pressed.url absoluteString]);
            }
        }
    };
public static interface OnCommandResponseListener {
    /**
     * Called whenever the {@link Command#complete(com.askingpoint.android.Command.Response)
     * complete} method is called on a command.
     *
     * @param command Command that was marked complete.
     * @param response Response chosen. For {@link com.askingpoint.android.AlertCommand} this
     * will be the {@link com.askingpoint.android.AlertCommand.Button} the user selected.
     */
    void onCommandResponse(Command<?> command, Command.Response response);
}

Set the Global Response Handler after the AskingPoint SDK is initialized and before anything else in an Activity is likely to cause something to fire. Safest to do it in the first Activity to get called. The following example outlines the technique for processing data passed to handlers:

public class MyGlobalCommandResponseListener implements OnCommandResponseListener {
    @Override
    public void onCommandResponse(Command<?> command, Command.Response response) {
        if(command.type == Command.Type.ALERT) {
            AlertCommand c = (AlertCommand)command;
            AlertCommand.Button b = (AlertCommand.Button)response;
            if(c.alertType == AlertCommand.AlertType.RATING) {
                switch(b.type) {
                    case RATING_YES: System.out.println("User Pressed Yes"); break;
                    case RATING_NO:  System.out.println("User Pressed No"); break;
                    case RATING_REMINDME: System.out.println("User Pressed Remind"); break;
                }
            }
            else if(c.alertType == AlertCommand.AlertType.MESSAGE) {
                if(b.cancel)
                    System.out.println("User Dismissed the Message");
                else
                    System.out.println("User pressed the action button");
            }
        }
    }
}

Top ▲

iOS Other

End User Opt-Out

AskingPoint takes privacy very seriously and while we work hard to protect privacy and believe that our services help improve the End User experience, we understand that some users don’t want to participate under any circumstances. Therefore, we provide 2 mechanisms for End User Opt Out:

1) SDK Functions To Disable/Enable Data Collection And Transmission

The SDK includes 2 functions for turning ON or OFF AskingPoint data collection and transmission from within Apps.

iOS

[ASKPManager setOptedOut:(BOOL)optedOut]

[ASKPManager optedOut]

Android

public static void setOptedOut(boolean optedOut)

public static boolean isOptedOut()

Use setOptedOut to offer End Users an option to disable data collection. The default value is NO/false (opted in) and remains that way until otherwise set.

When data collection has been disabled, it can be re-enabled by calling setOptedOut with a value of NO/false. Use of this function only affects data collection for the App it is used in.

If an End User uses the procedure outlined in 2, AskingPoint servers tell the App to stop collecting data and instruct it to NOT send anything further to our servers. In such cases, calls to setOptedOut from within the App are ignored.

Call optedOut or isOptedOut to learn the current status. These report state regardless of how it got set (via SDK of End User request).

2) Manual End User Opt Out

End Users may contact AskingPoint directly and request a device be Opted-out of AskingPoint services. For details see the information posted here: End User Opt Out. All such requests results in all data for the specified device(s) being removed from AskingPoint servers and the disabling of data collection and transmission in ALL Apps using AskingPoint services.

Top ▲

Mobile Survey Tech Notes

AskingPoint Mobile Surveys do not require development other than the inclusion of the AskingPoint SDK in the Apps. There is nothing that can be customized in code via the SDK.

See the Dashboard support topics for Mobile Surveys to learn how to Create, Edit and target them.

Top ▲

Languages & Localization

All AskingPoint widgets have default: title, message text, and button text for over 30 languages (all those supported by iOS), and we automatically add new ones whenever they become supported by iOS!

The currently supported languages are:

English, Chinese (Simplified), Chinese (Traditional), French, German, Italian, Japanese, Korean, Spanish, Arabic, Catalan, Croatian, Czech, Danish, Dutch, Finnish, Greek, Hebrew, Hindi, Hungarian, Indonesian, Malay, Norwegian, Polish, Portuguese, Portuguese (Brazil), Romanian, Russian, Slovak, Swedish, Thai, Turkish, Ukrainian, Vietnamese

Top ▲

Contact Support

Contact Support

We’re here when you need us, and we DO want to hear from you. Please feel free to contact us anytime with technical questions regarding:

  • Issues you’re having with the SDK, Dashboard or the website.
  • New Features or enhancements you’d like to see added.
  • Any custom integrations you want to speak with us about.
  • Billing issues.

Send your questions to: support@AskingPoint.com

We’ll do our best to get it sorted ASAP!

ibot!1435179084000

Top ▲