iOS

iOS SDK

Requirements

  • iOS 12+
  • CPU architectures: arm64, arm64e
  • Simulator architectures: arm64, x86_64
  • Devices with GPS chip (excludes iPod Touch and some iPads)

Basic integration

Migrating from older versions? Check the Migration guide

Add HyperTrack SDK to your project

We constantly work on making our SDKs better, so make sure you have the latest version. You can get it in the changelog here.

Swift Package Manager

Select File > Swift Packages > Add Package Dependency.... Enter this URL https://github.com/hypertrack/sdk-ios in the search field to install the dependency.

Swift Package Manager is supported in Xcode 12 and up.

CocoaPods

If you don't have CocoaPods installed, you can install it here.

Using command line run pod init in your project directory to create a Podfile. Put the following code (changing target placeholder to your target name) in the Podfile:

platform :ios, '12.0'
inhibit_all_warnings!

target 'YourApp' do
  use_frameworks!
  pod 'HyperTrack', '<version>'
end

Run pod install. CocoaPods will build the dependencies and create a workspace (.xcworkspace) for you.

Enable Background Modes

Enable Background Modes in your project target's Capabilities tab. Choose "Location updates" and "Remote notifications".

Remote Notifications in Xcode

In the same tab, ensure that push notifications is enabled.

Push Notifications in Xcode

Add purpose strings

Set the following purpose strings in the Info.plist file:

Always authorization location

The key names are as follows:

  • NSLocationAlwaysAndWhenInUseUsageDescription
  • NSLocationWhenInUseUsageDescription

Purpose string should explain the value that location tracking provides.

HyperTrack SDK requires "Always" permissions to reliably track user's location.
Be advised, purpose strings are mandatory.

Your app needs to make sure that it has location permissions for location tracking to work. See this F.A.Q. page for details on permissions best practices.

Set up silent push notifications

We use silent push notifications to wake up the app when work is assigned to a driver or to prevent tracking interruptions.

Enable push notifications capability

Check the iOS documentation on APNs for the instructions

Get the APNs key

You can create or download the existing key in your Apple Developer Account settings

Add APNs ket to HyperTrack dashboard

Log into the HyperTrack dashboard, and open the setup page. Upload your Auth Key (file in the format AuthKey_KEYID.p8) and fill in your Team ID.

Set the publishable key

Get your publishable key from the Setup page.

Put the publishable key in your app's Info.plist as HyperTrackPublishableKey key with type String and the value obtained above.

Grant the permissions to the app

To start tracking the app requires Location permissions. You have to grant them in Settings > Privacy > Location Services > ...Your App... > Allow Location Access > Always.

Also make sure that Location services and Precise location switches are on.

Start tracking

Now the app is ready to be tracked from the cloud.

You will need the device id to start tracking, check the Identify devices section for instructions on how to get it.

Follow the Start Tracking tutorial to learn how to control device tracking from your backend.

Dashboard

Once your app is running, go to the dashboard where you can see a list of all your devices and their live location with ongoing activity on the map.

Prepare for App Store submission

App Privacy

HyperTrack values user privacy and is not engaging in tracking the user across apps. All the data that the HyperTrack SDK collects is used only to power HyperTrack features. The data is collected on device, and then securely transferred to HyperTrack cloud.

Submitting the App Privacy report

In the App Store Connect select your app and go to App Store > App Privacy. If this is the first time you are submitting a report tap the "Get Started" button; if you already have an existing report tap the "Edit" button next to the "Data Types" section.

  1. Data Collection. Choose "Yes, we collect data from this app" and tap "Next"
  2. Scroll to "Location" section and choose "Precise Location". This is the primary data that the SDK collects and securely transfers to HyperTrack cloud to power all the features
  3. Scroll to "Identifiers". Choose "User ID". HyperTrack SDK generates a random device_id when the SDK is unlocked with the publishable key for the first time. This ID is completely random and does not encode any user-specific information. It is used to identify the user's device in our APIs and it is reset when a user reinstalls the app
  4. Choose "Device ID". HyperTrack SDK uses Identifier for Vendor (IDFV) to identify the user between app reinstalls if the user has multiple apps from you. If the user only has one app from you, this identifier is also reset when a user reinstalls the app. This identifier is available as os_hardware_identifier in our APIs
  5. Tap "Publish"

Setting up how the data is collected

If this is the first time you are submitting a report tap "Set Up ..." next to a data identifier. If you already have an existing report tap the "Edit" button next to the specific data identifier.

Precise Location
  1. Choose "App Functionality" and tap "Next"
  2. Select "Yes, precise location data collected from this app is linked to the user’s identity" and tap "Next". This data is linked to the user through the randomly generated "device_id"
  3. Select "No, we do not use precise location data for tracking purposes" and tap "Publish"
User ID
  1. Choose "App Functionality" and tap "Next"
  2. Select "Yes, user IDs collected from this app are linked to the user’s identity" and tap "Next". In this case the "device_id" is used to identify the user
  3. Select "No, we do not use user IDs for tracking purposes" and tap "Publish"
Device ID
  1. Choose "App Functionality" and tap "Next"
  2. Select "Yes, device IDs collected from this app are linked to the user’s identity" and tap "Next". This data is linked to the user through the randomly generated "device_id"
  3. Select "No, we do not use device IDs for tracking purposes" and tap "Publish"

Complying with App Store Review Guidelines

HyperTrack SDK requires the use of the UIBackgroundModes key inside the Info.plist file to collect the location data when the user is on the move and the app is not on-screen. This is the typical automating work on the move use case. If the App Store review team is not convinced that background location access is justified for your app, they may reject it for violating the 2.5.4 section of App Store Review Guidelines.

Here are some tips that will help you avoid this:

  • Your app should have permission strings that clearly explain to your worker why the app needs their location. Those strings will be displayed in permission dialogs and in Settings.app.
  • Don't ask for permissions right when the app starts. Instead ask for permissions after the user action that starts location tracking session. It is best to have a separate screen in the app, explaining the use of location tracking with a button that triggers permission dialog.
  • App Store review requires your app to have visible features that depend on background location access. For example, your app can have a map, showing the worker his route to a customer, or a visual element explicitly explaining that location tracking is currently active and is used to automatically complete a task the worker is performing.
  • When submitting your app for review, include a video showcasing all your app features that require location permissions to test. App Store review team usually doesn't want to grant those permissions and the video significantly speed ups the review process. A link to an unlisted YouTube video works great in most cases.

Recommended additional steps

Identify devices

All devices tracked on HyperTrack are uniquely identified using UUID. You can get this identifier programmatically in your app by calling deviceID.

⚠️

The device ID is changed on each app re-install

Another approach to identification is to tag devices with names that will make it easy to distinguish them on HyperTrack Dashboard.

HyperTrack.name = "Device name"

You can additionaly tag devices with custom metadata (and filter them in the Dashboard using metadata fields). Metadata should be representable in JSON.

HyperTrack.metadata = ["key": "value"]

Handle errors

Use the errors query or subscribeToErrors subscription to make sure that when the driver navigates to the screen where tracking is supposed to happen, there are no blockers that can interrupt it.

You can use subscription API to be able to react immediately when errors come up:

// The lifetime of this value is linked to the lifetime of subscription.
// Usually is declared as a property of a ViewController.
var errorsCancellable: HyperTrack.Cancellable? = nil

errorsCancellable = HyperTrack.subscribeToErrors { errorsSet in
  for error in errorsSet {
    switch error {
    case .location(.permissions(.denied)):
      // Handle case when location permissions are denied
    case ...
    }
  }
}

Or by querying the API only when needed:

for error in HyperTrack.errors {
  switch error {
  case .location(.permissions(.denied)):
    // Handle case when location permissions are denied
  case ...
  }
}

Check the API docs to get the full list of errors.

Migration guide

The release of HyperTrack iOS SDK 5.0.0 is a major update that has a bunch of new improvements. We highly recommend upgrading, but please note that there are a few breaking changes.

The most significant advancements in this release are:

User-friendly API:
The revamped static API is the highlight, standing out for its unmatched simplicity, ease of use, and conciseness.

Enhanced Responsiveness & Speed:
Experience quicker time to the first location and minimized system latency.

Superior Tracking Performance:
Delight in the improved quality, granularity, and accuracy of the location event stream.

Optimized Battery Efficiency:
Our refined tracking algorithm reduces unnecessary network calls, preserving battery life.

Decreased Binary Size:
The library's size optimization ensures a more compact overall app footprint.

You can check the detailed Changelog here.

The key breaking changes are:

Setting the publishable key

There is no need to initialize the SDK by setting publishable key. The Basic integration instructions describe the new way of setting it.

Static API

The SDK API was fully redesigned to be more ergonomic and to require less code to integrate.

All the API methods can be accessible at any time from any place in the app by calling them on the static HyperTrack class.

Check the Changelog for the renamed methods.

Motion activity permission is no longer required

While the SDK still can benefit from Motion activity data to get better accuracy, requesting this permission is now optional.

New nested HyperTrack.Error enum

In the older versions the HyperTrackError and HyperTrack.LocationError classes had one-level structure an were sets of errors.

In the new version they are replaced with HyperTrack.Error class that has the nested structure, but is equivalent to the two above. For example:

let error = HyperTrack.LocationError.locationPermissionsNotDetermined
let error = HyperTrack.Error.location(.permissions(.notDetermined))

Check the Handle errors section for more detailed instructions on how to use the Errors API

SDK Sync

The SDK is now automatically syncs with the servers, so the syncDeviceSettings() method is no longer needed. You can safely remove it and all the logic related to it.

Reference

For a full SDK API reference see HyperTrack iOS SDK Reference

SDK integration examples

To learn more about SDK integration examples, you may visit these resources:

Support

Join our Slack community for instant responses.

Frequently Asked Questions

What iOS versions are supported?

Check the Requirements section.

Why doesn't my iOS app start tracking in the background state?

Make sure your app has necessary location permissions to start tracking.
You can check them with the Errors API

Get permissions before your app is in the background state

For example, if your app does the following steps:

  • User logs in
  • Starts a shift
  • App calls your app backend which calls HyperTrack API to create a trip

then at this point the app can already be in the background because the user has already switched to other tasks. HyperTrack cannot start tracking on the device for the trip as permissions cannot be requested while the app is in the background state.

📘

If location permissions are not granted in the foreground prior to the app going to the background state, HyperTrack SDK cannot request them to start location tracking in your app in the background state.

That’s why it’s important to make sure that the app has all required permissions before the user can start a shift.

To make this happen, your app needs to use CLLocationManager to request authorization.

Usually apps detect current permissions state first and, if they are not granted, show a special screen allowing the user to grant them right there, or if they were denied to switch them on in Settings.app.

This way, when the user starts a new shift, push notification would reach the app, the app would have all the necessary permissions to track.

Why did my iOS app stop tracking?

OS regularly drops application memory when it needs more memory for the app that is currently in the foreground.

Test memory usage on device

Quickest way to check this is to run a game or open a Camera app and record a video. The OS sorts all apps frozen in the background by memory footprint and starts dropping memory one by one starting with the largest ones.

When iOS does this, it creates a file called "JetsamEvent", which you can see in Settings > Privacy > Analytics & Improvements > Analytics Data.

For more details see this Apple Developer Note.

📘

:::note

This is typical iOS behavior and no app can assume that the OS will always keep memory for frozen apps.

iOS versions 13.2 and 13.2.1 had a bug which caused the scheduler to drop memory for the frozen apps more aggressively.

Also, your app should not rely on memory to be preserved and should store and then restore their state when the user launches the app.

Sometimes application bugs, like memory leaks, can cause the app to consume a lot of RAM, and become one of the first apps in the iOS list for the memory reclaim process.

Prevent excessive memory usage on iOS device

To prevent this, your app should be regularly profiled in Xcode using Instruments tool, configured with Leaks preset. It provides two views into the app memory called Allocations and Leaks.

Allocations allow you to see how much RAM your app is consuming and how this size grows and shrinks in response to user actions.

Leaks tool automatically reports when memory is created and would never be freed. HyperTrack SDK profiled in Instruments consumes under 1 MB of RAM and doesn't have memory leaks.

Good starting point can be Instruments documentation by Apple. iOS also sends low memory warnings to the app when it detects that it consumes too much.

It's also useful to checkout Apple guide on improving your app's performance.

If you’ll find any instances of HyperTrack SDK consuming too much RAM, or being a reason for abrupt terminations, please do not hesitate to contact us and provide crash reports or Instrument analysis files. Instruments sessions can be saved and shared.

Prepare your app to run in the background

iOS can also abruptly terminate the app upon entering the background. This can happen if, upon entering background, the app does not free resources and does not stop long running tasks, like timers and network requests.

The app without a reason to stay in the background has only a couple of seconds to stop all its activities and if it fails, the OS will force the termination.

The following guide by Apple provides all the steps the app needs to do upon entering background and can serve as a checklist.

Why does my application state disappear when my app is opened?

App state is not preserved in the background

App does not hold state when it goes to the background state. When the user returns to the app, it starts from scratch. iOS stops executing an app and freezes its memory when the user hides the app's screen.

The only exceptions are apps that actively do background work, such as:

  • downloading content
  • VoIP calls
  • active location tracking

There are three things that can happen to the app in a stopped and frozen state:

  • The app's memory is stored in RAM and when the user returns to the app execution continues where he left off
  • OS drops the app's memory, so when the user returns, the app needs to restore state manually
  • OS terminates app execution abruptly, crashing the app in the background

📘

This is typical iOS behavior and no app can assume that the OS will always keep memory for frozen apps.

iOS versions 13.2 and 13.2.1 had a bug which caused the scheduler to drop memory for the frozen apps more aggressively.

Apps shouldn't rely on memory to be preserved and should store and then restore their state when the user launches the app.

A good starting point to learn how to manage restoring app state is newly updated UI state restoration guide.

What are the best practices for handling permissions on iOS?

In Human Interface Guidelines Apple recommends the following instructions below:

Request permissions only when they are needed in the flow of the app

If you app is centered around location tracking, then asking for permissions at the app launch can be understandable for users. On the other hand, if location tracking is just one of the features, then it makes sense to request them only when the feature is activated.

Provide short and specific purpose string

Purpose string should explain the value that location tracking provides.

In addition a lot of great apps provide a special screen explaining the need for permissions before asking them. If permissions are denied you can guide the user to the specific page in the Settings.app to change permissions (see this guide for special deep-links for the Settings.app).

"Provisional Always" authorization state

On iOS 13 Apple introduced a new "Provisional Always" authorization state (see this StackOverflow answer for details).

In short:

  • there is no API to detect this state
  • during this state there are no location events in background
  • user sees his permissions as granted and sees "While Using" state in Settings.app
  • app sees permissions as granted with "Always" state.

HyperTrack is working on ways to detect this state and provide APIs that would enable app developers to display explanation screens that will guide the user back to Settings.app to switch permissions from "While Using" to "Always".

Will the Location Services Status Bar (Blue Bar) show while tracking?

Only when tracking is enabled, the Location Services Status Bar (Blue Bar) will show. This is required in iOS 16.4 (and above) to guarantee reliable tracking.

Does the SDK use method swizzling?

The SDK, by default, utilizes Objective-C runtime method swizzling. This swizzling is employed to automatically integrate with AppDelegate methods, enabling the SDK to start at app launch and to integrate with silent push notification methods.
If the swizzling is not functioning as expected, or if you prefer to disable it, you can do so by adding a key named HyperTrackSwizzlingEnabled of type Boolean with the value No in the Info tab of the app's target. After disabling swizzling, you will need to manually implement the following static SDK methods:

class CustomAppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        HyperTrack.didFinishLaunchingWithOptions(launchOptions)

        return true
    }

    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        HyperTrack.didFailToRegisterForRemoteNotificationsWithError(error)
    }

    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        HyperTrack.didReceiveRemoteNotification(userInfo, fetchCompletionHandler: completionHandler)
    }

    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        HyperTrack.didRegisterForRemoteNotificationsWithDeviceToken(deviceToken)
    }
}