iOS SDK FAQ

What iOS versions are supported?

Check the Requirements section.

Can I test the tracking without actual movement?

Yes, please check the Test the workflow with mock locations doc.

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)
    }
}