# Getting Started

This section lists how to configure offline navigation, initialize the SDK during app startup, and understand initialization state, concurrency behavior, and health checks.

## Install the SDK with Swift Package Manager

**Package URL:** [GitHub - nextbillion-ai/navigation-distribution](https://github.com/nextbillion-ai/navigation-distribution)

The NextBillion Navigation package product includes _NbmapNavigation_, _NbmapCoreNavigation_, _Nbmap_, and _Turf_. Do not add a separate, older Maps SDK package when using Swift Package Manager.

## Configure runtime behavior

Configure the Offline Navigation runtime once, then initialize the offline subsystem during app startup. Repeated or concurrent initialization calls with the same configuration are safe.

Configure the route mode and offline download network policy before calling _initializeOffline_.

```swift
import NbmapCoreNavigation

let runtimeConfig = NBNavigation.NavigationRuntimeConfig(
    routing: RoutingConfig(mode: .smart),
    offlineDownloadNetworkPolicy: .wifiOnly
)
NBNavigation.setNavigationRuntimeConfig(runtimeConfig)
```

-   The default download policy is `wifiOnly`.
-   Use `anyNetwork` to allow cellular downloads.
-   _NBNavigation_ can be used to update the routing strategy and download network policy.

**Configuration requirement**

> NBNavigation _configures the offline map base URL centrally. Do not read or set `resolvedBaseURL`, and do not repeatedly configure the Maps offline runtime in application methods_.

## Initialize during app startup

```swift
func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    NGLAccountManager.accessToken = "YOUR_ACCESS_KEY"
    Task {
        do {
            try await NBNavigation.initializeOffline()
        } catch {
            print("Offline initialization failed: \(error.localizedDescription)")
        }
    }
    return true
}
```

`initializeOffline` configures the offline map runtime and initializes the offline routing engine. Concurrent calls with the same valid configuration wait for the same task. Calls made after successful initialization return immediately.

## Initialization behavior

| Scenario | SDK behavior | Integration guidance |
| --- | --- | --- |
| Concurrent calls with the same configuration | Waits for the same initialization task | Safe to call directly |
| Repeated calls with the same configuration | Returns immediately after successful initialization | No once flag required |
| Different configuration while initialization is in progress | Throws `invalidConfig` | Use one configuration source |
| Initialization fails | Enters the failed state and retains the error | Call _initializeOffline_ again after correcting the cause |
| Initialization has not started | Offline APIs throw `engineNotInitialized` | Start initialization first |

## Initialization state and loading screens

It is recommended to use `state` only to drive the UI

```swift
switch NBNavigation.getOfflineInitializationState() {
case .notStarted:    showStartRequired()
case .initializing:  showLoading()
case .initialized:   showContent()
case .failed:        showRetry()
case .shuttingDown:  showClosing()
}

// Use only when the screen has a separate loading phase.
try await NBNavigation.waitUntilOfflineInitialized()
```

_waitUntilOfflineInitialized_ does not start initialization. It throws _engineNotInitialized_ when the state is `notStarted` and rethrows the original error after a failed initialization. Call `initializeOffline` to start or retry initialization.

**Initialization state**

> _Use_ `isOfflineInitialized` _only to update UI state, such as displaying a loading indicator. Do not use it to decide whether an offline routing API can be called. Call the API directly and await its result. Offline routing APIs automatically wait for initialization that is already in progress and throw an error if initialization has not started or has failed. If a screen requires a separate initialization loading phase, call_ `waitUntilOfflineInitialized()`.

## Post Initialization Health Check

In order to test and run diagnostics after Initialization, use:

```swift
do {
    let health = try await NBNavigation.checkOfflineHealth()
    print("offline state=\(health.state)")
    print("data root=\(health.dataRoot)")
    print("routing tiles=\(health.loadedTileCount)")
} catch {
    print("Offline initialization failed: \(error.localizedDescription)")
}
```

Please note that:

-   _checkOfflineHealth_ reports the engine state after initialization. A successful call confirms that the native gateway can respond to queries.
-   A `loadedTileCount` of 0 means that no routing tiles are loaded; it does not indicate an initialization failure.
-   `health.state` is a diagnostic field and should not be treated as a stable application enum.

## Recommended call sequence

1.  Configure the route mode and download network policy.
    
2.  Call _initializeOffline_ during app startup.
    
3.  On the offline screen, synchronize the catalog, and then read the combined region list.
    
4.  Subscribe to progress updates before calling _downloadRegion_.
    
5.  Send all route requests through `NBNavigation.fetchRoute`. _RouteMode_ determines the online and offline strategy.
    

## Key takeaways

-   Call `NBNavigation.initializeOffline` as early as possible after app launch. Repeated or concurrent calls with the same configuration reuse the same initialization task.
    
-   Offline routing APIs such as _listOfflineRegions_, _syncOfflineRegionList_, and _downloadRegion_ wait for an initialization already in-progress, but they do not start initialization.
    
-   Routing data and map tiles are separate datasets linked by `regionId`. _downloadRegion_ starts both downloads, but the combined operation is not a database transaction.
    
-   An in-place update of the same app normally preserves offline data. Uninstalling and reinstalling the app deletes its sandbox. Use the SDK's default `dataRoot` whenever possible.
