Skip to content

pinpoint-positioning/Pinpoint-iOS-SDK

Repository files navigation

Pinpoint iOS SDK

Introduction

The Pinpoint iOS SDK is a Swift package for FiRa compliant Ultra-Wideband (UWB) positioning with Pinpoint's technology.

Use Cases

The Pinpoint iOS can be used to integrate our indoor positioning system into your own solutions.

Use Case examples

Routing Solution Integration with MapBox
Routing Solution Integration with Apple Maps
Navigation with MapsPeople Positioning with MapBox

Features

  • Indoor Positioning for GNSS/GPS denied areas
  • Accuracy of up to 30 cm
  • Simple Integration
  • UWB Background mode support

Prerequisites

Before integrating the Pinpoint iOS SDK, please ensure you have access to the necessary Pinpoint hardware components.

The SDK requires compatible Pinpoint Hardware for accurate indoor positioning. Depending on your use case, you can use one of the following hardware options:

  • Prototyping Kit:
    Ideal for developers and researchers who want to quickly evaluate and experiment with Pinpoint’s indoor positioning capabilities.
    The kit includes all essential components required to set up a small-scale test environment.

  • SATlets:
    Compact satellite modules designed for scalable and permanent installations.
    SATlets are suitable for production environments or larger deployments requiring reliable and precise indoor localization.

To ensure optimal performance, confirm that your hardware is correctly installed and configured before running the SDK.

Installation

Important The Pinpoint iOS SDK requires an iPhone with iOS 27beta as well as XCode27. Make sure your MacOS is at leat macOS 26.5 in order to run the latest XCode27 beta.

To integrate the Pinpoint iOS SDK add the repo as a swift package dependency to you project using the Swift Package Manager. This requires a setup of a custom registry and your access credentials for the Pinpoint SDK repository.

  1. Add the registry:
swift package-registry set --global https://posie.pinpoint.de:8073/repository/ios_sdk_release/

~/Library/org.swift.swiftpm/configuration/registries.json should look like this:

{
  "registries" : {
    "[default]" : {
      "supportsAvailability" : false,
      "url" : "https://posie.pinpoint.de:8073/repository/ios_sdk_release/"
    }
  },
  "version" : 1
}
  1. Add Credentials to Keychain
swift package-registry login https://posie.pinpoint.de:8073/repository/ios_sdk_release/login --username <username>

Enter your Pinpoint repository password when prompted

  1. In Xcode -> Add Package Dependencies -> Enter pinpoint.pinpointsdk -> Add to Project

Routing Solution

Versioning

Set the Dependency Rule to Exact Version.

To update the SDK, bump the version number to the latest, released Pinpoint SDK version.

Routing Solution

Getting Started

To use the Pinpoint iOS SDK in your iOS project, follow the steps below.

We strongly recommend to use the included Sample App as implementation reference.

The usage examples below can be found in PositionProvider.swift inside the demo app.

Importing the Module

First, import the module at the top of your Swift file:

import PinpointSDK

The PinpointApi class provides various functions to interact with nearby tracelets using Bluetooth.

Below are the main functions available for public use:

Initialize the SDK

Initialize the API class with your API-Key. The initialization requires to run ansynchronously.

It's recommended to initialize the API in a central place in your app and make it observable for other parts of your application.

The PinpointSDK offers two protocols to implement:

  • PinpointStateDelegate: Provides connection, BLE and license states updates.
  • PinpointPositionDelegate: Provides position updates.

Make your class conform to PinpointStateDelegate, and PinpointPositionDelegate.

Hint

You can use different classes to implement the delegates. E.g. a StateManager and a PositionManager. In our example, we implement both delegates in one single class.

class PositionProvider: ObservableObject,PinpointStateDelegate, PinpointPositionDelegate {

    private func initializeSDK() async {
        do {
            let sdk = try await PinpointAPI(apiKey: "YOUR-API-KEY")
            self.api = sdk
            self.api?.positionDelegate = self   // assign self as delegate
            self.api?.stateDelegate = self      // assign self as delegate
            print("SDK initialized successfully")
        } catch {
            self.api = nil
            print("SDK initialization failed:", error)
        }
    }

Implement delegate stubs for state changes and position changes

The LocalPosition data model provides the following positioning values withing the UWB-network coverage:

    var x:Double
    var y:Double
    var z:Double
    var acc: Double
    var lat:Double
    var lon:Double
    var alt:Double
// Delegate method for PinpointPositionDelegate
  func pinpointAPI(_ api: PinpointAPI, didUpdatePosition position: LocalPosition) {
        self.handleNewPosition(position)
    }
    
// Delegate methods for PinpointStateDelegate
    func pinpointAPI(_ api: PinpointAPI, didChangeBLEState state: BLEState) {
        print(state)
    }
    
    func pinpointAPI(_ api: PinpointAPI, didChangeConnectionState state: ConnectionState) {
        DispatchQueue.main.async {
            self.connectionState = state
        }
    }

    // New: Returns the exiry date of the cached license. 
    // The cached licence is renewed automatically. 
    // In rare cases, when the phone has no internet connection for license renewal, this date should be
    // observed and the user notified to connect to the internet.
    func pinpointAPI(_ api: PinpointSDKFramework.PinpointAPI, didChangeLicenseState expiry: Date) {
        print("License expires on: \(expiry.formatted())")
    }
    

Listen to @Published position stream (Alternative)

Altenatively, you can listen to changes within the published variable api.localPosition directly, when using SwiftUI

.onAppear {
    // Your code here e.g.
    // Set initial position
    xPos = api.localPosition.x
    yPos = api.localPosition.y
    latPos = api.localPosition.lat
    lonPos = api.localPosition.lon
}
.onChange(of: api.localPosition) { newPosition in
    // Your code here e.g.
    // Update position when localPosition changes
    xPos = newPosition.x
    yPos = newPosition.y
    latPos = api.localPosition.lat
    lonPos = api.localPosition.lon
}

Starting position stream

The connection, setup and position updates can be initiated with as single function call of startPositionStream(siteID:UInt32, blob:Data).

  • siteID: The Site ID from your site (shown in EasyPlan)
  • blob: A .bin file that can be generated from EasyPlan

The blob needs to be converted to Data:

e.g.: blobData = try Data(contentsOf: pathToBinFile)

In our Sample App, the blob will be added via a simple file picker.

When the call was successful, you receveive continuous position updates via didUpdatePosition delegate method, you implemented before.

    // Start the postion stream
    func startPositionStream(siteID:UInt32, blob:Data) async  {
        guard let api = self.api else { return }
            await api.startPositionStream(siteId: siteID, blob: blob)
    }

Background positioning with native UWB

The UWB-session can be kept alive by using LiveActivites.

Set up a LiveActivity as described here:

https://developer.apple.com/documentation/activitykit/displaying-live-data-with-live-activities

You also need to add Background Modes capability to your target and check Uses Nearby Interaction in:

XCode -> Target -> Signing and Capabilities -> Add capability -> Background Modes.

A minimal set of ActivityAttributes for the LiveActivity can look like this:

import ActivityKit
import NearbyInteraction

struct WidgetAtributes: ActivityAttributes {
    struct ContentState: Codable, Hashable {
        var x: Double
        var y: Double
    }
}

The included Sample App shows a minimal implementation of the LiveActivity with continuous background positioning.

License

This package is licensed under a proprietary license. Please refer to the LICENSE file for more details.

About

Pinpoint iOS SDK to enable FiRa-compliant Ultra-Wideband positioning for indoor environments

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages