RORK LABEN
FOUNDATION — アプリビルダーの土台にあるモデル層が動きました。9月2日に Gemini 3.8 Flash が一般提供へ移り、長期にわたるコーディングと自律エージェントへ向けた世代交代が進んでいますRECORD — 生成されるコードの質は、こうした更新に合わせて静かに変わります。いつ何が変わったかを手元に書き留めておくと、後から挙動の差を追いやすくなると考えていますMAX — Rork Max はネイティブ Swift を書き、クラウド上の Mac 群でコンパイルします。ブラウザに実機さながらのシミュレータが流れ、App Store への公開まで Xcode なしで進められますDEPTH — 触れる範囲の広さが持ち味です。LiDAR、Dynamic Island、Live Activities、HealthKit、ウィジェット、App Clips、そして Core ML によるオンデバイス推論まで扱えますPRICING — Max は月額 $200 から。上位の階層では $1,800 まで幅があり、無料枠は週5プロンプト程度です。個人開発でしたら、まず無料枠でどこまで届くかを見極めるところからだと思いますSTACK — 標準の Rork は React Native と Expo が土台です。Web ラッパーではない体験を狙う構成で、ネイティブの深いところまで要るときに Max を選ぶ、という切り分けになりますFOUNDATION — アプリビルダーの土台にあるモデル層が動きました。9月2日に Gemini 3.8 Flash が一般提供へ移り、長期にわたるコーディングと自律エージェントへ向けた世代交代が進んでいますRECORD — 生成されるコードの質は、こうした更新に合わせて静かに変わります。いつ何が変わったかを手元に書き留めておくと、後から挙動の差を追いやすくなると考えていますMAX — Rork Max はネイティブ Swift を書き、クラウド上の Mac 群でコンパイルします。ブラウザに実機さながらのシミュレータが流れ、App Store への公開まで Xcode なしで進められますDEPTH — 触れる範囲の広さが持ち味です。LiDAR、Dynamic Island、Live Activities、HealthKit、ウィジェット、App Clips、そして Core ML によるオンデバイス推論まで扱えますPRICING — Max は月額 $200 から。上位の階層では $1,800 まで幅があり、無料枠は週5プロンプト程度です。個人開発でしたら、まず無料枠でどこまで届くかを見極めるところからだと思いますSTACK — 標準の Rork は React Native と Expo が土台です。Web ラッパーではない体験を狙う構成で、ネイティブの深いところまで要るときに Max を選ぶ、という切り分けになります
記事一覧/開発ツール
開発ツール/2026-09-05上級

Widget Extension でも BGTaskScheduler.submit は成功します。走らないのは register が親アプリだけのものだからです

Widget Extension から BGTaskScheduler に依頼を出すとビルドも submit も通るのに、翌朝ウィジェットは変わりません。register がホストアプリ専用である事実から、更新の主語を親アプリへ戻す設計まで、壁紙アプリの運用で詰めた手順を残します。

Rork552WidgetKit11BGTaskScheduler4iOS111Expo200App Extension3

プレミアム記事

夕方になるとホーム画面のウィジェットが昨日の一枚のまま止まる、という問題を片づけた翌週のことでした。次に届いた要望は「アプリを一度も開かない日でも、朝には次の壁紙に変わっていてほしい」というものです。

素直に考えれば、更新の主語はウィジェット側にあります。表示しているのはウィジェットなのですから、次の画像を用意する仕事も同じターゲットに持たせればよい——そう考えて、Widget Extension のコードに BGAppRefreshTaskRequest を組み込みました。

ビルドは通りました。submittrue を返しました。それなのに、翌朝の画面は前日のままでした。原因にたどり着くまで半日かかっております。

submit は通り、register だけが拒まれます

先に結論をお伝えします。BGTaskScheduler は、拡張から依頼を出すことは許していますが、依頼を受け取る側になることは許していません。SDK のヘッダには registerForTaskWithIdentifier:usingQueue:launchHandler: に対して拡張では使えない旨の注釈が付いており、その理由が「Only the host application may register launch handlers」と一行だけ添えられています(BackgroundTasks.framework の BGTaskScheduler.h)。

同じヘッダの説明文には、拡張から依頼を出せる場合があること、そして背景作業のために起動されるのはホストアプリだけであることが、続けて書かれています。つまり submit の成功は「受け付けました」以上の意味を持ちません。

呼び出しWidget Extension から実際に起きること
submitTaskRequest:error:呼べます依頼は受理され、戻り値は true になります
registerForTaskWithIdentifier:...呼べません拡張では利用できない指定が付いています
起動されるターゲットホストアプリのみで、拡張は起動されません

私が書いてしまったのは、次のような拡張側のコードでした。動きはします。ただし、受け手がどこにもいません。

// WallpaperWidget/RefreshScheduler.swift(この設計は行き止まりです)
import BackgroundTasks
 
enum RefreshScheduler {
    static func scheduleFromWidget() {
        let request = BGAppRefreshTaskRequest(identifier: "net.dolice.wallpaper.dailyRefresh")
        request.earliestBeginDate = Calendar.current.date(byAdding: .hour, value: 6, to: Date())
        do {
            try BGTaskScheduler.shared.submit(request)
            // ここは通ります。true が返り、ログにも「予約できた」と出ます。
            // しかし launchHandler は拡張に登録できないため、誰も起きてきません。
            NSLog("[widget] submitted dailyRefresh")
        } catch {
            NSLog("[widget] submit failed: \(error)")
        }
    }
}

submit が例外を投げないので、ログには成功しか残りません。落ちないぶん、気づくのが遅れます。私はこの種の無言の失敗をいちばん警戒しております。

本番運用でいちばん怖いのは、対処のしようがある不具合ではなく、こうして誰にも報告されない取りこぼしなのかもしれません。クラッシュしていれば計測に乗りますが、これは乗りません。

Info.plist の台帳は親アプリ側にしかありません

もう一つ、拡張に更新を持たせようとすると必ずぶつかる壁があります。識別子の許可リストです。

BGTaskSchedulerNotPermitted(Code=3)は、UIBackgroundModes に適切なモードが含まれていないか、識別子が BGTaskSchedulerPermittedIdentifiers に無い場合に返ります。ここで大事なのは、その配列が置かれるべき場所がアプリの Info.plist だという点です(BGTaskScheduler.Error.Code.unavailable の説明 と併せて読むと、Code=1 と Code=3 の役割分担がはっきりします)。

拡張の Info.plist に書いても効きません

Xcode のターゲット一覧で Widget Extension を選び、そちらの Info.plist に BGTaskSchedulerPermittedIdentifiers を足したくなります。私も一度そうしました。エラーは何も出ません。何も起きないだけです。

Rork や Expo の構成では app.config 側に書きます

Rork が出力するのは React Native と Expo の構成ですので、Info.plist を手で編集するのではなく、設定ファイル側に寄せます。

// app.config.js — 親アプリの Info.plist に入る場所へ書きます
export default {
  expo: {
    ios: {
      bundleIdentifier: "net.dolice.wallpaper",
      infoPlist: {
        UIBackgroundModes: ["fetch", "processing"],
        BGTaskSchedulerPermittedIdentifiers: [
          "net.dolice.wallpaper.dailyRefresh"
        ]
      }
    }
  }
};

識別子は 1 か所で定義して両方から参照します

親アプリと拡張で識別子の文字列がずれると、registersubmit が別々のタスクを指すことになり、これも無言で外れます。私は共有ターゲットに定数を置いて、両方からそれを参照する形にしております。

// Shared/RefreshTaskID.swift — 親アプリと Widget Extension の両方に含めます
public enum RefreshTaskID {
    public static let daily = "net.dolice.wallpaper.dailyRefresh"
    public static let appGroup = "group.net.dolice.wallpaper"
    public static let widgetKind = "DailyWallpaperWidget"
}

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

この記事の続きを読む

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

この記事で得られること
Widget Extension に背景更新を持たせようとして半日溶かす前に、register と submit のどちらが自分の構成で禁じられているかを 5 分で判別できるようになる
BGAppRefreshTask の実行機会と WidgetKit の reload という2つの予算を切り分けて設計し、親アプリからウィジェットへ確実に橋渡しできるようになる
submit が true を返したのに更新が来ないとき、getPendingTaskRequests と App Group の受信記録のどちらを先に見るかを迷わず決められるようになる
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

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

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

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

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

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

関連記事

開発ツール2026-06-15
Rork 製アプリのウィジェットにタップで動くボタンを置く — App Intents で「アプリを開かない操作」を実装する
Rork が生成する Expo アプリのウィジェットに、タップしてもアプリを開かずに状態を変えるボタンを置く方法です。App Intents と WidgetKit を App Group で結び、reloadTimelines まで往復させる実装を、詰まった2か所も含めて手順で整理します。
開発ツール2026-06-14
アプリを開かなくても更新される、を Expo で実際に届ける — Background Task の現実的な設計
Rork が生成する Expo アプリで『毎朝コンテンツが更新される』体験を作ろうとすると、iOS のバックグラウンド実行は思ったほど律儀に動きません。expo-background-task の最小実装と、実行されない前提で破綻しない設計をまとめました。
開発ツール2026-06-12
Rork 製アプリにホーム画面ウィジェットを追加する — Expo の制約を越えて WidgetKit を動かすまで
Rork が生成する Expo アプリにはホーム画面ウィジェットを直接追加できません。config plugin と App Group を使って WidgetKit を組み込む実装ルートを、詰まった点も含めて手順で整理します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →