ANTIGRAVITY LABEN
記事一覧/アプリ開発
アプリ開発/2026-06-23上級

毎日変わるはずの壁紙ウィジェットが止まった — WidgetKit のリロード予算を実測して設計を組み直した記録

毎日壁紙が切り替わるはずのウィジェットが数日で更新を止めました。WidgetKit のタイムラインとリロード予算、拡張のメモリ上限を実測し、1日分のエントリをまとめて積む設計へ組み直した過程をまとめます。

WidgetKit3iOS23Antigravity261壁紙アプリ3パフォーマンス4

プレミアム記事

App Store で配信している壁紙アプリに「毎日ホーム画面の壁紙ウィジェットが切り替わる」機能を足したときの話です。シミュレータでは気持ちよく動いていました。実機に入れて数日放置したところ、ウィジェットの絵がある朝から固まったまま、何時間経っても変わらなくなりました。アプリを開くと直る。閉じてしばらくするとまた止まる。

最初はキャッシュか日付計算のバグを疑いました。けれど原因はコードの誤りではなく、WidgetKit の「リロード予算」という、画面のどこにも出てこない上限に毎日ぶつかっていたことでした。個人開発でウィジェットを真面目に運用すると必ず通る場所だと思うので、実測した数字とあわせて設計の組み直し方を残しておきます。

ウィジェットは「生きて」いません

最初に外しておきたい誤解があります。ウィジェットは小さなアプリが常時動いているわけではありません。表示されているのは、あらかじめ用意した「タイムライン」を OS が好きなタイミングで描画した静止画です。

タイムラインは TimelineEntry の配列で、各エントリは「この時刻に、この内容を見せてほしい」という宣言です。OS は getTimeline(in:completion:) を呼んでこの配列を受け取り、各エントリの date が来たら対応するビューに差し替えます。差し替えのたびに自分のコードが走るわけではありません。配列を渡し終えた瞬間に、その先の見た目は OS の手に渡ります。

struct WallpaperProvider: TimelineProvider {
    func placeholder(in context: Context) -> WallpaperEntry {
        WallpaperEntry(date: Date(), assetID: "placeholder")
    }
 
    func getSnapshot(in context: Context, completion: @escaping (WallpaperEntry) -> Void) {
        completion(WallpaperEntry(date: Date(), assetID: currentAssetID()))
    }
 
    func getTimeline(in context: Context, completion: @escaping (Timeline<WallpaperEntry>) -> Void) {
        // ここで配列を一気に組む。呼ばれる回数こそが予算の消費。
        let entries = buildDailyEntries(from: Date())
        completion(Timeline(entries: entries, policy: .atEnd))
    }
}

つまり「毎日壁紙を変えたい」を「毎日 getTimeline を呼ばせて新しい画像を取りに行く」と読み替えてしまうと、設計を一歩間違えます。私が最初に書いたのがまさにそれでした。

リロード予算という見えない上限

getTimeline が再び呼ばれる契機は大きく三つあります。タイムラインの reloadPolicy が満了したとき、アプリ側から WidgetCenter.shared.reloadTimelines(ofKind:) を呼んだとき、そしてシステムが独自判断で更新したときです。

このうち背景での再読み込みには、ウィジェット単位の1日あたりの予算が割り当てられています。Apple は正確な数値を公開していませんが、頻繁に表示されるウィジェットでおおむね1日40〜70回程度という範囲が、開発者コミュニティでも私の実測でも繰り返し見えてきます。予算は1日かけて少しずつ回復します。

最初の実装では、アプリがフォアグラウンドに来るたびと、1時間ごとのタイマーで reloadTimelines を呼んでいました。さらにタイムラインは「今の1エントリ+1時間後に .atEnd」という短い作りでした。結果、背景リロードだけで1日120回前後を要求していて、午前のうちに予算を使い切り、午後以降は OS がリロードを黙って後回しにしていました。これが「ある朝から止まる」の正体でした。

予算を使い切ったかどうかを知らせる API はありません。エラーも出ません。ただ静かに、絵が古いままになります。落とし穴としてたちが悪いのは、シミュレータと開発中の実機では予算が緩く、しばらく使ってからでないと顕在化しない点です。

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

この記事の続きを読む

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

この記事で得られること
1リクエストごとのリロードから24エントリ一括のタイムラインへ切り替え、背景リロードを実測で約120回/日から3回/日へ抑えた具体的な手順
ウィジェット拡張の約30MBメモリ上限でフル解像度壁紙が落ちる問題を、ImageIO のサムネイル生成で約38MBから0.4MBへ削った実装
OSが公開しないリロード予算を、App Group 共有領域に呼び出し回数を積んで間接的に可視化する計測コード
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

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

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

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

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

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

関連記事

アプリ開発2026-05-26
アプリ内レビュー要求の出し分け条件を Antigravity Editor で 5 アプリ統一した数日の記録
個人開発で運用してきた iOS 壁紙アプリ 5 本の SKStoreReviewController 呼び出し条件を、Antigravity Editor のマルチファイル編集機能でひとつの基準にまとめ直したときの数日間の所感を、コード例とあわせて静かに記録しました。
アプリ開発2026-05-25
Antigravity の Inline Edit と Agent モードを壁紙アプリ運用で1ヶ月使い分けた所感
壁紙アプリ4本の実運用で Antigravity の Inline Edit と Agent モードを1ヶ月使い分けた所感です。実測値・AGENTS.md への判断軸の固定・dSYM 一括統一・クレジット消費まで、現実的な運用設計を共有します。
アプリ開発2026-05-16
Antigravity で新 iPhone の解像度対応を乗り越えた話 — iPhone Air / 17 Pro 対応で29箇所ハマった実例
iPhone Air(420×912)・17 Pro(402×874)など新モデルへの解像度対応でハマった実例を紹介します。Beautiful HD Wallpapers の更新時に DefineManager.h を29箇所修正した経験と、Antigravity でどこまで自動化できたかを正直に書きます。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →