> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ones1ght.com/llms.txt
> Use this file to discover all available pages before exploring further.

# iOS 設定ガイド

## システム要件

| 項目 | 要件 |
| - | - |
| OS | iOS 27 以上（アプリの最小ターゲットは iOS 18） |
| 対応端末 | UWB チップ搭載の iPhone 12 以上（iPhone SE・iPad・Apple Watch は非対応） |
| 開発環境 | Xcode 27 以上 |
| 言語 | Swift 5 以上・Objective-C（[ブリッジ経由](/ja/developers/sdk/reference/ios#objective-c-ブリッジ)） |
| パッケージ管理 | Swift Package Manager |

測位情報を受信できない端末では SDK が動作を停止し、稼働中のアプリには影響しません。

## SDK のインストール

**Step 1**

Xcode で **\[File] → \[Add Package Dependencies…]** を実行します。

**Step 2**

左上の検索欄に以下の URL を入力します。

```text theme={null}
https://github.com/onecheck-inc/OneS1ght-iOS-SDK
```

**Step 3**

**Dependency Rule** を `Up to Next Major Version` にし、値を `0.2.2` に設定します。

**Step 4**

**\[Add Package]** を押して `OneS1ght` ライブラリをアプリターゲットに追加します。

## iOS 権限設定

`Info.plist` に以下 5 つの権限説明文を 1 つも欠かさず設定します。

| キー | 権限 | 用途 |
| - | - | - |
| `NSBluetoothAlwaysUsageDescription` | Bluetooth 権限 | ロケーターの BLE 受信用 |
| `NSLocationWhenInUseUsageDescription` | 位置情報権限 | ロケーターの位置確認用 |
| `NSLocationAlwaysAndWhenInUseUsageDescription` | 位置情報権限（常に） | フロア検出用 （iOS 27.2 以上で BLE によるフロア判定に必要） |
| `NSLocationTemporaryUsageDescriptionDictionary` | 正確な位置情報権限 | 正確な屋内位置の計算用 内側のキーは必ず `Positioning` |
| `NSNearbyInteractionUsageDescription` | Nearby Interaction | ユーザーの高精度測位用 |

Xcode でアプリターゲットの **\[Info]** タブの一覧に追加します。

**1. String キー 4 つ**

行にマウスを重ねると表示される **\[+]** を押し、Key にキー名、Value に説明文を入力します。Type は String です。

**2. Dictionary キー 1 つ**

`NSLocationTemporaryUsageDescriptionDictionary` は 2 段構成です。

1. **\[+]** → Key にキー名を入力 → Type を **Dictionary** に変更します（Value は空のままにします）。
2. 行の左の **▸** を開き、その行で **\[+]** → Key に `Positioning`、Type を String、Value に説明文を入力します。

**3. 確認**

一覧に 5 項目がすべて表示されれば完了です。セクションの見出しが **Custom macOS Application Target Properties** と表示されていても問題ありません。

Value に入れる説明文は以下の `<string>` の値をそのまま使えます。Xcode の画面ではなくファイルに直接書く方法は[付録](#付録)を参照してください。

```xml Info.plist theme={null}
<key>NSBluetoothAlwaysUsageDescription</key>
<string>周辺の測位機器を探すために使用します。</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>店舗内での位置確認のために使用します。</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>iOS 27.2 以上で店舗のフロアを特定するために使用します。</string>
<key>NSLocationTemporaryUsageDescriptionDictionary</key>
<dict>
    <key>Positioning</key>
    <string>正確な屋内位置を計算するために使用します。</string>
</dict>
<key>NSNearbyInteractionUsageDescription</key>
<string>UWB 高精度測位のために使用します。</string>
```

## SDK の初期化

SDK を初期化すると、SDK 内部のエンジンを実行できるようになります。

| 関数・プロパティ | 説明 | 戻り値 |
| - | - | - |
| `initialize(sdkKey:)` | キーの検証と設定の取得。アプリ起動時に 1 回 | なし |
| `isInitialized` | 初期化に成功したか | `Bool` |
| `sdkVersion` | SDK バージョン | `String`（例: `"0.2.3"`） |

Objective-C ブリッジは同名のメソッドで、結果を completion ブロックで返します。\

ブリッジのコールバック（`onPosition`・`onZoneEnter`・`onFloorDetected`・`onConfigChanged`・`onStopped` など）は `initialize` が成功した後に登録してください。それより前に登録しても何も起きません（`onDebugLog` は例外）。

```swift Swift icon="swift" theme={null}
import OneS1ght

#if DEBUG
let sdkKey = "YOUR_DEVELOPMENT_API_KEY" // 開発（テスト）モードで使用する場合
#else
let sdkKey = "YOUR_PRODUCTION_API_KEY"  // 本番モードで使用する場合
#endif
try await OneS1ght.initialize(sdkKey: sdkKey)
```

```objc Objective-C icon="apple" theme={null}
#import "MyApp-Swift.h"   // MyApp には Product Module Name。ブリッジファイルを追加して 1 回ビルドすると生成されます。

#ifdef DEBUG
NSString *sdkKey = @"YOUR_DEVELOPMENT_API_KEY"; // 開発（テスト）モードで使用する場合
#else
NSString *sdkKey = @"YOUR_PRODUCTION_API_KEY";  // 本番モードで使用する場合
#endif
[OneS1ghtBridge initializeWithSdkKey:sdkKey completion:^(NSError *error) {
    if (error) { return; }   // 失敗処理
}];
```

## プロフィール

ユーザー（アカウントまたは端末）1 人の動線は**プロフィール**単位で管理されます。\

プロフィール ID は一意で、紛失すると復元できないため保管に注意してください。

| 関数・プロパティ | 説明 | 戻り値 |
| - | - | - |
| `createProfile(_:)` | 属性からプロフィールを作成 | `String`（プロフィール ID） |
| `identify(profileId:)` | この端末の測位をプロフィールに紐付け。 解除する場合は `nil` | なし |
| `fetchProfile(_:)` | プロフィール ID で属性を取得 | `[String: String]` |
| `replaceProfile(_:attributes:)` | 属性をすべて置き換え | なし |
| `deleteProfile(_:)` | プロフィールを削除 | なし |

### プロフィールの作成

新しいプロフィールを作成するとプロフィール ID が返ります。属性はレポート・指標のセグメントとして使われ、Key-Value に制約はありません。\

発行された ID はアプリ（または自社サーバー）に保管し、起動のたびに測位前に `identify` で紐付けます。

> [!WARNING]
>
> プロフィール属性に氏名・電話番号・会員 ID のような機微な情報を入れないでください。\\
>
> 年代（`"20s"`）のように個人を特定できない値だけを入れます。

```swift Swift icon="swift" theme={null}
let profileId = try await OneS1ght.createProfile(["gender": "F", "ageBand": "20s"])   // 新しいプロフィールを作成 → プロフィール ID を返す
save(profileId)                                                                     // アプリまたは自社サーバーに保管

OneS1ght.identify(profileId: savedProfileId)   // 起動のたびに測位前に紐付け。ログアウト時は nil
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge createProfile:@{ @"gender": @"F", @"ageBand": @"20s" }                 // 新しいプロフィールを作成 → プロフィール ID を返す
                    completion:^(NSString *profileId, NSError *error) {
    if (!error) { [self save:profileId]; }                                          // アプリまたは自社サーバーに保管
}];

[OneS1ghtBridge identifyWithProfileId:savedProfileId];   // 起動のたびに測位前に紐付け。ログアウト時は nil
```

### プロフィール情報の取得

プロフィール ID から、保存されたパーソナライズ属性を取得します。

```swift Swift icon="swift" theme={null}
let attributes = try await OneS1ght.fetchProfile(profileId)   // ["gender": "F", "ageBand": "20s"]
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge fetchProfile:profileId completion:^(NSDictionary *attributes, NSError *error) {
    if (error) { return; }   // 存在しない ID
}];
```

### プロフィール情報の更新

パーソナライズ属性は**まるごと置き換え**られます。更新後、以前の値は削除され、元に戻せません。

```swift Swift icon="swift" theme={null}
try await OneS1ght.replaceProfile(profileId, attributes: ["gender": "F", "ageBand": "30s"])   // 属性をすべて置き換え
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge replaceProfile:profileId attributes:@{ @"gender": @"F", @"ageBand": @"30s" }   // 属性をすべて置き換え
                    completion:^(NSError *error) { }];
```

### プロフィールの削除

パーソナライズ属性を削除します。削除した属性は元に戻せません。

```swift Swift icon="swift" theme={null}
try await OneS1ght.deleteProfile(profileId)
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge deleteProfile:profileId completion:^(NSError *error) { }];
```

## 建物・フロアの選択

フロアの指定は任意です。指定しなくても、測位エンジンがロケーターの BLE 信号からフロアを見つけて座標を送ります。\

ただし、ゾーンイベントを受け取るにはフロアの指定が必要です（[ゾーンイベント](#ゾーンイベント)を参照）。

| 関数・プロパティ | 説明 | 戻り値 |
| - | - | - |
| `floorSession()` | 測位セッション | `FloorSession` |
| `session.onFloorDetected` | エンジンがフロアを検出すると呼ばれる。 フロアを見失うと `nil` | `(String?)`（フロア ID） |
| `buildings()` | コンソールに登録された建物一覧 | `[Building]`  `id`: 建物 ID  `name`: 建物名  `floorCount`: フロア数 |
| `floors(buildingId:)` | 建物のフロア一覧（図面画像なし） | `[Floor]` |
| `floor(buildingId:floorId:)` | フロア 1 件（図面画像あり） | `Floor` |
| `setFloorMap(_:buildingId:)` | フロアを指定  解除する場合は `nil` | なし |
| `session.floor` | 現在指定されているフロア | `Floor?` |

### BLE 受信で選択

SDK の測位エンジンがロケーターの BLE 信号からフロアを検出すると、`onFloorDetected` にフロア ID が届きます。\

フロアを見失うと `nil` が届きます。

```swift Swift icon="swift" theme={null}
let session = try OneS1ght.floorSession()   // 測位セッションを取得
session.onFloorDetected = { floorId in      // エンジンがフロアを検出するとフロア ID を渡す
    guard let floorId else { return }
    Task {
        let floor = try await OneS1ght.floor(buildingId: buildingId, floorId: floorId)   // フロア情報を取得
        try await OneS1ght.setFloorMap(floor, buildingId: buildingId)                   // フロアを指定
    }
}
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge onFloorDetected:^(NSString *floorId) {   // エンジンがフロアを検出するとフロア ID を渡す
    if (!floorId) { return; }
    [OneS1ghtBridge setFloorMapWithBuildingId:buildingId floorId:floorId completion:^(NSError *error) { }];   // フロアを指定
}];
```

### 手動で選択

ユーザーにフロアを選ばせる場合や、測位前に地図を先に描画する場合は、建物とフロアを直接指定します。

```swift Swift icon="swift" theme={null}
let buildings = try await OneS1ght.buildings()                            // コンソールに登録された建物一覧
let floors    = try await OneS1ght.floors(buildingId: buildings[0].id)   // 建物のフロア一覧

try await OneS1ght.setFloorMap(floors[0], buildingId: buildings[0].id)   // フロアを指定
try await OneS1ght.setFloorMap(nil)                                      // フロア指定を解除
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge buildings:^(NSArray<NSDictionary *> *buildings, NSError *error) {                 // コンソールに登録された建物一覧
    NSString *buildingId = buildings.firstObject[@"id"];
    [OneS1ghtBridge floorsWithBuildingId:buildingId completion:^(NSArray<NSDictionary *> *floors, NSError *error) {   // フロア一覧
        [OneS1ghtBridge setFloorMapWithBuildingId:buildingId floorId:floors.firstObject[@"id"]
                                       completion:^(NSError *error) { }];   // フロアを指定
    }];
}];
[OneS1ghtBridge setFloorMapWithBuildingId:nil floorId:nil completion:^(NSError *error) { }];   // フロア指定を解除
```

## リアルタイム測位情報の受信

`floorSession()` で測位セッションを取得し、`begin()` で開始、`end()` で終了します。\

位置は `onPosition` で受け取り、座標（メートル）はエンジンが出す頻度のまま届きます。\

サーバーへ送る座標だけが、コンソール設定の頻度（既定は毎秒 4 回）に間引かれます。

| 状況 | 対応 |
| - | - |
| アプリがバックグラウンドへ移行 | 不要 — SDK が測位を止め、フォアグラウンドに戻ると自動で再開します。 |
| 画面を一時的に離れるとき | `pause()` で停止し、`resume()` で再開します。エンジンは動いたままなので、すぐに続きます。 |
| 測位を完全に終えるとき | `end()`。エンジンも停止するため、次の `begin()` はロケーターを最初から探し直します。 |

| 関数・プロパティ | 説明 | 戻り値 |
| - | - | - |
| `session.onPosition` | リアルタイム座標 | `(Coordinates)`  `x`・`y`: 図面基準のメートル  `z`: 高さ |
| `session.begin()` | 測位開始 | なし |
| `session.end()` | 測位終了 + 残りの座標を送信 | なし |
| `session.pause()` / `resume()` | 一時停止 / 再開 | なし |
| `session.isRunning` / `isPaused` | 測位中 / 一時停止中か | `Bool` |

```swift Swift icon="swift" theme={null}
let session = try OneS1ght.floorSession()
session.onPosition = { coord in updateMyLocationMarker(x: coord.x, y: coord.y) }   // coord.z: 高さ

try await session.begin()   // 測位開始
await session.end()         // 測位終了 + 残りの座標を送信
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge onPosition:^(double x, double y, double z) { [self updateMyLocationMarkerX:x y:y]; }];

[OneS1ghtBridge beginWithCompletion:^(NSError *error) { }];   // 測位開始
[OneS1ghtBridge endWithCompletion:^{ }];                       // 測位終了 + 残りの座標を送信
```

## ゾーンイベント

コンソールの[空間管理](/ja/console/areas)で描いたゾーンの進入・退出・滞在イベントを受け取ります。判定は端末内で行われるため、すぐに届きます。\

ゾーンに紐付いた施策（クーポン・サイネージなど）はサーバーがマッチングし、`onTriggers` で届きます。\

ゾーン一覧は `setFloorMap` で指定したフロアから取得します。フロアを指定しないとゾーンが空になり、`onZoneEnter`・`onZoneExit` は届かず `E3009` が記録されます。

| 関数・プロパティ | 説明 | 戻り値 |
| - | - | - |
| `session.onZoneEnter` / `onZoneExit` | ゾーン進入 / 退出 | `(Zone)`  `id`: ゾーン ID  `name`: ゾーン名  `polygon`: ゾーン形状（頂点リスト）  `dwellSeconds`: 滞在判定の基準（秒） |
| `session.onZoneDwell` | ゾーン滞在時  `dwellSeconds` 到達時に訪問ごとに 1 回 | `(Zone, TimeInterval)`  ゾーン、滞在時間（秒） |
| `session.onTriggers` | サーバーがマッチングしたパーソナライズアクション | `(String, [Trigger])`  ゾーン ID、トリガー一覧 （`triggerId`: トリガー ID  `type`: 種類 — `signage`・`coupon`・`tracking`・`merch`・`generic`  `payload`: 種類ごとの付加情報） |
| `session.onConfigChanged` | コンソールでゾーン設定が変更されたとき | `(ConfigChange)`  `.zonesChanged`: ゾーン変更  `.planChanged`: 図面変更  `.rulesChanged`: 施策変更  `.sdkConfigChanged`: SDK リモート設定変更  `.resyncNeeded`: 全体を再取得 （再接続後、またはイベントを取りこぼした可能性がある場合） |
| `refreshZones()` | ゾーン情報を最新化 | `[Zone]` |

```swift Swift icon="swift" theme={null}
session.onZoneEnter = { zone in showBanner("進入: \(zone.name)") }
session.onZoneExit  = { zone in hideBanner() }
session.onZoneDwell = { zone, seconds in showBanner("滞在: \(zone.name) — \(Int(seconds))秒") }
session.onTriggers  = { zoneId, triggers in triggers.forEach(handle) }   // type: signage · coupon · tracking · merch · generic
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge onZoneEnter:^(NSDictionary *zone) { [self showBanner:zone[@"name"]]; }];
[OneS1ghtBridge onZoneExit:^(NSDictionary *zone)  { [self hideBanner]; }];
[OneS1ghtBridge onZoneDwell:^(NSDictionary *zone, double seconds) { [self showDwell:zone[@"name"] seconds:seconds]; }];
[OneS1ghtBridge onTriggers:^(NSString *zoneId, NSArray<NSDictionary *> *triggers) {
    for (NSDictionary *trigger in triggers) { [self handle:trigger]; }   // triggerId · type · payload
}];
```

### ゾーン情報の更新

コンソールでゾーン情報が変わると `onConfigChanged` が呼ばれます。SDK は呼び出し回数を間引きません。\

ゾーンを再取得するたびに進入・退出の判定が最初からやり直しになるため、続けて届く通知はアプリ側で 1 秒ほどまとめて 1 回だけ処理してください。

```swift Swift icon="swift" theme={null}
var refreshTask: Task<Void, Never>?
session.onConfigChanged = { change in
    switch change {
    case .zonesChanged, .resyncNeeded:
        refreshTask?.cancel()                             // 続けて届いたら最後の 1 回だけ
        refreshTask = Task {
            try? await Task.sleep(for: .seconds(1))
            guard !Task.isCancelled else { return }
            _ = await OneS1ght.refreshZones()
        }
    case .planChanged:                 reloadFloorPlan()   // 図面が変わった
    default:                           break
    }
}
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge onConfigChanged:^(NSString *kind, NSString *targetId) {
    if ([kind isEqualToString:@"zonesChanged"] || [kind isEqualToString:@"resyncNeeded"]) {
        [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(reloadZones) object:nil];
        [self performSelector:@selector(reloadZones) withObject:nil afterDelay:1.0];   // 1 秒まとめて 1 回だけ — reloadZones で refreshZones: を呼ぶ
    } else if ([kind isEqualToString:@"planChanged"]) {
        [self reloadFloorPlan];   // 図面が変わった
    }
}];
```

## 図面の表示

ロケーターに紐付く図面と、ユーザーの現在位置を表示できます。\

図面を設定しない場合、背景はグリッドで表示されます。

| 関数・プロパティ | 説明 | 戻り値 |
| - | - | - |
| `floor(buildingId:floorId:)` | フロア詳細 | `Floor` `image: Data?`: 図面画像 `hasPlan`: 図面登録の有無 `originX`: 図面原点 X（メートル） `originY`: 図面原点 Y（メートル） `widthM`: 横幅（メートル） `heightM`: 縦幅（メートル）  `minX`: X の最小値  `minY`: Y の最小値 `maxX`: X の最大値 `maxY`: Y の最大値 |
| `locators(buildingId:floorId:)` | フロアのロケーター情報 | `FloorLocators` `locators`: ロケーター情報 （`address`: UWB MAC の下位 2 バイト（`Int`）、  `x`・`y`・`z`: ロケーター座標） `sessionId`: UWB セッション ID `positioningReady`: 測位可能か |

```swift Swift icon="swift" theme={null}
let floor = try await OneS1ght.floor(buildingId: buildingId, floorId: floorId)
planView.image = floor.image.flatMap(UIImage.init(data:))
setBounds(minX: floor.minX, minY: floor.minY, maxX: floor.maxX, maxY: floor.maxY)
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge floorWithBuildingId:buildingId floorId:floorId completion:^(NSDictionary *floor, NSError *error) {
    self.planView.image = floor[@"image"] ? [UIImage imageWithData:floor[@"image"]] : nil;
    // 範囲: originX・originY・widthM・heightM（メートル）
}];
```

## その他のオプション

| 関数・プロパティ | 説明 | 戻り値 |
| - | - | - |
| `uploadPendingPositions()` | アプリ内に溜めた座標を即時送信 | なし |
| `discardPendingPositions()` | アプリ内に溜めた座標を破棄 | なし |
| `reset()` | セッションを破棄（破棄後は `initialize` の再呼び出しが必要） | なし |
| `session.onStopped` | セッション停止 | `(StopReason)`: 停止理由  `.ended`: セッション終了（正常）  `.engineFailed`: エンジン異常（失敗） |
| `OneS1ght.onDebugLog` | SDK デバッグ用 | `(LogLevel, String)` ログを返す |

### データ送信の制御

座標は **300 件たまったとき**、および `begin()` から **60 秒ごとに**自動で送信されます（300 件の送信で 60 秒の周期がリセットされることはありません）。\

バックグラウンドへの移行時と `end()` のときも残りの座標を送信します。ただし、アプリが強制終了されると座標は破棄されます。

```swift Swift icon="swift" theme={null}
await OneS1ght.uploadPendingPositions()   // 溜めた座標を今すぐ送信
OneS1ght.discardPendingPositions()        // 送信せずに破棄
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge uploadPendingPositions:^{ }];   // 溜めた座標を今すぐ送信
[OneS1ghtBridge discardPendingPositions];       // 送信せずに破棄
```

### セッションのリセット

測位を止めてセッションを破棄します。保存されたキーも消えるため、`initialize` を再度呼ぶまで API は `notInitialized` エラーになります。\

アプリを再ビルドせずに別のキーへ切り替えるときに使います。

```swift Swift icon="swift" theme={null}
await OneS1ght.reset()
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge reset:^{ }];
```

### 測位終了時の処理

測位エンジンが終了すると `onStopped` イベントが発生し、測位可能な状態へ戻せます。

```swift Swift icon="swift" theme={null}
session.onStopped = { reason in
    if case .engineFailed = reason { showRetrySearch() }   // 原因を解消して begin() をやり直す
}
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge onStopped:^(NSString *reason) {
    if ([reason isEqualToString:@"engineFailed"]) { [self showRetrySearch]; }   // 原因を解消して begin をやり直す
}];
```

### 対応端末の確認

`deviceAvailability` はネットワーク（インターネット）接続なしで即時に確認でき、\

測位に対応しない端末でもアプリの動作には影響しません。

| 関数・プロパティ | 説明 | 戻り値 |
| - | - | - |
| `deviceAvailability` | 端末の対応状況（詳細） | `DeviceAvailability` `.available`: 対応端末 `.osVersionTooLow`: OS 非対応  `.deviceNotSupported`: 測位情報を受信できない端末 |
| `isDeviceAvailable` | 端末の対応状況（要約） | `Bool` |

```swift Swift icon="swift" theme={null}
switch OneS1ght.deviceAvailability {
case .available:          break
case .osVersionTooLow:    showNotice("iOS 27 以上が必要です")
case .deviceNotSupported: hidePositioningFeatures()     // UWB 非対応端末
@unknown default:         break
}
```

```objc Objective-C icon="apple" theme={null}
NSString *availability = OneS1ghtBridge.deviceAvailability;   // @"available" · @"osVersionTooLow" · @"deviceNotSupported"
if (![availability isEqualToString:@"available"]) {
    [self hidePositioningFeatures];
}
```

## 付録

### Info.plist に直接書く

Xcode の **\[Info]** タブに表示される一覧は、実際には `Info.plist` というファイルの内容です。最近の Xcode で作成したプロジェクトはこのファイルを
表示せず、ビルド時に Xcode が自動生成するため、直接書くにはまずファイルを作る必要があります。
Dictionary キーを入れる途中で Xcode が終了してしまう場合も、この方法で追加できます。

**1. ファイルの有無を確認**

左のプロジェクトナビゲーターに `Info.plist` が表示されていれば、手順 3 へ進みます。

**2. ファイルを作成**

**\[File] → \[New] → \[File from Template…]** で **Property List** を選び、名前を `Info.plist`、保存先をアプリターゲットのフォルダーにします。
次に **\[Build Settings]** タブで `Info.plist File` を検索し、値に `ターゲット名/Info.plist` を入れます。
`Generate Info.plist File` は **Yes** のままにします — Xcode が自動生成項目とこのファイルを統合します。

**3. XML を貼り付け**

`Info.plist` を右クリック → **Open As → Source Code** で開き、[iOS 権限設定](#ios-権限設定)の XML を `<dict>` と `</dict>` の間に貼り付けます。

### 権限のリクエスト（Nearby Interaction）

ロケーターの測位情報は Apple の Nearby Interaction を使用します。`requestPermission()` はシステムの権限ダイアログを表示し、許可するかどうかはユーザーが決めます。\

一度拒否されるとアプリから再度リクエストできないため、設定アプリで権限をオンにするよう案内してください。

| 関数・プロパティ | 説明 | 戻り値 |
| - | - | - |
| `requestPermission()` | Nearby Interaction 権限をリクエスト | `PermissionStatus` `.authorized`: 許可 `.denied`: 拒否 `.unsupported`: 非対応端末 |

```swift Swift icon="swift" theme={null}
switch await OneS1ght.requestPermission() {
case .authorized:  break
case .denied:      showSettingsGuide()        // アプリから再リクエスト不可 — 設定アプリへ案内
case .unsupported: showUnsupportedNotice()    // 測位非対応端末
@unknown default:  break
}
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge requestPermission:^(NSString *status) {
    if ([status isEqualToString:@"denied"])      { [self showSettingsGuide]; }       // アプリから再リクエスト不可 — 設定アプリへ案内
    if ([status isEqualToString:@"unsupported"]) { [self showUnsupportedNotice]; }   // 測位非対応端末
}];
```

### 位置情報の常時許可

iOS 27.2 以降では、フロアを検出するには位置情報のアクセス権限が\*\*「常に」\*\*である必要があります（BLE ビーコン領域の検出）。iOS 27.1 以前は「アプリの使用中のみ」で足ります。\

SDK は「常に」をリクエストしません。権限がなくても SDK は起動しますが、フロアを見つけられません。ユーザーが拒否した場合は設定アプリへ案内してください。

```swift Swift icon="swift" theme={null}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
    if manager.authorizationStatus == .authorizedWhenInUse {
        manager.requestAlwaysAuthorization()   // iOS はこのダイアログをアプリごとに 1 回しか表示しません
    }
}
```

```objc Objective-C icon="apple" theme={null}
- (void)locationManagerDidChangeAuthorization:(CLLocationManager *)manager {
    if (manager.authorizationStatus == kCLAuthorizationStatusAuthorizedWhenInUse) {
        [manager requestAlwaysAuthorization];   // iOS はこのダイアログをアプリごとに 1 回しか表示しません
    }
}
```

### デバッグログ

デバッグログを確認するには、SDK の初期化（`initialize`）の**直前**に登録してください。\

下記のように `print` で出力したログは Xcode のデバッグコンソールで確認できます。

```swift Swift icon="swift" theme={null}
#if DEBUG
OneS1ght.onDebugLog = { level, line in print("[OneS1ght][\(level)] \(line)") }
#endif
```

```objc Objective-C icon="apple" theme={null}
#ifdef DEBUG
[OneS1ghtBridge onDebugLog:^(NSString *level, NSString *line) { NSLog(@"[OneS1ght][%@] %@", level, line); }];
#endif
```

## トラブルシューティング

> **[エラーコード](/ja/developers/sdk/troubleshooting/error-codes)**
>
> 開発中に発生するエラーの内容を案内します。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.