axiom-core-location-ref について
Core Location を扱う iOS 開発者向けの API リファレンスです。iOS 17 以降の新しい API と従来の実装パターンを取り上げ、位置情報更新、ジオフェンス、認証、バックグラウンド設定を説明します。
主な機能
- 01最新の位置情報更新 API
- 02ジオフェンスとビーコン監視
- 03認証と精度の管理
- 04バックグラウンド位置情報の設定
- 05従来 API のリファレンス
活用シーン
- 01ジオフェンスや領域監視の実装
- 02バックグラウンド追跡の設定
- 03位置情報の認証やサービスの問題調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ charleswiltgen/ axiom --skill axiom-core-location-refインストール後、Claude Code で/axiom-core-location-refを入力して読み込まれたか確認します。
詳細
Core Location リファレンス
最新の Core Location(iOS 17 以降)の包括的な API リファレンスです。
使用する場面
- CLLocationUpdate、CLMonitor、CLServiceSession の API シグネチャが必要な場合
- ジオフェンシングや領域モニタリングを実装する場合
- バックグラウンドでの位置情報更新を設定する場合
- 認証パターンを理解する場合
- 位置情報サービスの問題をデバッグする場合
関連するスキル
axiom-core-location— アンチパターン、判断ツリー、負荷のかかるシナリオaxiom-core-location-diag— 症状に基づくトラブルシューティングaxiom-energy-ref— バッテリーサブシステムとしての位置情報(精度と電力の比較)
Part 1: 最新 API の概要(iOS 17 以降)
4 つの主要なクラスが、従来の CLLocationManager パターンに代わります。
| クラス | 目的 | iOS |
|---|---|---|
CLLocationUpdate | 位置情報更新の AsyncSequence | 17+ |
CLMonitor | 条件ベースのジオフェンシング/ビーコン | 17+ |
CLServiceSession | 宣言型の認証目標 | 18+ |
CLBackgroundActivitySession | バックグラウンドでの位置情報サポート | 17+ |
移行パス:従来の CLLocationManager も引き続き動作しますが、新しい API では次の機能が利用できます。
- Swift の並行処理(async/await)
- 自動的な一時停止/再開
- 簡素化された認証
- バッテリー効率の向上
Part 2: CLLocationUpdate API
基本的な使い方
import CoreLocation
Task {
do {
for try await update in CLLocationUpdate.liveUpdates() {
if let location = update.location {
// Process location
}
if update.isStationary {
break // Stop when user stops moving
}
}
} catch {
// Handle location errors
}
}
LiveConfiguration のオプション
CLLocationUpdate.liveUpdates(.default)
CLLocationUpdate.liveUpdates(.automotiveNavigation)
CLLocationUpdate.liveUpdates(.otherNavigation)
CLLocationUpdate.liveUpdates(.fitness)
CLLocationUpdate.liveUpdates(.airborne)
ユースケースに応じて選択します。判断に迷う場合は、.default を使用するか、パラメーターを省略してください。
主なプロパティ
| プロパティ | 型 | 説明 |
|---|---|---|
location | CLLocation? | 現在地(取得できない場合は nil) |
isStationary | Bool | デバイスの移動が停止している場合は true |
authorizationDenied | Bool | ユーザーが位置情報へのアクセスを拒否した |
authorizationDeniedGlobally | Bool | システム全体で位置情報サービスが無効になっている |
authorizationRequestInProgress | Bool | ユーザーの認証判断を待機中 |
accuracyLimited | Bool | 精度が制限されている(15~20 分ごとに更新) |
locationUnavailable | Bool | 位置情報を特定できない |
insufficientlyInUse | Bool | 認証を要求できない(フォアグラウンドにない) |
自動的な一時停止/再開
デバイスが静止状態になると、次のようになります。
isStationary = trueかつ有効なlocationとともに、最後の更新が配信されます- 更新が一時停止します(バッテリーを節約します)
- デバイスが移動すると、
isStationary = falseで更新が再開します
操作は不要です。自動的に行われます。
AsyncSequence の操作
// Get first location with speed > 10 m/s
let fastUpdate = try await CLLocationUpdate.liveUpdates()
.first { $0.location?.speed ?? 0 > 10 }
// WARNING: Avoid filters that may never match (e.g., horizontalAccuracy < 1)
Part 3: CLMonitor API
地理的な条件やビーコンをモニタリングするための Swift アクターです。
基本的なジオフェンシング
let monitor = await CLMonitor("MyMonitor")
// Add circular region
let condition = CLMonitor.CircularGeographicCondition(
center: CLLocationCoordinate2D(latitude: 37.33, longitude: -122.01),
radius: 100
)
await monitor.add(condition, identifier: "ApplePark")
// Await events
for try await event in monitor.events {
switch event.state {
case .satisfied: // User entered region
handleEntry(event.identifier)
case .unsatisfied: // User exited region
handleExit(event.identifier)
case .unknown:
break
@unknown default:
break
}
}
CircularGeographicCondition
CLMonitor.CircularGeographicCondition(
center: CLLocationCoordinate2D,
radius: CLLocationDistance // meters, minimum ~100m effective
)
BeaconIdentityCondition
粒度は次の 3 段階です。
// All beacons with UUID (any site)
CLMonitor.BeaconIdentityCondition(uuid: myUUID)
// Specific site (UUID + major)
CLMonitor.BeaconIdentityCondition(uuid: myUUID, major: 100)
// Specific beacon (UUID + major + minor)
CLMonitor.BeaconIdentityCondition(uuid: myUUID, major: 100, minor: 5)
条件の上限
アプリごとに条件は最大 20 件です。 モニタリングする項目の優先順位を付けてください。必要に応じて、ユーザーの位置に基づいて動的に領域を切り替えます。
状態を仮定して追加する
// If you know initial state
await monitor.add(condition, identifier: "Work", assuming: .unsatisfied)
仮定が間違っている場合は、Core Location が修正します。
レコードへのアクセス
// Get single record
if let record = await monitor.record(for: "ApplePark") {
let condition = record.condition
let lastEvent = record.lastEvent
let state = lastEvent.state
let date = lastEvent.date
}
// Get all identifiers
let allIds = await monitor.identifiers
イベントのプロパティ
| プロパティ | 説明 |
|---|---|
identifier | 条件を示す文字列識別子 |
state | .satisfied、.unsatisfied、.unknown |
date | 状態が変化した日時 |
refinement | ワイルドカードビーコンの場合、検出された実際の UUID/major/minor |
conditionLimitExceeded | 条件が多すぎる(上限は 20 件) |
conditionUnsupported | 条件の種類を利用できない |
accuracyLimited | 精度の制限によりモニタリングできない |
重要な要件
- 名前ごとにモニターは 1 つ — 同じ名前のインスタンスは、同時に 1 つのみ使用できます
- イベントは必ず await する — イベントの処理後にのみ
lastEventに反映されます - 起動時に再初期化する —
didFinishLaunchingWithOptionsでモニターを再作成します
Part 4: CLServiceSession API(iOS 18 以降)
宣言型の認証です。何をするかではなく、必要なものを Core Location に伝えます。
基本的な使い方
// Hold session for duration of feature
let session = CLServiceSession(authorization: .whenInUse)
for try await update in CLLocationUpdate.liveUpdates() {
// Process updates
}
認証要件
CLServiceSession(authorization: .none) // No auth request
CLServiceSession(authorization: .whenInUse) // Request When In Use
CLServiceSession(authorization: .always) // Request Always (must start in foreground)
高精度の位置情報をリクエストする
// For features requiring precise location (e.g., navigation)
CLServiceSession(
authorization: .whenInUse,
fullAccuracyPurposeKey: "NavigationPurpose" // Key in Info.plist
)
Info.plist に NSLocationTemporaryUsageDescriptionDictionary が必要です。
暗黙のセッション
CLLocationUpdate.liveUpdates() または CLMonitor.events を反復処理すると、.whenInUse を目標とする暗黙のセッションが作成されます。
暗黙のセッションを無効にするには:
<key>NSLocationRequireExplicitServiceSession</key>
<true/>
セッションの重ね合わせ
セッションを置き換えるのではなく、重ねて使用します:
// Base session for app
let baseSession = CLServiceSession(authorization: .whenInUse)
// Additional session when navigation feature active
let navSession = CLServiceSession(
authorization: .whenInUse,
fullAccuracyPurposeKey: "Nav"
)
// Both sessions active simultaneously
診断プロパティ
for try await diagnostic in session.diagnostics {
if diagnostic.authorizationDenied {
// User denied—offer alternative
}
if diagnostic.authorizationDeniedGlobally {
// Location services off system-wide
}
if diagnostic.insufficientlyInUse {
// Can't request auth (not foreground)
}
if diagnostic.alwaysAuthorizationDenied {
// Always auth specifically denied
}
if !diagnostic.authorizationRequestInProgress {
// Decision made (granted or denied)
break
}
}
セッションのライフサイクル
セッションは次の状況でも維持されます:
- アプリがバックグラウンドに移行したとき
- アプリが一時停止したとき
- アプリが終了したとき(Core Location が追跡します)
再起動時には、didFinishLaunchingWithOptions で直ちにセッションを再作成します。
パート 5:認証状態の状態機械
認証レベル
| ステータス | 説明 |
|---|---|
.notDetermined | ユーザーはまだ決定していません |
.restricted | ペアレンタルコントロールによりアクセスが制限されています |
.denied | ユーザーが明示的に拒否しました |
.authorizedWhenInUse | アプリがアクティブな間のアクセス |
.authorizedAlways | バックグラウンドでのアクセス |
精度の認証
| 値 | 説明 |
|---|---|
.fullAccuracy | 正確な位置情報 |
.reducedAccuracy | おおよその位置情報(約5km)、15~20分ごとに更新 |
必須の Info.plist キー
<key>NSLocationWhenInUseUsageDescription</key>
<string>We need your location to show nearby places</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>We track your location to send arrival reminders</string>
<key>NSLocationDefaultAccuracyReduced</key>
<true/>
従来の認証パターン
@MainActor
class LocationManager: NSObject, CLLocationManagerDelegate {
private let manager = CLLocationManager()
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
switch manager.authorizationStatus {
case .notDetermined:
manager.requestWhenInUseAuthorization()
case .authorizedWhenInUse, .authorizedAlways:
enableLocationFeatures()
case .denied, .restricted:
disableLocationFeatures()
@unknown default:
break
}
}
}
パート 6:バックグラウンドでの位置情報
要件
- バックグラウンドモード機能:Signing & Capabilities → Background Modes → Location updates
- Info.plist:
UIBackgroundModesにlocationの値を追加します - CLBackgroundActivitySession または LiveActivity
CLBackgroundActivitySession
// Create and HOLD reference (deallocation invalidates session)
var backgroundSession: CLBackgroundActivitySession?
func startBackgroundTracking() {
// Must start from foreground
backgroundSession = CLBackgroundActivitySession()
Task {
for try await update in CLLocationUpdate.liveUpdates() {
processUpdate(update)
}
}
}
func stopBackgroundTracking() {
backgroundSession?.invalidate()
backgroundSession = nil
}
バックグラウンドインジケーター
次の場合に、青色のステータスバー/ピルが表示されます:
- アプリの認証が「使用中のみ」である
- アプリがバックグラウンドで位置情報を受信している
- CLBackgroundActivitySession がアクティブである
アプリのライフサイクル
- フォアグラウンド → バックグラウンド:セッションは継続します
- バックグラウンド → 一時停止:セッションは維持され、更新は一時停止します
- 一時停止 → 終了:Core Location がセッションを追跡します
- 終了 → バックグラウンドで起動:直ちにセッションを再作成します
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Recreate background session if was tracking
if wasTrackingLocation {
backgroundSession = CLBackgroundActivitySession()
startLocationUpdates()
}
return true
}
パート 7:従来の API(iOS 12-16)
CLLocationManager デリゲートパターン
class LocationManager: NSObject, CLLocationManagerDelegate {
private let manager = CLLocationManager()
override init() {
super.init()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.distanceFilter = 10 // meters
}
func startUpdates() {
manager.startUpdatingLocation()
}
func stopUpdates() {
manager.stopUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager,
didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
// Process location
}
}
精度定数
| 定数 | 精度 | バッテリーへの影響 |
|---|---|---|
kCLLocationAccuracyBestForNavigation | 約5m | 最大 |
kCLLocationAccuracyBest | 約10m | 非常に大きい |
kCLLocationAccuracyNearestTenMeters | 約10m | 大きい |
kCLLocationAccuracyHundredMeters | 約100m | 中程度 |
kCLLocationAccuracyKilometer | 約1km | 小さい |
kCLLocationAccuracyThreeKilometers | 約3km | 非常に小さい |
kCLLocationAccuracyReduced | 約5km | 最小 |
従来のリージョン監視
// Deprecated in iOS 17, use CLMonitor instead
let region = CLCircularRegion(
center: coordinate,
radius: 100,
identifier: "MyRegion"
)
region.notifyOnEntry = true
region.notifyOnExit = true
manager.startMonitoring(for: region)
重要な位置情報の変更
概略的な追跡に使える低消費電力の代替手段:
manager.startMonitoringSignificantLocationChanges()
// Updates ~500m movements, works in background
滞在の監視
到着/出発を検出します:
manager.startMonitoringVisits()
func locationManager(_ manager: CLLocationManager, didVisit visit: CLVisit) {
let arrival = visit.arrivalDate
let departure = visit.departureDate
let coordinate = visit.coordinate
}
パート 8:ジオフェンシングのベストプラクティス
リージョンのサイズ
- 実用上の最小半径:約100メートル
- より小さいリージョン:確実にトリガーされない場合があります
- より大きいリージョン:信頼性は高まりますが、精度は下がります
20リージョン制限への対策
// Dynamic region management
func updateMonitoredRegions(userLocation: CLLocation) async {
let nearbyPOIs = fetchNearbyPOIs(around: userLocation, limit: 20)
// Remove old regions
for id in await monitor.identifiers {
if !nearbyPOIs.contains(where: { $0.id == id }) {
await monitor.remove(id)
}
}
// Add new regions
for poi in nearbyPOIs {
let condition = CLMonitor.CircularGeographicCondition(
center: poi.coordinate,
radius: 100
)
await monitor.add(condition, identifier: poi.id)
}
}
入退出のタイミング
- 入場:通常、数秒から数分以内
- 退出:離れてから3~5分かかることがあります
- 精度は次の要素に依存します:携帯電話基地局、WiFi、GPS の利用可否
永続性
- 条件はアプリの起動をまたいで維持されます
- 起動時に同じ名前でモニターを再初期化する必要があります
- Core Location はイベント発生時にアプリを起動します
パート 9:テストとシミュレーション
Xcode の位置情報シミュレーション
- シミュレーターで実行します
- Debug → Simulate Location → 位置を選択します
- またはカスタム GPX ファイルを使用します
カスタム GPX ルート
<?xml version="1.0"?>
<gpx version="1.1">
<wpt lat="37.331686" lon="-122.030656">
<time>2024-01-01T00:00:00Z</time>
</wpt>
<wpt lat="37.332686" lon="-122.031656">
<time>2024-01-01T00:00:10Z</time>
</wpt>
</gpx>
認証状態のテスト
設定 → プライバシーとセキュリティ → 位置情報サービス:
- アプリの認証を切り替えます
- システム全体の位置情報サービスを切り替えます
- 精度を下げた状態をテストします
コンソールのフィルタリング
# Filter location logs
log stream --predicate 'subsystem == "com.apple.locationd"'
パート 10:Swift Concurrency との統合
タスクのキャンセル
let locationTask = Task {
for try await update in CLLocationUpdate.liveUpdates() {
if Task.isCancelled { break }
processUpdate(update)
}
}
// Later
locationTask.cancel()
MainActor に関する考慮事項
@MainActor
class LocationViewModel: ObservableObject {
@Published var currentLocation: CLLocation?
func startTracking() {
Task {
for try await update in CLLocationUpdate.liveUpdates() {
// Already on MainActor, safe to update @Published
self.currentLocation = update.location
}
}
}
}
エラー処理
Task {
do {
for try await update in CLLocationUpdate.liveUpdates() {
if update.authorizationDenied {
throw LocationError.authorizationDenied
}
processUpdate(update)
}
} catch {
handleError(error)
}
}
パート 11:ジオコーディング
CLGeocoder — 前方ジオコーディング(住所 → 座標)
let geocoder = CLGeocoder()
func geocodeAddress(_ address: String) async throws -> CLLocation? {
let placemarks = try await geocoder.geocodeAddressString(address)
return placemarks.first?.location
}
// With locale for localized results
let placemarks = try await geocoder.geocodeAddressString(
"1 Apple Park Way",
in: nil, // CLRegion hint (optional)
preferredLocale: Locale(identifier: "en_US")
)
CLGeocoder — 逆ジオコーディング(座標 → 住所)
func reverseGeocode(_ location: CLLocation) async throws -> CLPlacemark? {
let placemarks = try await geocoder.reverseGeocodeLocation(location)
return placemarks.first
}
// Usage
if let placemark = try await reverseGeocode(location) {
let street = placemark.thoroughfare // "Apple Park Way"
let city = placemark.locality // "Cupertino"
let state = placemark.administrativeArea // "CA"
let zip = placemark.postalCode // "95014"
let country = placemark.country // "United States"
let isoCountry = placemark.isoCountryCode // "US"
}
CLPlacemark の主なプロパティ
| プロパティ | 例 | 説明 |
|---|---|---|
name | "Apple Park" | 場所の名前 |
thoroughfare | "Apple Park Way" | 通りの名前 |
subThoroughfare | "1" | 番地 |
locality | "Cupertino" | 市区町村 |
subLocality | "Silicon Valley" | 地区 |
administrativeArea | "CA" | 州・県 |
postalCode | "95014" | 郵便番号 |
country | "United States" | 国名 |
isoCountryCode | "US" | ISO 国コード |
timeZone | America/Los_Angeles | タイムゾーン |
location | CLLocation | 座標 |
ジオコーディングのレート制限
- 一度にリクエストは 1 件まで — リクエストの処理中に CLGeocoder を呼び出すとエラーが発生します
- Apple によるレート制限 —
kCLErrorGeocodeCanceledを避けるため、リクエストの頻度を抑えてください - 結果をキャッシュする — 同じ住所や座標を再度ジオコーディングしないでください
- バッチ処理は慎重に — 連続するジオコーディングリクエストの間に遅延を設けてください
// Check if geocoder is busy
if geocoder.isGeocoding {
geocoder.cancelGeocode() // Cancel previous before starting new
}
トラブルシューティング早見表
| 症状 | 確認項目 |
|---|---|
| 位置情報が更新されない | 認証ステータス、Info.plist のキー |
| バックグラウンドで動作しない | バックグラウンドモードの機能、CLBackgroundActivitySession |
| 「常に許可」が有効にならない | .always を指定した CLServiceSession、フォアグラウンドで開始しているか |
| ジオフェンスが作動しない | リージョン数(最大 20)、半径(最小約 100 m) |
| 精度が低い状態のまま | accuracyAuthorization を確認し、一時的なフル精度をリクエストする |
| 位置情報アイコンが消えない | stopUpdatingLocation() を呼び出すか、非同期ループから抜けていることを確認する |
リソース
WWDC: 2023-10180, 2023-10147, 2024-10212
ドキュメント: /corelocation, /corelocation/clmonitor, /corelocation/cllocationupdate, /corelocation/clservicesession
スキル: axiom-core-location, axiom-core-location-diag, axiom-energy-ref