Actions

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 library comes with built-in actions for common tasks such as setting/modifying tags, showing a landing page, enabling user notifications, scheduling or canceling action schedules, and deep linking. Actions can also be extended to enable custom application behaviors and engagement experiences.

In iOS, Actions are sent as part of the notification payload as top level key values, where the key is the name of the action and the value is the action’s argument. The argument can be any valid JSON value.

Action Situations

Actions are triggered with extra context in the form of a Situation. The different situations allows actions to determine if they should run or not, and possibly do different behavior depending on the situation.

DescriptionAndroidiOS
Action was invoked manually..SITUATION_MANUAL_INVOCATIONUASituationManualInvocation
Action was invoked from a launched push notification..SITUATION_PUSH_OPENEDUASituationLaunchedFromPush
Action was invoked from a received push notification in the foreground.N/AUASituationForegroundPush
Action was invoked from a received push notification in the background.N/AUASituationBackgroundPush
Action is triggered when a notification is opened..SITUATION_PUSH_OPENEDN/A
Action was invoked from JavaScript or a URL..SITUATION_WEB_VIEW_INVOCATIONUASituationWebViewInvocation
Action was invoked from a foreground interactive notification button..SITUATION_FOREGROUND_NOTIFICATION_ACTION_BUTTONUASituationForegroundInteractiveButton
Action was invoked from a background interactive notification button..SITUATION_BACKGROUND_NOTIFICATION_ACTION_BUTTONUASituationBackgroundInteractiveButton
Action was invoked from automation..SITUATION_AUTOMATIONUASituationAutomation

Available Actions

A list of common actions that can be configured on the Content step of a composer is available in the Actions User Guide.

iOS Imports

For CocoaPods

import AirshipKit
@import AirshipKit;

For all other package managers

import AirshipCore;
@import AirshipCore;

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

val customAction: Action = CustomAction()
UAirship.shared().actionRegistry
    .registerAction(customAction, "my_action_name", "my_alias")
Action customAction = new CustomAction();
UAirship.shared().getActionRegistry()
    .registerAction(customAction, "my_action_name", "my_alias");
Airship.shared.actionRegistry.registerEntry(
    names: ["action_name", "action_alias"],
) {
    return ActionEntry(action: action)
}

Looking up an action entry

val entry = UAirship.shared().actionRegistry.getEntry("my_action_name")
ActionRegistry.Entry entry = UAirship.shared().getActionRegistry().getEntry("my_action_name");
let entry = Airship.shared.actionRegistry.entry(name: "action_name")

Setting a predicate

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

entry?.predicate = rejectPushReceivedPredicate
// Predicate that will reject PUSH_RECEIVED, causing the action to never run during that situation.
Predicate<ActionArguments> rejectPushReceivedPredicate = new Predicate<ActionArguments>() {
    @Override
    public boolean apply(ActionArguments arguments) {
        return !(SITUATION_PUSH_RECEIVED.equals(arguments.getSituation()));
    }
};

entry.setPredicate(rejectPushReceivedPredicate);
// Predicate that only allows the action to run if it was launched from a push
let predicate: @Sendable (ActionArguments) async -> Bool = { args in
    return args.situation == .launchedFromPush
}

// Update the predicate
Airship.shared.actionRegistry.updateEntry(name: "action_name", predicate: predicate)

Triggering Actions

Actions can be programmatically through the UAActionRunner , by defining actions in a push notification, from JavaScript using a Custom HTML Template, or from an automation schedule.

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();
let result = await ActionRunner.run(
    actionName: "action_name",
    arguments: ActionArguments(
        string: "some value",
        situation: .manualInvocation
    )
)

// Run an action directly
let result = await ActionRunner.run(
    action: action,
    arguments: ActionArguments(
        string: "some value",
        situation: .manualInvocation
    )
)

Custom Actions

The action framework supports any custom actions. Create an action by extending the Action base class on Android, or Actionprotocol on iOS. iOS also allows actions to be defined using blocks. 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();
    }
}
let customAction = BlockAction { args in
    print("Action is performing with args: \(args)")
    return nil
}

Airship.shared.actionRegistry.registerEntry(names: ["custom_action"]) {
    return ActionEntry(action: customAction)
}
 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.