Skip to main content

Overview

iOS Live Activities display your app’s most current data as real-time, interactive updates on the iPhone Lock Screen and in the Dynamic Island. Transactional Live Activities are specifically designed for unique, user-specific events such as order tracking, ride-hailing updates, or personalized transaction states.
InformationLive Activities and push notifications have different user permission models. By default, Live Activities are enabled for an app. Users can manage permissions for each app individually in their device settings.
PrerequisitesBefore you begin, ensure your project and accounts are configured correctly.
  1. Apple Developer Account Configuration:
    • In your Apple Developer account, navigate to Certificates, IDs & Profiles > Identifiers and select your app’s identifier.
    • Under the Capabilities tab, ensure that Push Notifications checkbox is selected. This is mandatory for the Apple Push Notification service (APNs) to deliver activity updates.
    • APNs Authentication Key: To authorize MoEngage to send push notifications on your behalf, you must configure an APNs Authentication Key. For detailed steps on how to upload the .p8 file to the MoEngage dashboard, please refer to the documentation on APNs Authentication Key.
  2. SDK version: MoEngage iOS SDK 10.09.0 or higher is required to support Transactional Live Activities.
  3. MoEngage Live Activity Module: The MoEngageLiveActivity module is required to handle transactional updates.
  4. Xcode and iOS Version:
    • Xcode: Use Xcode 14.1 or later.
    • iOS Target: Your Live Activity must target iOS 18 and later.

Implementing a Transactional Live Activity

This section covers the client-side setup required within your Xcode project for Transactional Live Activities.

Step 1: Add a Widget Extension

  1. In Xcode, navigate to File > New > Target.
  2. Select Widget Extension and click Next.
    Transla1
  3. Enter a product name for your widget.
  4. Select the Include Live Activities checkbox.
    Transla2
  5. Click Finish.

Step 2: Configure App’s Info.plist

Add Live Activities support to your main app’s Info.plist.
<key>NSSupportsLiveActivities</key>
<true/>

Step 3: MoEngageLiveActivity integration

InformationTo integrate the MoEngageLiveActivity framework, ensure you are using MoEngage iOS SDK version 10.09.0 or higher.
The MoEngageLiveActivity framework is supported via SPM from SDK version 10.09.0. To integrate, use the GitHub URL https://github.com/moengage/apple-sdk.git and set the branch as master or the required version.

Install using CocoaPod

InformationCocoaPods is being deprecated. MoEngage recommends using Swift Package Manager for all new integrations. For more info on CocoaPods, refer to CocoaPods Integration Guide.
To integrate the MoEngageLiveActivity framework, add the following dependency to your Podfile:
target 'MoETest' do
  use_frameworks!

  # Pods for app target
  pod 'MoEngage-iOS-SDK' # specify version constraint
  pod 'MoEngage-iOS-SDK/LiveActivity'

  target 'LiveActivity' do
    use_frameworks!
    inherit! :search_paths
    # Pods for live activity extension target
    pod 'MoEngage-iOS-SDK/LiveActivity'
  end
end

Step 4: Define the Live Activity Attributes

In the Swift file generated for your widget extension, define the data structure for your Transactional Live Activity (e.g., a Food Delivery order).
  1. Configure ActivityAttributes: Create a struct that conforms to ActivityAttributes. This struct will contain:
    • Static Data: Attributes that are set once and do not change (e.g., Order Number).
    • ContentState: A nested struct for dynamic data that will be updated in real-time (e.g., Delivery Status).
      import Foundation
      import ActivityKit
      import WidgetKit
      import SwiftUI
      
      struct FoodOrderAttributes: ActivityAttributes {
          public struct ContentState: Codable, Hashable {
              // Dynamic stateful properties about your order go here!
              var status: String // e.g., "Out for Delivery"
              var estimatedMinutes: Int
          }
      
          // Fixed non-changing properties about your order go here!
          var orderNumber: String
          var restaurantName: String
      }
      
  2. When creating ActivityConfiguration, use MoEngageTransactionActivityAttributes<FoodOrderAttributes> instead of FoodOrderAttributes as your ActivityAttributes type for transactional support.
  3. Track widget clicks by configuring the deeplink and widget ID with the moengageWidgetClickURL API.
    import ActivityKit
    import WidgetKit
    import SwiftUI
    import MoEngageLiveActivity
    
    struct FoodOrderWidget: Widget {
        var body: some WidgetConfiguration {
            ActivityConfiguration(for: MoEngageTransactionActivityAttributes<FoodOrderAttributes>.self) { context in
                // Lock screen/banner UI goes here
                VStack(spacing: 12) {
                    Text(context.attributes.appAttributes.restaurantName)
                    Text(context.state.appContent.status)
                }
                .moengageWidgetClickURL(URL(string: "moeapp://order-tracking"), context: context, widgetId: 2)
                
            } dynamicIsland: { context in
                DynamicIsland {
                    // Expanded UI goes here
                } compactLeading: {
                    Text("Preparing")
                } compactTrailing: {
                    Text("\(context.state.appContent.estimatedMinutes)m")
                } minimal: {
                    Text("Preparing")
                }
                .moengageWidgetClickURL(URL(string: "moeapp://order-tracking"), context: context, widgetId: 1)
            }
        }
    }
    
  4. Ensure Target Membership: Make your ActivityAttributes struct accessible to your main app target.
    1. Select the Swift file where you defined your ActivityAttributes.
    2. Open the File Inspector (Option + Command + 1).
    3. In the Target Membership section, check the box for your main app target.

Step 5: Monitor Live Activities

Call the monitorLiveActivities method to register the ActivityAttributes types that the SDK should monitor for real-time updates. This method must be invoked within your app's didFinishLaunchingWithOptions method. This registration is mandatory for the SDK to successfully track and manage the short tokens required for transactional activity updates.
Task {
         if #available(iOS 18, *) {
             await MoEngageSDKLiveActivity.monitorLiveActivities(types: [ FoodOrderAttributes.self]) { data in
                     print("Push token generated for live activity",data)
             }
          }
      }

   public struct MoEngageTransactionCampaignData {
        public struct MoEngageTokenData {
              public let transactionId: String
              public let shortToken: String
        }
        
        public let accountMeta: MoEngageAccountMeta
        public let tokenData: MoEngageTokenData
    }

    public class MoEngageAccountMeta {
        /// Account identifier, APP ID on the MoEngage Dashboard.
        public let appID: String
    }

Managing the Live Activity Lifecycle

Once your app is configured, you can start, update, and end Transactional Live Activities using a combination of local app code and MoEngage APIs.

Step 6: Start a Transactional Live Activity

A Transactional Live Activity is typically started locally from the app when an end user initiates a transaction (e.g., placing a food order) or you can initiate it remotely via the Inform API (Server-side).

Push-to-Start (Remote)

Start a live activity for a user using the Inform API. For more information, refer here.

Click-to-Start (Local)

Start an activity from within the app, triggered by a user action. Get Live Activity data from the createAttributes(withCampaign:completion:) or createAttributes(withCampaign:) async SDK APIs by combining your application’s ActivityAttributes data with mandatory MoEngage metadata (retrieved from your server). Use Apple’s Activity.request() method with pushType as .token to start Live Activity. This links the locally started activity to your campaign.
MoEngageSDKLiveActivity.createAttributes(
    withCampaign: .init(
        campaignId: campaignId,
        campaignName: "Order Tracking \(orderId)",
        transactionId: transactionId,
        attributeType: "\(FoodOrderAttributes.self)",
        instanceId: instanceId,
        appAttributes: FoodOrderAttributes(orderNumber: "ORD-123", restaurantName: "Pizza Palace"),
        appContent: FoodOrderAttributes.ContentState(status: "Preparing", estimatedMinutes: 30)
    )
) { [weak self] result in
    guard let result = result else {
        self?.view.makeToast("No Live Activity creation result")
        return
    }
    
    do {
        let activity = try MoEngageTransactionActivity<FoodOrderAttributes>.request(
            attributes: result.attributes,
            content: .init(
                state: result.content,
                staleDate: .distantFuture,
                relevanceScore: 10
            ),
            pushType: .token,
            style: .standard
        )
        MoEngageSDKLiveActivity.trackStarted(activity: activity)
        self?.view.makeToast("Order Tracking Live Activity started successfully")
    } catch {
        self?.view.makeToast("Activity request error: \"\(error.localizedDescription)\"")
    }
}
InformationBy using pushType: .token,the Live Activity is configured to receive transactional updates specifically targeted to this activity instance via its unique push token.

Step 7: Update a Live Activity

Update the transactional activity status using a push notification targeted at the activity’s push token. Updates must be performed exclusively via the Inform API. For more information, refer to the Inform API.

Step 8: End a Live Activity

Ending an activity must be performed exclusively through the Inform API; otherwise, it will terminate automatically upon reaching the configured dismissal_date. For more information, refer to the Inform API.