RORK LABEN
GROWTH — Rorkは月間74.3万訪問・成長率85%と、利用が伸び続けていますMAX — Rork MaxはネイティブSwiftアプリを生成し、iPhone・iPad・Watch・TV・Vision Pro・iMessageに対応しますMAX — AR/LiDARスキャン・Metalの3Dゲーム・Live Activities・HealthKit・Core MLなど、React Nativeでは届きにくい領域に踏み込めますSTACK — 通常のRorkはReact Native(Expo)でiOSとAndroidを同時に生成し、非エンジニアでも実機アプリを作れますPRICE — 料金は無料から用意され、有料プランは月$25から、Rork Maxは月$200ですMARKET — Gartnerは2026年末までに新規アプリの75%が低コード/ノーコード製になると予測していますGROWTH — Rorkは月間74.3万訪問・成長率85%と、利用が伸び続けていますMAX — Rork MaxはネイティブSwiftアプリを生成し、iPhone・iPad・Watch・TV・Vision Pro・iMessageに対応しますMAX — AR/LiDARスキャン・Metalの3Dゲーム・Live Activities・HealthKit・Core MLなど、React Nativeでは届きにくい領域に踏み込めますSTACK — 通常のRorkはReact Native(Expo)でiOSとAndroidを同時に生成し、非エンジニアでも実機アプリを作れますPRICE — 料金は無料から用意され、有料プランは月$25から、Rork Maxは月$200ですMARKET — Gartnerは2026年末までに新規アプリの75%が低コード/ノーコード製になると予測しています
記事一覧/開発ツール
開発ツール/2026-07-04上級

Rork Max の健康アプリで、朝になると歩数が更新されない — HKObserverQuery が無言で止まる background delivery の設計

Rork Max が生成したネイティブ Swift の健康アプリで、アプリを閉じている間の歩数や心拍が反映されない——その多くは HKObserverQuery の background delivery が無言で止まっていることが原因でした。切り分けと、そのまま組み込める観測レイヤーの実装をまとめます。

Rork Max213HealthKit4background deliveryHKObserverQuerySwift40iOS101

プレミアム記事

歩数を記録するだけの小さなアプリを Rork Max で組んだとき、シミュレータでは何の問題もありませんでした。手動でヘルスデータを流し込むと即座に画面へ反映されます。ところが実機に載せて数日使うと、朝アプリを開いた瞬間だけ前日夜からの歩数がごっそり欠けていて、しばらくすると帳尻が合う、という妙な挙動に気づきました。エラーは一切出ません。ただアプリを閉じている間の更新が届いていないだけでした。

原因は HKObserverQuery の background delivery が、登録したつもりで実際には有効になっていなかったことです。個人開発でヘルスケア連携を扱うと、この「フォアグラウンドでは動くのに、閉じると静かに止まる」パターンに最初に足を取られます。Dolice Labs で運用している小さなアプリ群でも、この種の本番でしか露見しない不具合には何度も向き合ってきました。ここでは Rork Max が生成したネイティブアプリに、アプリが起きていない間もヘルスデータを拾い続ける観測レイヤーを最小差分で乗せる前提で、無言の失敗の切り分け方と、そのまま使える実装を順に見ていきます。

HealthKit のバックグラウンド更新が「三段構え」であること

多くの人が HKObserverQuery を一つ張れば済むと考えますが、アプリを閉じた状態でも更新を受け取るには、独立した三つの仕組みを同時に満たす必要があります。ここを分けて捉えないと、どれか一つが欠けたまま「なぜか届かない」で止まります。

権限・登録・observer の三段を分けて捉える

一段目は権限です。読みたい型(歩数なら HKQuantityType(.stepCount))に対して読み取り認可が下りていること。二段目は background delivery の登録で、enableBackgroundDelivery(for:frequency:) を型ごとに呼び、システムに「この型が変化したら起こしてくれ」と伝えること。三段目が observer query 本体で、変化の通知を受けて実際にデータを引きに行く役割です。

無言の失敗が生まれる非対称性

厄介なのは、権限が「読み取り」しか下りていない状態でも background delivery の登録 API がエラーを返さないことです。登録は成功したように見えるのに、通知が一度も来ない。この非対称性が無言の失敗の温床になっています。本番でだけ静かに欠ける不具合は、たいていこの手前で決まっています。

まず「どの段で落ちているか」を log で切り分ける

原因を憶測で追うと時間を溶かします。私はいつも、三段のそれぞれに印字を仕込んで、どこまで到達しているかを実機の log で確認する手順から入ります。

import HealthKit
import os
 
let healthLog = Logger(subsystem: "net.rorklab.sample", category: "health")
 
final class HealthObservation {
    let store = HKHealthStore()
    let stepType = HKQuantityType(.stepCount)
 
    func bootstrap() async {
        // 一段目: 権限
        do {
            try await store.requestAuthorization(toShare: [], read: [stepType])
            healthLog.info("auth requested")
        } catch {
            healthLog.error("auth failed: \(error.localizedDescription)")
            return
        }
 
        // 二段目: background delivery 登録
        do {
            try await store.enableBackgroundDelivery(for: stepType, frequency: .hourly)
            healthLog.info("background delivery enabled")
        } catch {
            healthLog.error("bg delivery failed: \(error.localizedDescription)")
        }
 
        // 三段目: observer query
        startObserver()
    }
}

enableBackgroundDeliveryfrequency.immediate を渡せますが、歩数のように頻繁に変わる型に即時配信を求めると、システムがスロットリングして結局間引かれます。私は歩数・移動距離のような累積系は .hourly に落ち着きました。心拍のワークアウト連動のような即応が要る型だけ .immediate を検討する、という使い分けを推奨します。実機ではこの方が堅いと考えています。

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

この記事の続きを読む

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

この記事で得られること
アプリを閉じている間だけデータが遅れる症状を、権限・background delivery 登録・observer の生存期間のどこで落ちているか log から切り分けられるようになります
HKObserverQuery と HKAnchoredObjectQuery を組み合わせ、completionHandler を必ず呼ぶ観測レイヤーを、そのまま Rork Max の生成コードに足せる薄いラッパーとして手に入ります
Rork Max が書ききれない Info.plist・Capabilities・バックグラウンド更新の実機制約を、どこで自分の手で補うかがわかります
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

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

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

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

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

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

関連記事

開発ツール2026-07-04
Rork Max のアプリで、選んだ写真が次回起動時に消えている — PHPicker の限定アクセスで URL を握り続けようとする罠
Rork Max が生成したネイティブ Swift アプリで、PHPickerViewController で選んだ写真が再起動後に読めなくなる——限定アクセスの時代に URL や PHAsset を握り続けようとするのが原因でした。選んだ瞬間に自前ストレージへ実体をコピーする設計をまとめます。
開発ツール2026-07-04
Rork Max のアプリでアプリを起動せずに Live Activity を出す — push-to-start トークンが無言で取れない時の設計
Rork Max が生成したネイティブ Swift アプリで、アプリを一度も開かずにサーバから Live Activity を開始したい。ところが push-to-start トークンが観測できず無言で失敗する——その原因と、トークンを確実に取り切る観測レイヤーの実装をまとめます。
開発ツール2026-07-04
Rork Max 生成アプリで端末同士を直接つなぐ — MultipeerConnectivity が無言で失敗する Local Network 権限の罠
Rork Max が生成したネイティブ Swift アプリに、サーバを介さず近くの端末同士をつなぐ共有機能を組み込む方法です。シミュレータでは動くのに実機でピアが見つからない——その多くは Local Network 権限まわりの無言の失敗が原因でした。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →