Actions for the Android SDK

Airship Actions provide a convenient way to automatically perform tasks by name in response to push notifications, Message Center App Page interactions, and JavaScript.

An action describes a function, which takes an optional argument and performs a predefined task, producing an optional result. Actions may restrict or vary the work they perform depending on the arguments they receive, which may include type introspection and runtime context.

The Airship SDK includes built-in actions for common tasks, and you can create custom actions to extend functionality.

For a complete list of available built-in actions, see the Actions User Guide.

Action Situations

Actions are triggered with extra context in the form of a Situation. The different situations allow actions to determine if they should run, and may perform different behavior depending on the situation.

DescriptionAndroid
Action was invoked manually..SITUATION_MANUAL_INVOCATION
Action was invoked from a launched push notification..SITUATION_PUSH_OPENED
Action is triggered when a notification is opened..SITUATION_PUSH_OPENED
Action was invoked from JavaScript or a URL..SITUATION_WEB_VIEW_INVOCATION
Action was invoked from a foreground interactive notification button..SITUATION_FOREGROUND_NOTIFICATION_ACTION_BUTTON
Action was invoked from a background interactive notification button..SITUATION_BACKGROUND_NOTIFICATION_ACTION_BUTTON
Action was invoked from automation..SITUATION_AUTOMATION

Action Registry

The action registry is the central place to register actions by name. Each entry in the registry contains an action, the names that the action is registered under, a predicate that allows filtering when an action should run, and allows specifying alternative actions for different situations.

Registering an action

Airship.actionRegistry.registerEntry(setOf("my_action_name", "my_alias")) {
    ActionRegistry.Entry(action = CustomAction())
}
Airship.getActionRegistry().registerEntry(Set.of("my_action_name", "my_alias"), () -> {
    return new ActionRegistry.Entry(new CustomAction());
});

Looking up an action entry

val entry = Airship.actionRegistry.getEntry("my_action_name")
ActionRegistry.Entry entry = Airship.getActionRegistry().getEntry("my_action_name");

Setting a predicate

// Predicate that will reject PUSH_RECEIVED, causing the action to never run during that situation.
val rejectPushReceivedPredicate: ActionPredicate = object : ActionPredicate {
    override fun apply(arguments: ActionArguments): Boolean {
        return SITUATION_PUSH_RECEIVED != arguments.situation
    }
}

// Update the entry with a new predicate
Airship.actionRegistry.updateEntry("my_action_name", predicate = rejectPushReceivedPredicate)
// Predicate that will reject PUSH_RECEIVED, causing the action to never run during that situation.
ActionPredicate rejectPushReceivedPredicate = new ActionPredicate() {
    @Override
    public boolean apply(ActionArguments arguments) {
        return !(SITUATION_PUSH_RECEIVED.equals(arguments.getSituation()));
    }
};

// Update the entry with a new predicate
Airship.getActionRegistry().updateEntry("my_action_name", null, Collections.emptyMap(), rejectPushReceivedPredicate);

Triggering Actions

In addition to triggering actions from messages, you can trigger them programmatically.

Running Actions

// Running an action directly through the ActionRunRequest
ActionRunRequest.createRequest("actionName")
    .setSituation(SITUATION_MANUAL_INVOCATION)
    .setValue("actionValue")
    .run()

// Running an action by registered name
ActionRunRequest.createRequest("my_action_name")
    .setValue("actionValue")
    .run()

// An optional callback when finished
ActionRunRequest.createRequest("my_action_name")
    .setValue("actionValue")
    .run { arguments, result ->
        Logger.info("Action finished! Result: $result")
    }

// Block until the action finishes
val result = ActionRunRequest.createRequest("my_action_name").runSync()
// Running an action directly through the ActionRunRequest
ActionRunRequest.createRequest("actionName")
    .setSituation(Situation.MANUAL_INVOCATION)
    .setValue("actionValue")
    .run();

// Running an action by registered name
ActionRunRequest.createRequest("my_action_name")
    .setValue("actionValue")
    .run();

// An optional callback when finished
ActionRunRequest.createRequest("my_action_name")
    .setValue("actionValue")
    .run(new ActionCompletionCallback() {
        public void onFinish(ActionArguments arguments, ActionResult result) {
            Logger.info("Action finished!  Result: " + result);
        }
    });

// Block until the action finishes
ActionResult result = ActionRunRequest.createRequest("my_action_name").runSync();

Custom Actions

The action framework supports any custom actions. Create an action by extending the Action base class on Android. After takeOff, register the action. The action can be triggered the same way as built-in actions.

Custom Action

class CustomAction : Action() {
    override fun acceptsArguments(arguments: ActionArguments): Boolean {
        if (!super.acceptsArguments(arguments)) {
            return false
        }

        // Do any argument inspections. The action will stop
        // execution if this method returns false.

        return true
    }

    override fun perform(arguments: ActionArguments): ActionResult {
        Log.i("CustomAction", "Action is performing!")
        return ActionResult.newEmptyResult()
    }
}
public class CustomAction extends Action {
    @Override
    public boolean acceptsArguments(ActionArguments arguments) {
        if (!super.acceptsArguments(arguments)) {
            return false;
        }

        // Do any argument inspections. The action will stop
        // execution if this method returns false.

        return true;
    }

    @Override
    public ActionResult perform(ActionArguments arguments) {
        Log.i("CustomAction", "Action is performing!");
        return ActionResult.newEmptyResult();
    }
}
 Note

On Android, custom actions may override the shouldRunOnMainThread() method to specify whether the action should be run on the main tread, or on a background thread. Implementations should take care to avoid long-running tasks, especially when running on the main thread.