メインコンテンツへスキップ

iOSがバックグラウンドでの位置情報更新を停止する理由

Capacitor アプリでiOSがバックグラウンドの位置情報更新を停止する原因(サスペンド、バックグラウンドモード、権限、自動一時停止、精度)とその解決策を解説します。

iOSがバックグラウンドでの位置情報更新を停止する理由

iOSがバックグラウンドでの位置情報更新を停止するのは、Core Locationの失敗ではなく、アプリがサスペンドされるためです。アプリが位置情報のバックグラウンドモードを宣言し、 CLLocationManagerバックグラウンド更新を有効化して、フォアグラウンド中に更新を開始していない限り、ユーザーがアプリを離れて数秒後にiOSはプロセスをフリーズさせ、修正をキューに入れるか破棄します。本ガイドでは、Capacitor アプリで見られるすべての原因とその解決策をまとめ、 @capgo/background-geolocation 処理されます。

iOSによるバックグラウンドアプリの扱い

ユーザーがホーム画面に戻ったり、端末をロックしたりすると、iOSはアプリに短い猶予を与えた後、アプリをサスペンド(中断)します。サスペンド状態のアプリにはCPU時間が割り当てられません。Capacitor アプリの場合、ネイティブ側とWebViewの両方が停止するため、JavaScriptのコールバックも実行されなくなります。

Appleは、位置情報をアクティブに使用しているアプリに対して例外を設けています。アプリがバックグラウンドでの位置情報利用に設定されており、フォアグラウンドで位置情報セッションが開始されている場合、iOSはアプリの実行を継続し、アップデートを配信し続けます。以下では、その条件を満たす方法と、システムが意図的にその動作を中断するケースについて説明します。

原因1:Location Background Modeが設定されていない

がないと、 location 内の UIBackgroundModesいくら code を使っても、アップデートを継続させることはできません。これを ios/App/App/Info.plist:

<key>UIBackgroundModes</key>
<array>
  <string>location</string>
</array>

また、Xcodeの Signing & Capabilities > Background Modes > Location updates からも有効にできます。これはplistのキーであり、entitlementではないため、プロビジョニングプロファイルの変更は不要です。

その背後にあるネイティブのプロパティは allowsBackgroundLocationUpdates。これを true に設定しても、plistにバックグラウンドモードがないとアプリはクラッシュします。Capgo プラグインは、 backgroundMessage へ start()そのため、リリース前に必ずplistキーを設定しておく必要があります。

App Reviewでは、バックグラウンドモードの使用理由が確認されます。レビュー時のメモにどの機能がそれを使用しているかを明記し、レビュアーがその機能を確認できるようにしてください。

原因2:バックグラウンドからアップデートを開始した

Appleのルール:アプリがフォアグラウンドにいる間に開始されたバックグラウンドアップデートは継続されます。サイレントプッシュやバックグラウンドフェッチ、または BGTaskScheduler 標準的な位置情報アップデートでは、タスクからセッションを開始することはできません。

ユーザーのアクション、またはアプリのレジューム時にトラッキングを開始してください:

import { App } from '@capacitor/app';
import { BackgroundGeolocation } from '@capgo/background-geolocation';

let tracking = false;

export async function startTracking() {
  if (tracking) return;
  tracking = true;
  await BackgroundGeolocation.start(
    {
      backgroundMessage: 'Recording your route',
      backgroundTitle: 'Route recording',
      requestPermissions: true,
      distanceFilter: 10,
      url: 'https://api.example.com/v1/points',
    },
    (location, error) => {
      if (error) return console.error(error);
      if (location) console.log(location.latitude, location.longitude);
    },
  );
}

// Re-arm when the user comes back, if the session should be active
App.addListener('appStateChange', ({ isActive }) => {
  if (isActive && shouldBeTracking()) startTracking();
});

declare function shouldBeTracking(): boolean;

原因3: backgroundMessage が渡されていませんでした

これは Capgo プラグイン特有の、最も頻繁に報告されるバグです。もし backgroundMessage が undefined の場合、プラグインは位置情報マネージャーをフォアグラウンド専用として設定してしまいます: allowsBackgroundLocationUpdates が維持されます false また、アプリがサスペンドされると更新も停止します。両プラットフォームでメッセージを渡すことが可能です。Androidでは、フォアグラウンドサービスの通知テキストとしても使用されます。

原因4:不適切な権限レベル、または「1回のみ許可」の選択

バックグラウンドで追跡するには「常に許可」が必要だと考える開発者は多いですが、実はそうではありません。Appleのドキュメントによると、バックグラウンド更新が有効であれば、「使用中のみ許可」の権限を持つアプリでも、位置情報サービスがアクティブな間はバックグラウンドで動作し続けます。

「常に許可」は別の用途、つまり終了したアプリの再起動において重要になります。リージョンモニタリング、大幅な位置変化(significant-change location)、および訪問(visits)のみが、アプリを再起動させることができますが、これには「常に許可」が必要です。

ユーザーの以下の2つの選択が、バックグラウンド追跡を密かに停止させます:

  • 「1回のみ許可」 これは一時的な「使用中のみ許可」の付与であり、アプリの使用が停止されると期限切れとなります。次回のセッションでは、再び「未決定」の状態から始まります。
  • 「使用中のみ許可」を選択した場合、「常に許可」へのアップグレードプロンプトは表示されません。 「常に許可」をリクエストしても、iOSは後で、OSが判断したタイミング(多くの場合、アプリが画面に表示されていない時)にアップグレードプロンプトを表示することがあります。

セッションを開始する前に、実際の状態を確認してください:

import { BackgroundGeolocation } from '@capgo/background-geolocation';

const status = await BackgroundGeolocation.checkPermissions();

if (status.location !== 'granted') {
  await BackgroundGeolocation.requestPermissions({ permissions: ['location'] });
}

if (status.backgroundLocation === 'when_in_use') {
  // Background tracking still works for standard updates.
  // Explain why Always helps if you also rely on geofences.
}

iOS の場合、 backgroundLocation を返します when_in_use または granted / always、推測ではなく正しい原因を提示できます。

原因5:Core Location による自動的な更新停止

CLLocationManager.pausesLocationUpdatesAutomatically のデフォルト設定は true。iOSがユーザーの移動がないと判断すると、バッテリー節約のために更新を一時停止します。「When In Use」権限のアプリの場合、一時停止されるとアプリが再起動されるまで位置情報のアクセスは終了し、Core Locationが自動的に再開することはありません。

Capgo プラグインは、 pausesLocationUpdatesAutomatically = false をネイティブの code 内で設定しているため、この問題は解決済みです。独自のネイティブ code を作成する場合や他のプラグインを使用する場合は、まずこのプロパティを確認してください。

原因6:デバイスが静止しており、フィルター値が大きい

を使用している場合、 distanceFilter が50メートルに設定されていると、机に置かれたスマホは更新を生成しません。これはログ上では「トラッキング停止」のように見えますが、設計通りの動作です。

  • 静止中もハートビートが必要な場合は、小さい値かゼロの distanceFilter.
  • 使用するのは minIntervalMs 大きな距離フィルターではなく、ネイティブのPOST送信頻度を制限します。
await BackgroundGeolocation.start(
  {
    backgroundMessage: 'Vehicle tracking active',
    distanceFilter: 0,
    minIntervalMs: 120_000, // at most one native POST every 2 minutes
    url: 'https://api.example.com/v1/vehicle-points',
  },
  () => {},
);

原因 7: 「正確な位置情報」がオフになっている

iOS 14以降、ユーザーはアプリの「正確な位置情報」をオフにできます。位置情報は取得できますが、精度が低くなり(数キロ単位)、更新頻度も大幅に減少します。データ上の大きな( accuracy 値)からこれを検知し、なぜその機能に正確な位置情報が必要なのかをユーザーに説明してください。配送やフィットネスアプリなら、走行後に伝えるのではなく、オンボーディングで説明しましょう。

原因 8: ユーザーによるアプリの強制終了

アプリスイッチャーでユーザーがアプリをスワイプして終了させると、iOSは標準的な位置情報の更新を停止します。どのプラグインでもこれを継続させることはできません。これは、タスク削除後もフォアグラウンドサービスが動作し続けるAndroidから移行してきたチームがよく直面する問題です。

対策:

  • セッション中にアプリを強制終了しないようユーザーに伝えます。多くのフリート管理アプリでは、これをオンボーディングで行っています。
  • 重要な場所に「常に許可」権限を用いたジオフェンスを追加します。これにより、エリアへの進入・退出時にiOSがバックグラウンドでアプリを再起動できるようになります。
  • サーバー側でセッション中のポイント受信が止まった場合、ユーザーにアプリの再開を促すプッシュ通知を送信します。

原因 9: ネイティブは動作しているが、JavaScriptが実行されていない

見落としがちな原因です。WebViewがサスペンド状態にあるとき、あるいはWebViewは生存しているもののタイマーやネットワークコールが迅速に処理できないときでも、ネイティブの code は位置情報を受信できます。もし、 fetch コールバックからの通知は、遅れて届くことも、まったく届かないこともあります。

プラグインの url オプションを使用してください。各ポイントはネイティブの code から、次と同じ JSON で POST されます。 Location タイプに加え、 "source": "native"WebView とは独立して動作します。コールバックは UI 更新専用にしてください。オンディスクキューを持たないベストエフォート配信なので、ポイントを失えない場合はコールバック発火時にローカルにも保存し、後で突き合わせてください。

位置情報以外のバックグラウンド処理については、以下を参照してください。 Capacitor でのバックグラウンドタスクの仕組み および、 @capgo/capacitor-background-task.

原因 10: 低電力モードとサーマルステート

低電力モードはシステム全体のバックグラウンドアクティビティを抑制します。位置情報は動作しますが、セッションが依存する他の処理(ネットワークの再試行やバックグラウンド更新など)が遅くなります。リリースを承認する前に、必ず低電力モードをオンにしてテストしてください。

青いインジケーター

「使用中のみ許可」の権限を持つアプリがバックグラウンドで位置情報を使用すると、iOS はステータスバーに青いピルを表示します。Capgo プラグインは、 showsBackgroundLocationIndicator へ true ユーザーが期待し、レビュアーも確認するバックグラウンドセッションとして実装してください。隠そうとせず、ユーザーに信頼してもらうことが重要です。

これらのバグを確実に防ぐテストプラン

バックグラウンドでの位置情報はシミュレーターでは不十分です。実機のiPhoneを使用し、以下を行ってください:

  1. DebugではなくRelease構成でビルドしてください。Xcodeに接続したDebugビルドは、ライフサイクルの挙動が異なります。
  2. フォアグラウンドでセッションを開始し、端末をロックして、20分間歩行またはドライブしてください。
  3. 「1回のみ許可」、位置情報の精度オフ、低電力モードONの状態で繰り返しテストしてください。
  4. 以下の内容をサーバーログで確認してください: source: "native" アプリ内のログだけでなく、データポイントを確認してください。
  5. セッション中にアプリを強制終了し、次回起動時にアプリが状況を適切に説明できるか確認してください。

ad hocビルドにデバイスのUDIDが必要な場合は、 iOS UDID finder Safariから取得します。ビルド用にXcode 26を搭載したMacをお持ちでない場合でも、 Capgo Build クラウド上で署名済みのiOSビルドを作成できます。

トラブルシューティング・チェックリスト

症状 考えられる原因 解決策
ロック後数秒で停止する いいえ location バックグラウンドモードの設定漏れ backgroundMessage plistにキーを追加して設定してください backgroundMessage
起動時にクラッシュする allowsBackgroundLocationUpdates バックグラウンドモードなし 追加 UIBackgroundModes → location
一度動いて、その後停止 ユーザーが「1回のみ許可」を選択 理由を説明して再要求、または〜へ送信 openSettings()
停車時に停止 大きい distanceFilter 下げて使用 minIntervalMs
地点が離れすぎ、精度が低い 「正確な位置情報」がオフ AIに聞く
アプリをスイープすると停止 ユーザーによるアプリの強制終了 iOSの仕様です。再起動にはジオフェンスを使用してください
ネイティブ側は取得できますが、サーバー側は取得できません JavaScript fetch コールバック内 また、 url オプション

修正プログラムの配信

これらの修正の多くは、 Info.plist ネイティブの設定に関わるため、App Storeでの新しいビルドが必要です。一方、権限の説明、onboardingのコピー、リトライロジックなどのJavaScript部分は、 Capgo Live Update を利用する ネイティブビルドのリリース後に既存ユーザーへ配信可能です。

プラグイン選びで迷っているなら、当社の比較記事が Transistorsoftと無料のCapgoプラグインの トレードオフを解説しています。

Capacitor アプリ向けの Live Update

Webレイヤーのバグが本番に出たときは、アプリストアの審査を何日も待たずに Capgo で修正を配信できます。ネイティブの変更は通常の審査フローに乗せたまま、ユーザーにはバックグラウンドでアップデートが届きます。

最新のブログ記事

Capgo は、本格的なプロフェッショナルモバイルアプリの開発に必要な最高のインサイトを提供します。