# Initializing the SDK

The SDK needs to be initialized with some basic settings (such as the directory the SDK can use for data storage and logs), and with a `TokenSigner` that is provided by the host application. This must occur early in the lifecycle of the app.

Create a class to implement the `TokenSigner` (see example below):

```swift
import Common

class TokenSignerExample: TokenSigner {
    func sign(_ unsignedToken: String, resultHandler: @escaping ResultHandler<String>) {
        // signing logic
    }
}
```

Next, create a class to configure/initialize the SDK (see example below):

```swift
import Common

class SDKConfigExample {
    // Choose a directory that the SDK can access and will own.
    let sdkRootDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        .first!.appendingPathComponent("sdk", isDirectory: true)
    
    init() {
        try! initialize(Directories(root: sdkRootDirectory),
                        logLevel: .debug,
                        tokenSignerFactory: TokenSignerExample())
    }
}
```

NOTE: Classes can (and should) be renamed, as appropriate.

***WARNING:*** Failing to initialize the SDK before using its functionality will result in unexpected behaviour.

## Beginning Trip Detection Manager

To upload trip data, the current mobile device must be activated for data collection through the `Portal`. This is to ensure trip data can be analyzed properly on the IMS backend. Depending on the mode of activation the host application chooses and the design of the app, device activation may only need to be performed once for a device.

### Identity

An `Identity` is constructed with the host application's unique user identifier, provided during the enrolment process. Once the user is authenticated using the host application's authentication provider, the host application communicates this to the SDK using `Identity.setIdentity()`.

While the SDK will generally persist a user identity across app launches, `SDKConfig.shared.identity` should be explicitly checked at app launch and `setIdentity()` called if it is nil.

**Important:** The host application must wait until it receives the result from the **identity.setIdentity** call before calling any Portal APIs.

**Example:**

```swift
let identity = Identity(externalReferenceID: uid)
let result = await identity.setIdentity()

switch result {
case .success(let value):
    // Identity successfully set
case .failure(let error):
    // Failure
    // User is not considered logged in. 
    // Trip detection will not work as expected
}
```

When logging out, identity needs to be cleared. To clear identity, `clearIdentity()` must be called. Any SDK API call made after invoking this method will fail.

**Example:**

```swift
await identity.clearIdentity()
```

### UploadRoute

The host application can choose upload route for uploading trip files which can be passed during the initialization of the SDK.

For more details about upload routes check [Using the SDK](/readme/ios/using-the-sdk.md#controlling-how-the-files-are-uploaded)

### Feature

The `features`: `[Feature]` parameter of TripDetectionManager's initializer specifies which features are used for *Trip Detection* and *Trip Validation*. A combination of Trip Detectors and Trip Validators can be passed into the initializer to meet the needs of the App. Simply declare all `Feature` components that are needed.

A standard setup would include at least one Trip Detector and one Trip Validator. For example, a phone only trip detection configuration would include `[Feature.Geofence]` and `[Feature.PhoneOnlyValidation]`.

#### Trip Detection

*Feature.Geofence***:** To use geofences for trip detection, pass in `[Feature.Geofence].`This feature provides trip detection using Core Motion and Core Location functionalities.

*Feature.Bluetooth:* To use Bluetooth devices for trip detection, pass in `[Feature.Bluetooth].`This feature uses Core Bluetooth functionality to have trip detection using a bluetooth device (i.e. wedge).

NOTE: If there is no Trip Detection Feature parameter passed in the configuration, Trip Detection functionality will be limited.

#### Trip Validation

Starting with the SDK 1.15.0, the host app can provide the trip validation features as in the example above during the initialization of SDK.

*Feature.PhoneOnlyValidation:* To use phone-only trip validation feature, pass in `[Feature.PhoneOnlyValidation].` This feature allows a trip to be validated using the onboard sensors of the phone.

*Feature.DeviceValidation:* To use Bluetooth devices for trip validation feature, pass `[Feature.DeviceValidation].` This feature allows a trip to be validated by the presence of an associated Bluetooth device during the trip.

NOTE: If there is no Trip Validation Feature parameter passed in the configuration, trips will be validated as soon as they are detected.

### Complete Example

We can create a class that contains all of the trip detection methods listed above:

```swift
import Common
import Portal
import TripDetection
import TripDetectionUmbrella

class TripDetectionManagerExample {

    private let tripDetectionManager: TripDetectionManager?

    init() {

        // The telemetry events to be recorded
        let telemetryEvents: Set<TelemetryEvent> = [.gps,
                                                    .speed,
                                                    .gyroscope(.oneHz),
                                                    .gravity(.oneHz),
                                                    .accelerometer(.oneHz),
                                                    .userAcceleration(.oneHz),
                                                    .magnetometer(.oneHz)]
        
        // Feature for phone trip detection
        let features: [Feature] = [Feature.Geofence, Feature.PhoneOnlyValidation]
        
        // Feature for device trip detetction
        // let features = [Feature.Bluetooth, Feature.DeviceValidation]
        
        // Feature for phone-only and device trip detection
        // let features: [Feature] = [Feature.Geofence, Feature.PhoneOnlyValidation, Feature.Bluetooth, Feature.DeviceValidation]

        // Initializes trip detection by way of the TripDetectionManager.
        tripDetectionManager = TripDetectionManager(uploadRoute: uploadRouteType,
                                                    telemetryEvents: telemetryEvents,
                                                    features: features)
    }

    func activateDevice() {
        deviceService.activate { [weak self] result in
            guard self != nil else {
                return
            }
            switch result {
            case .failure(let error):
                log.e("Error activating device: \(error)")
            case .success:
                log.i("Device activation successful")
            }
        }
    }

    func enableTripDetection() {
        // Enable Trip Detection
       tripDetectionManager.enable { (state, date) in
            switch state {
            case .potentialTrip:
                log.d("Potential trip at \(date)!")
            case .confirmedTrip:
                log.d("Confirmed trip at \(date)!")
            case .endedTrip:
                log.d("Trip ended at \(date)!")
            @unknown default:
                log.e("Error fetching trip states with date!")
            }
        }
    }

    func disableTripDetection() {
        tripDetectionManager?.disable()
    }
}
```

## Configure Bluetooth Device Provider

* Starting with SDK 1.19.0, host app has the capabilities to configure the device providers
* Host app can use the new `Devices` and `IMSBluetooth` frameworks to configure the bluetooth usage for TripDetection. Both frameworks are required to be included in the project if the trip detection variant is using bluetooth and devices to detect trips.

### Concrete Example

The Devices module provides APIs as listed below:

* scanForDevices: To scan bluetooth devices
* associateDevice: To associate an IMS device
* disassociateDevice: To disassociate an IMS device
* clearAllAssociatedDevices: To clear all associated devices
* associatedDevices: To retrieve already associated devices

Below is the snapshot for understanding the configuration required to utilize the new modules:

```swift
import Combine
import Common
import Devices
import IMSInterfaces
import IMSBluetooth
import Primitives

class BluetoothManager {
    static let shared = BluetoothManager()
    private let bluetoothDeviceProvider: IMSDeviceProvidable

    let supportedDevicesPrefixes = [
        "IMS-"
    ]

    init() {
        let pattern = "^(" + supportedDevicesPrefixes.joined(separator: "|") + ")"
        do {
            // Create a regex object
            bluetoothDeviceProvider = BluetoothDeviceProvider(wedgeRegex: try NSRegularExpression(pattern: pattern, options: []),
                                                              tdwdServerEnv: .dev)
        } catch {
            fatalError("Failed to create regex: \(error)")
        }
        IMSDeviceManager.configure(providers: [bluetoothDeviceProvider])
    }
    
    func scanForDevices() {
        IMSDeviceManager.scanForDevices(withTimeout: 20.0)
            .sink { completion in
                switch completion {
                case .finished:
                    break
                case .failure(let error):
                    print("Scan error: \(error)")
                }
            } receiveValue: {
                self.devices.append($0)
            }
            .store(in: &cancellables)
    }
    
    func associateDevice(deviceId: String, deviceName: String, toVehichleId vehicleId: String?) {
        let bluetoothDevice = IMSDevice(deviceId: deviceId, deviceName: deviceName)
        IMSDeviceManager.associateDevice(bluetoothDevice, toVehichleId: vehicleId)
    }
    
    func disassociateDevice(_ device: IMSDevice) {
        IMSDeviceManager.disassociateDevice(device)
    }
    
    func clearAllAssociatedDevices() {
        IMSDeviceManager.clearAllAssociatedDevices()
    }
    
    func associatedDevices() -> [IMSDevice] {
        IMSDeviceManager.associatedDevices.compactMap { device in
            // use the device
        }
    }
}
```

## SDK initialization feedback

Starting with the SDK 1.10, it is possible to add a handler to be notified of SDK status changes. Setting a handler:

```swift
tripDetectionManager.setStatusHandler { status in
    print("Trip detection status \(status)")
}
```

Removing the current handler:

```swift
tripDetectionManager.setStatusHandler(nil)
```

These can be added to the Trip Detection Manager class.

NOTE: The list of statuses will be expanded in future releases.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://sdk.ims.tech/readme/ios/initializing-the-sdk.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
