Implementing iOS Live Activities for Real‑Time Travel Information in Qunar
This article explains how Qunar integrated iOS 16 Live Activities to display real‑time travel updates on the lock screen and Dynamic Island, covering background, feature comparison, requirements, system design, Swift implementation, push‑based updates, debugging tips, and lessons learned.
iOS 16 introduced Live Activities, a default‑enabled feature that shows core information on the lock screen and Dynamic Island without requiring the main app to stay open, offering higher reach than widgets. Qunar leveraged this to provide users with real‑time travel information throughout the journey.
The article compares Live Activities with iOS 14 widgets, highlighting differences in persistence, user attention, and suitable scenarios, and outlines when Live Activities should be displayed for travel tickets.
Key requirements include determining display timing, ensuring timely data updates via the main app or APNS push, and handling graceful termination of activities.
The system design involves five roles: the Order Center (binds users to travel products), business lines (monitor specific travel data), the Push Platform (delivers updates via QMQ), the client app (starts, updates, and ends activities, synchronizes push tokens), and the PUSH channel (provides remote update capability independent of the main app).
Implementation steps are demonstrated with Swift code. First, an ActivityAttributes struct is defined:
struct MyLiveAcitityAttributes: ActivityAttributes {
public struct ContentState: Codable, Hashable {
// ContentState holds dynamic data, here a JSON string
var content: String
}
// Immutable data passed at launch, e.g., source, business ID
var channelID: String
}Before launching, activity permission is checked:
guard ActivityAuthorizationInfo().areActivitiesEnabled else { … }Launching the activity uses Activity.request(attributes:contentState:pushType:) :
do {
let myActivity = try Activity
.request(
attributes: attribute,
contentState: contentState,
pushType: PushType.token)
print("start my Live Activity \(myActivity.id)")
} catch let error {
print("fail to request my Live Activity \(error.localizedDescription)")
}Updates can be performed either by the foreground app:
let contentState = MyWidgetAttributes.ContentState(content: unwrapJsonStr)
await liveActivity.update(using: contentState)or via APNS push when pushType is .token . Closing the activity can be done programmatically:
// MARK: Stop Live Activity
@available(iOS 16.1, *)
@objc public func stop(activtyId: String?) -> Bool {
let liveActivity: Activity
? = getLiveActivity(ID: activtyId)
guard let liveActivity else { return false }
await liveActivity.end(dismissalPolicy: .immediate) // immediate end
return true
}Or by sending an APNS payload with an event: "end" and optional dismissal-date to trigger remote termination.
Because Live Activities cannot make network requests, a data‑center pattern is used: incoming data is stored centrally and shared across UI components, allowing fallback to the last valid state when updates are invalid.
UI constraints are described (fixed width, height limits, Dynamic Island safe areas) and the need to coordinate with designers to avoid layout issues.
Since the system lacks a built‑in timer for automatic closure, the team uses push notifications to send an end event at the appropriate moment.
A script for simulating APNS pushes is provided, showing how to generate a JWT authentication token and send an update or end payload via curl :
# Generate AUTHENTICATION_TOKEN
export JWT_ISSUE_TIME=$(date +%s)
... (omitted for brevity) ...
curl -v \
--header "apns-topic:{YOUR_BUNDLE_ID}.push-type.liveactivity" \
--header "apns-push-type:liveactivity" \
--header "authorization: bearer $AUTHENTICATION_TOKEN" \
--data '{"aps": {"timestamp":$(date +%s)000,"event":"update","content-state":{"content":"{\"businessType\":\"train\",\"trainData\":{}}"}}}' \
--http2 https://$APNS_HOST_NAME/3/device/$DEVICE_TOKENFor debugging, developers can attach to the Live Activity extension process in Xcode, trigger activity launch or update from the main app, and set breakpoints in the extension code.
Finally, the article notes that many Qunar apps have adopted Live Activities, improving user experience and brand perception, and encourages readers to explore this technology for their own products.
Qunar Tech Salon
Qunar Tech Salon is a learning and exchange platform for Qunar engineers and industry peers. We share cutting-edge technology trends and topics, providing a free platform for mid-to-senior technical professionals to exchange and learn.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.