Live Activity、より深く試してみましょう:リアルタイムスケジュール機能開発機

こんにちは! TraceチームがiOS Product Engineerとして働いているキム・ソンフン。
最近、ほとんどのアプリはユーザーの注意を得るためにプッシュ通知を注ぎます。
しかし、私たちは皆知っています。通知は簡単に無視され、スクロールに埋め込まれ、必要な瞬間には私の役割を果たすことができないということです。
逆に、クパンツや配達の民族のようにロック画面で配達状態がリアルタイムで変化するLive Activity体験は、ユーザーの注意を自然に捕らえます。
アプリを開かなくても、今どこに来ているのか、どれだけ残っているのかをすぐに確認でき、このフローがユーザーエクスペリエンスをさらに滑らかにします。
実際にAppleもLive Activityを一定・運動・配信・移動・タイマーなど「持続的に変化する情報」を提供するために最適化された機能だと紹介します。
Traceディスコードコミュニティでも同様のユーザーの要求がありました。
- 「アプリをあえて開かなくても今日何をすべきか一目で見たいです」
- 「ロック画面で今進行中のスケジュールが見えてほしい」
そのため、TraceはこのニーズをLive Activityでどのように解放できるかを本格的に実験を始めました。
この記事では、TraceがLive Activityを活用してリアルタイムのスケジュール体験を実装する過程でどのような問題に直面し、その問題をどのように解決していったかを段階的にまとめていきたいと思います。



APN
iOSでは、すべてのプッシュはApple Push Notification service(APN)を介して配信されます。 APNが送信するプッシュタイプは、大きく3つに分けられます。
- 一般通知(Alert Push)
- ユーザーに見えるバナー/音/振動通知
- Silent Push(バックグラウンドプッシュ)
- 画面には表示されず、しばらくアプリを起動してバックグラウンドタスクを実行する目的
- ActivityKit Push(Live Activityアップデートプッシュ)
- Live Activityの状態を直接更新するために使用される専用タイプ
初めてLive Activityを貼り始めたときは、ActivityKit Pushがどの構造で動作するのか、そしてどのデータ構造を要求するのかが明確に把握されていない状態でした。
それで自然に、これまで多く使ってきてバックグラウンドアップデートにも馴染みのあるSilent Pushから試みることになりました。
「アプリを静かに目覚めさせてLive Activityだけを更新すればいいのか?」
最も簡単に思い出せるアプローチでした。
しかし、何度も試してみた最後に重要な事実を一つ悟りました。
Live Activityは単に「更新要求」を送信する構造ではなく、その時点で画面に表示する必要があるデータ全体(contentState)をプッシュに送信する必要があります。
つまり、サーバーは「現在どのスケジュールが進行中か、どれだけ残っているか」を直接計算して送信しなければならず、Silent Pushインフラストラクチャはこのニーズを確実に満たすことが困難でした。
Live Activityの自動更新
コアアイデアは単純だった。
「アプリを目覚めさせずに、サーバーがLive Activityの状態を計算してそのままプッシュで送ろう」
Traceは別のサーバーインフラストラクチャの代わりにFirebaseを使用しているため、
この構造をFirebase Functions + Firestoreだけで比較的簡単に実装できました。
Live Activityを「リアルタイムのように」更新するには、必要なのは2つだけです。
- 今どのスケジュールが進行中であるかを計算する場所
- その結果をLive Activityに直接プッシュする通路
📌フルデータフロー
iOS App
└─ (토큰 + 일정 저장)
↓
Firestore
↓
Firebase Functions
└─ 현재 이벤트 계산
↓
APNs – ActivityKit Push
└─ contentState 전송
↓
Live Activity
└─ UI 자동 업데이트
1) iOS
- Live Activityの作成時に自動的に発行されるliveActivityTokenを取得
- 時間ベースのカレンダーリストを Firestore に保存
この情報だけで、サーバーは「どのデバイスに、どのスケジュールでLive Activityを更新する必要があるか」を知ることができます。
2) Firebase Functions
Functionsは毎分実行され、次のことを行います。
- Firestoreで現在有効なデバイスリストを検索する
- 各デバイスのイベントのうち、現在時刻基準で「今見せなければならないイベント」を選択
- そのイベントをcontentStateに入れて、liveActivityTokenにActivityKit Pushを送信する
// ActivityKit Push 전송
const notification = new apn.Notification();
notification.topic = "com.example.app.push-type.liveactivity";
notification.pushType = "liveactivity";
notification.event = "update";
notification.contentState = {
event: currentEventData, // 지금 보여줄 이벤트
timestamp: Date.now(),
status: "Active"
};
await apnsProvider.send(notification, liveActivityToken);
3) 動作映像
サーバーがcontentStateをActivityKit Pushに渡し、Live Activityがそれをすぐに反映するフロー全体が実際にどのように機能するかを示します。

Push to Start
これまでのLive Activity構造には1つの前提がありました。
Live Activityは、ユーザーがアプリに直接参加してトリガーする必要があるだけです。
しかし、私たちはここでさらに一歩進みたいと思いました。
「アプリの電源を入れなくてもLive Activityを自動的に起動することはできませんか?」
すぐにこの部分を可能にする機能がiOS 17.2から導入されたpushToStartTokenです。 pushToStartToken を使用すると、サーバーから Live Activity をリモートで起動できます。
つまり、ユーザーがアプリを開かなくても
- 重要なスケジュールがすぐに始まるとき
- やることが始まる直前
- ユーザーが一日中アプリをまったくオンにしていない場合でも
ロック画面にLive Activityを自動的に表示する体験を作成できます。
ちなみに、Appleのドキュメントでは、Activityを生成しなくてもpushToStartTokenUpdatesからトークンを受け取ることができると説明しています。しかし、iOS 17.xでは、この動作はかなり不安定でした。多くの開発者が同じ問題を経験したという報告もあり、Appleも関連問題を認識していることが知られています。
このため、Traceはアプリ実行時にユーザーに見えない「ダミーActivity」をしばらく生成してトークンを確保する方式を採用しました。 (iOS 18ではこの動作が改善されたそうです。)
📌フルデータフロー
iOS App
└─ (pushToStartToken + 시작 시각 저장)
↓
Firestore
↓
Firebase Functions
└─ 시작 시점 도달 여부 확인
↓
APNs – Push to Start
└─ attributes + contentState 전송
↓
Live Activity
└─ 앱을 열지 않아도 자동 생성
Push to Startトークンを取得した後、全体の構造は非常に単純です。
1) iOS
- アプリ実行時のダミー活動を通じてpushToStartToken獲得
- pushToStartToken とスケジュール開始時刻を Firestore に保存
2) Firebase Functions
Functionsは毎分実行され、次のことを行います。
- 「今Live Activityを起動する時期ですか?」を確認してください。
- 視点に達するとAPNにpushToStartTokenに Push to Start リクエストを送信します。このとき、Live Activityに最初に表示されるattributesとcontentStateも一緒に渡されます。
// Push to Start - Activity 생성용 Push
notification.event = "start"; // "update"가 아닌 "start"
notification.attributes = { // 생성 시에만 필요
startTime: Date.now()
};
notification.contentState = {
title: "러닝 30분",
eventDate: 1733458200,
status: "active"
};
つまり、更新プッシュと同様に、サーバーが画面に表示するデータをすべて計算して一度に送信する構造です。
3) 動作映像
サーバーがpushToStartTokenを使用してLive Activityをリモートで作成し、最初に表示されるattributes、contentStateを送信してロック画面に自動的に表示されるプロセスを確認できます。

仕上げ
Live Activityを導入した後、Traceの重要な指標にも変化がありました。
特にDay0→Day1リテンションが約10%上昇し、初期経験の改善効果がはっきりしていました。
ユーザーは「アプリを開かなくてもロック画面ですぐにチェックできて楽」、「やるべきことをLive Activityですぐに完了できるのがいい」というフィードバックを与えました。
Traceは今後もAIとiOSエコシステムの機能を深く探求し、ユーザーの一日に自然に浸透する経験を作っていく予定です。
今回のLive Activity構築過程はチームにとっても非常に興味深い課題であり、個人的にも多くのインサイトを得た経験でした。この記事が似たような問題に悩んでいる人には、ちょっとした参考点や参考になれば幸いです。
ありがとうございます。
参考資料
Starting and updating Live Activities with ActivityKit push notifications — Apple Developer
Update Live Activities with push notifications — WWDC23