◉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-17上級

Rork Max のネイティブ Swift ウィジェットで日替わり表示が止まる — TimelineProvider の更新予算を設計する

Rork Max が生成するネイティブ Swift のホーム画面ウィジェットは、TimelineProvider の更新予算を理解しないと日替わり表示が翌日以降に止まります。reloadPolicy と App Group、ディープリンクまでを実アプリ設計の観点で整理します。

Rork Max235WidgetKit11Swift48ホーム画面ウィジェット個人開発234

✦ プレミアム記事

個人開発で壁紙系や引き寄せ系のアプリを長く運用していると、「ホーム画面に日替わりで1枚見せたい」という要望は必ず出てきます。Rork Max がネイティブ Swift でウィジェットを出力できるようになって、私自身も既存アプリに WidgetKit を載せ直してみたのですが、最初のビルドで素直に詰まりました。シミュレータでは日替わりに見えるのに、実機に入れて翌朝確認すると、ウィジェットが前日の1枚のまま固まっていたのです。

原因は、生成された TimelineProvider が「いつ・どれだけ更新を予約するか」を決めていなかったことでした。WidgetKit のタイムラインは cron ではありません。ここを設計せずに Rork Max の出力をそのまま出すと、初日は動いて2日目から止まる、という最もたちの悪い壊れ方をします。

ウィジェットが止まるのは「予算」を使い切るから

WidgetKit はバッテリーを守るため、各ウィジェットが受け取れる更新回数に1日あたりの上限(更新予算)を設けています。Apple の公開ガイダンスでは、ホーム画面に置かれ頻繁に閲覧されるウィジェットでおおむね 1日40〜70回 が目安とされ、TimelineProvider が返したタイムラインのエントリ消化や reloadTimelines(ofKind:) の呼び出しはこの予算から差し引かれます。

ここで重要なのは、タイムラインの最後のエントリを過ぎても、次のタイムラインの再生成は自動では走らないという点です。getTimeline で「今日の0時のエントリ1件だけ」を返し、reloadPolicy を指定しなかった場合、システムは「いつ次を読み込むべきか」を知りません。結果として、表示は最後のエントリのまま固定されます。ここが最大の落とし穴です。シミュレータで気づけないのは、デバッグ実行のたびにタイムラインが再生成されるためで、本番運用の挙動とは別物です。

予算は「使い切ったら次の日まで回復しない」性質があるので、設計の目標は2つになります。第一に、1日の更新回数を予算内に収めること。第二に、その範囲で確実に翌日分へ繋ぐこと。日替わり表示なら、本当に必要な更新は1日1回です。予算を気にして過剰に減らすより、reloadPolicy を正しく使って「次の更新時刻」を明示するほうが安全です。

reloadPolicy で「次にいつ起こすか」を必ず宣言する

Timeline(entries:policy:) の policy には3種類があります。.atEnd は最後のエントリを過ぎたら再読み込み、.after(date) は指定時刻に再読み込み、.never は再読み込みしないという意味です。日替わりウィジェットでは、翌日0時を明示する .after が最も予測可能です。

import WidgetKit
import SwiftUI
 
struct DailyEntry: TimelineEntry {
    let date: Date
    let title: String
    let imageName: String
}
 
struct DailyProvider: TimelineProvider {
    func placeholder(in context: Context) -> DailyEntry {
        DailyEntry(date: Date(), title: "今日の一枚", imageName: "placeholder")
    }
 
    func getSnapshot(in context: Context, completion: @escaping (DailyEntry) -> Void) {
        completion(currentEntry())
    }
 
    func getTimeline(in context: Context, completion: @escaping (Timeline<DailyEntry>) -> Void) {
        let entry = currentEntry()
 
        // 翌日0時(端末ローカル)を次の更新時刻として明示する
        let calendar = Calendar.current
        let startOfTomorrow = calendar.startOfDay(
            for: calendar.date(byAdding: .day, value: 1, to: entry.date)!
        )
 
        let timeline = Timeline(entries: [entry], policy: .after(startOfTomorrow))
        completion(timeline)
    }
}

ここでの肝は、エントリを「今日の1件」に絞り、reloadPolicy を .after(翌日0時) にしている点です。こうすると、システムは翌日0時前後にもう一度 getTimeline を呼び、そこで「次の日の1枚」が確定します。1日の更新は実質1回で済み、予算の枯渇を回避できます。

.atEnd でも動きますが、エントリを1件しか積んでいないと「最後のエントリ=今表示中」になり、再読み込みのタイミングが曖昧になります。確実に日付の境界で切り替えたいなら、.after で時刻を握るほうが意図どおりに動きます。私自身は、.atEnd で組んだ初回ビルドが翌日に固まり、.after に変えて解消した経緯があるので、日替わり用途では .after を既定にしています。個人的にも、日替わり表示ではこの方針を推奨します。注意点として、.after の時刻は端末ローカルの0時に合わせるのが無難です。

✦

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

この記事の続きを読む

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

この記事で得られること
✦TimelineProvider の reloadPolicy と日次更新予算を踏まえ、日替わりウィジェットを翌日以降も止めずに回す設計
✦App Group 経由でアプリ本体とウィジェットがコンテンツを共有し、ネットワークなしで当日分を確定させる実装パターン
✦ウィジェットのタップを Widget URL で該当画面へ正しく繋ぐディープリンク設計と、よくある失敗の切り分け
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

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

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

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

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

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

関連記事

⬡ 開発ツール2026-04-05
Rork Max × WidgetKit・ライブアクティビティ実装ガイド 2026 — Dynamic Island 対応まで
Rork Max で iOS Widget・ロック画面ウィジェット・Dynamic Island 対応のライブアクティビティを実装した記録。Timeline の焼き込み設計、APNs のヘッダーと優先度、push-to-start、stale-date の扱いまで実運用の判断を残します。
⬡ 開発ツール2026-05-17
Rork Max の SwiftUI 機能を壁紙アプリ開発で検証した結果 — 実際に動いた機能と手を入れた機能
運用中の壁紙アプリの本番コードを基準に、Rork Max の SwiftUI ネイティブ生成を検証しました。そのまま使えた機能、手を入れた機能、生成を諦めた機能を、動くコードと実機での計測値とともにお伝えします。
⬡ 開発ツール2026-05-12
Rork Max で複数アプリ共通UIライブラリを Swift Package Manager で構築する実践ガイド
複数アプリを運営する個人開発者向けに、Swift Package Managerで共通UIライブラリを構築してRork Max生成コードの重複を排除する手順です。パッケージ構成の設計、テーマシステムとカードコンポーネント、アニメーションプリセットの共通化、テストまで詳解します。