◉RORK LABEN
●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SONNET 4.5 — Claude API での提供終了は 11/30、残り27日。API 連携を足したアプリは移行先の確認を●SDK 58 — React Native 0.88 に更新されました。Android のリリース版で R8 が既定オンになり、iOS は SceneDelegate を生成します●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SONNET 4.5 — Claude API での提供終了は 11/30、残り27日。API 連携を足したアプリは移行先の確認を●SDK 58 — React Native 0.88 に更新されました。Android のリリース版で R8 が既定オンになり、iOS は SceneDelegate を生成します●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…
記事一覧/開発ツール
⬡ 開発ツール/2026-06-14上級

Live Activities をリモートから更新する設計 — Rork 製アプリにロック画面の生きた情報を載せるまで

ロック画面と Dynamic Island に「いま動いている情報」を出す Live Activities を、APNs プッシュでリモート更新する設計をまとめました。push-to-start トークンの取得、content-state ペイロード、stale-date と更新予算の扱い、Expo からのネイティブ橋渡しまで、本番で詰まった点を実コードつきで共有します。

Live Activities5ActivityKit4APNs3Expo234Rork Max235iOS117

✦ プレミアム記事

壁紙アプリのダウンロード進捗をロック画面に出してみようと考えたとき、最初に手こずったのが「アプリを閉じている間、誰がこの表示を更新するのか」という一点でした。Live Activities はアプリが前面にいなくても動き続ける表示ですが、その更新をアプリ自身がやろうとすると、バックグラウンド実行の制約にすぐぶつかります。

答えは、サーバーから APNs 経由で直接 Live Activity を更新する経路を用意することでした。ここを設計でつまずくと、ロック画面に古い数字が貼りついたまま動かなくなります。Rork が生成する Expo アプリでも、Rork Max が生成するネイティブ Swift アプリでも、リモート更新の考え方は共通です。本番運用で詰まった順に整理します。

更新には2つの経路がある

Live Activity の更新には、ローカル更新とリモート更新の2系統があります。ローカル更新はアプリが前面にいる短い間だけ Activity.update(...) を呼ぶ方式で、即時性はありますが、アプリが眠ると止まります。

リモート更新は APNs にプッシュを投げ、システムが受け取って表示を書き換える方式です。アプリが閉じていても更新が届くため、進捗・スコア・配車位置のように「アプリの外で進んでいく情報」にはこちらが必須になります。

個人開発で複数のアプリを運用している私の場合、開始直後の数秒だけローカルで初期表示を整え、その後の継続更新はすべてリモートに寄せる形に落ち着きました。両方を中途半端に混ぜると、どちらの値が正かが追えなくなります。

push-to-start と update、2種類のトークン

リモート更新でまず理解しておきたいのが、トークンが2種類あることです。ひとつは「まだ存在しない Live Activity をサーバー側から開始する」ための push-to-start トークン、もうひとつは「すでに動いている特定の Activity を更新する」ための update トークンです。

push-to-start トークンはアプリ全体に1つで、起動時に購読しておきます。update トークンは Activity ごとに発行され、Activity を開始した直後に非同期で流れてきます。この順番を取り違えると、開始はできても以後の更新が一切届かない、という状態になります。

import ActivityKit
 
@available(iOS 17.2, *)
func registerPushToStart() {
    Task {
        for await data in Activity<DownloadAttributes>.pushToStartTokenUpdates {
            let token = data.map { String(format: "%02x", $0) }.joined()
            // アプリ全体で1つ。サーバーに「このユーザーは新規開始を受け付けられる」と登録
            await sendToServer(kind: "start", token: token, activityId: nil)
        }
    }
}
 
@available(iOS 16.1, *)
func observeUpdateToken(for activity: Activity<DownloadAttributes>) {
    Task {
        for await tokenData in activity.pushTokenUpdates {
            let token = tokenData.map { String(format: "%02x", $0) }.joined()
            // Activity ごとに発行される。失効するので毎回サーバーへ上書き送信
            await sendToServer(kind: "update", token: token, activityId: activity.id)
        }
    }
}

ここで大事なのは、pushTokenUpdates は1回きりの取得ではなく、ストリームとして複数回流れてくる点です。トークンはローテーションするため、最初に受け取った1個を保存して終わりにすると、数時間後に更新が止まります。流れてくるたびにサーバー側を上書きする設計にしてください。

✦

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
✦push-to-start トークンと update トークンの2種類をどの順で取得し、どこでサーバーへ送るかを、動く Swift と TypeScript の実例で追える
✦stale-date・dismissal-date・relevance-score を含む APNs ペイロード設計を、更新予算を使い切らないための数値感覚つきで持ち帰れる
✦ロック画面が固まる・Dynamic Island が崩れる・トークンが失効するという本番の3つの落とし穴と、それぞれの回避手順がわかる
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

⬡ 開発ツール2026-10-30
開発ビルドでは動くのに、Release の iOS だけ起動直後に落ちる — scheme を外した app.json が原因の場合の確かめ方
expo-router のアプリで app.json に scheme がないと、Release の iOS だけ起動直後に落ちることがあります。Debug と Android が無事な理由、直し方の二択、scheme を外したい場合の考え方、提出前に見つける確認手順を書き残します。
⬡ 開発ツール2026-09-21
exit code 0 で止まるビルド — ログを黙らせていた設定と、空ファイルを通した存在チェック
eas build --local が exit code 0 but produced no further output で止まる件と、0 バイトのスタブが埋め込まれず dyld で落ちる件。どちらも原因は出力を減らす設定でした。自分のスクリプトを棚卸しする手順まで書き残します。
⬡ 開発ツール2026-09-10
画面を暗くする機能を足したら、アプリを閉じたあとも iPhone が暗いままでした
expo-brightness の setBrightnessAsync は、Android では現在のアクティビティにだけ効き、iOS では端末の明るさそのものを変えます。戻す責任が片側にしかない理由と、AppState で後始末をするフックの実装をまとめました。