iOS documentation

The MotionTag Mobility & Location Analytics SDK collects an iPhone's raw sensor data in a battery efficient way. This data is then transmitted to the MotionTag back-end system (ISO 27001 certified). In the backend, the sensor events are processed and a partial journey is constructed. Journeys consist either solely of tracks or tracks plus stays. Tracks describe a movement from a origin to a destination with a certain mode of transport. Stays symbolize a stationary behaviour with a particular purpose for the visit.

The use cases for the SDK are manifold. In the mobility sector it can be used to get detailed mobility data for planning purposes. The collected data enables to compare how the transport network is being used. This way the effectiveness of the current infrastructure and the passenger flow management is measured and the design of new mobility services. By implementing and using the SDK you can make use of these findings to improve timetables and routes, expand transport supply and attract more passengers.

If you integrate MotionTag Tracker SDK inside your own application, you can either download user journeys via a provided dump interface on the internet or we tailor a customized solution to your needs.

1. Changelog

You can find the latest SDK version in our changelog page.

2. Native sample app

A native iOS sample app can be found on our GitHub page: https://github.com/MOTIONTAG/motiontag-sample-app-ios This sample app showcases the best practices in integrating the SDK into native iOS apps.

3. Required App Settings

  • Capabilities -> Background Modes:

    • Location Updates
  • Add to Info.plist:

    • "Privacy - Motion Usage Description" string
    • "Privacy - Location Always & When in Use Description" string
    • "Privacy - When in Use Description" string
  • minimum deployment target is 11.0.

Authorizations

The SDK requires two authorizations:

  1. Location (Always)
  2. Motion

Both would be need to be obtained by your app before calling the start method the first time.

Location

On iOS > 13.5, the "Always" authorization can be obtained by obtaining the "While Using" authorization, and elevating it to "Always" right away as demonstrated in our sample app.

Motion

The "Motion authorization" is not essential, but it is recommended for improved battery usage. Unfortunately, iOS provides no such way for requesting "Motion authorization" - it is automatically requested when you start gathering motion data the first time. This is also demonstrated in the sample app.

4. Interface

public enum DataTransferMode : UInt {
    case wifiOnly
    case wifiAnd3G
}

open class MotionTagCore : NSObject {
    open class func sharedInstance(withSettings settingsDict: [AnyHashable : Any]?) -> MotionTag & NSObjectProtocol
    open func setDelegate(_ delegate: MotionTagDelegate?)
}

public protocol MotionTagDelegate : NSObjectProtocol {
    optional func trackingStatusChanged(_ isTracking: Bool)
    optional func locationAuthorizationStatusDidChange(_ status: CLAuthorizationStatus, precise: Bool)
    optional func motionActivityAuthorized(_ authorized: Bool)
    optional func didTrackLocation(_ location: CLLocation)
    optional func didTransmitData(_ transmissionTimestamp: Date, lastEventTimestamp: Date)
}

public protocol MotionTag {
    var isTrackingActive: Bool { get }
    var trackingActiveAsInt: NSNumber { get }
    weak var delegate: MotionTagDelegate? { get set }
    func start(withToken token: String?)
    func start(withToken token: String?, settings settingsDict: [AnyHashable : Any]?)
    func stop()
    func useWifiOnlyDataTransfer(_ on: Bool)
    func handleEvents(forBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void)
}

5. SDK user authentication

The SDK must be configured at runtime with a user-specific token.

Tokens can be generated on your backend, or manually with the form below (only accessible when signed in). They are signed JWTs (see jwt.io). Users are identified by distinct UUIDs – the creation and management of the user UUIDs is up to you. MOTIONTAG creates a user entry in its database when data from the SDK for a new user UUID arrives for the first time.

To generate the JWTs on your backend, encode and sign a payload like the example below with the shared secret, which is accessible in the admin dashboard under "Authentication tokens". Include these claims:

  • iss claim: the tenant key that you have received from MOTIONTAG
  • sub claim: the user UUID
  • exp claim: expiry integer timestamp (optional)

Example payload:

{
  "iss": "my-tenant-key",
  "sub": "aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb"
}

Generate JWTs from user UUIDs

Only accessible when signed in. You need a custom domain setup by MOTIONTAG (e.g. my-tenant-key.motion-tag.de) and an account to sign in. Contact MOTIONTAG Support to request a custom domain setup and an account. If you already have both, visit your custom domain and sign in to see a customized version of this documentation.

6. Setup

Initialize the library via the singleton method:

    let motionTag = MotionTagCore.sharedInstance(withSettings: SETTINGS_OR_NIL)

This needs to be done somewhere near the top of didFinishLaunchingWithOptions. The reason is that the app may be started from the background by the system. By initializing the tracking library early, you guarantee that all location managers are set up to retreive new incoming locations.

The settings parameter can be NSDictionary or nil. For more info see the Settings section below.

Also, the AppDelegate's handleEventsForBackgroundURLSession method needs to be implemented like below;

func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
   motionTag.handleEvents(forBackgroundURLSession: identifier, completionHandler: completionHandler)
}

If you're using FirebaseAnalytics, you need to call its handleEvents(forBackgroundURLSession ... here as well. Moreover addFirebaseAppDelegateProxyEnabled to your App's Info.plist and set its value to NO. Please see:

https://firebase.google.com/docs/reference/swift/firebaseanalytics/api/reference/Categories/FIRAnalytics(AppDelegate)

This goes for similar frameworks which swizzle the handleEventsForBackgroundURLSession method by default.

If you want to receive callbacks, set the appropriate delegate (MotionTagDelegate):

    motionTag.delegate = self

To start tracking, just call the startWithToken:settings: method:

    motionTag.start(withToken:"A_VALID_TOKEN", settings:SETTINGS_OR_NIL)

To stop tracking, just call the stop method:

    motionTag.stop()

7. SDK Settings

Both, sharedInstance(withSettings: ) and start(withToken: , settings: ) accept an NSDictionary as a parameter - if you pass in nil the SDK will fall back to default values. The settings described in this section cannot be changed while the SDK is running. So you will have stop the tracking (motionTag.stop()) before changing the settings and finally call start(withToken: , settings: ) with the modified settings to re-start the tracking. You would then also pass these modified settings into the sharedInstanceWithToken:settings: method on the next start of your application - so it makes sense to persist the settings within your app.

The following options are available:

  • kMTDataTransferMode (MTDataTransferMode, either kDataTransferModeWifiOnly or kDataTransferMode3G; default is kDataTransferModeWifiOnly). It defines how the recorded data will be transmitted to the backend. With kDataTransferModeWifiOnly data will only be transmitted while the device has a Wifi connection. Settings the mode to kDataTransferMode3G will also allow the device to transmit data when only having a cellular connection.
  • kMTBatterySavingsMode (BOOL; default is true). If true MotionTag's battery saving tracking algorithm will be used. If set to false the SDK will fall back to a standard (always running in the background) CLLocationManager startUpdatingLocation routine with a desiredAccuracy of kCLLocationAccuracyKilometer.

Example:

private let settings: [String: AnyObject] = [kMTDataTransferMode: DataTransferMode.wifiAnd3G.rawValue as AnyObject,
                                             kMTBatterySavingsMode: true as AnyObject]
let motionTag = MotionTagCore.sharedInstance(withSettings: setting)
motionTag.stop()

private let settings: [String: AnyObject] = [kMTDataTransferMode: DataTransferMode.wifiOnly.rawValue as AnyObject,
                                             kMTBatterySavingsMode: true as AnyObject]
motionTag.start(withToken: "A_VALID_TOKEN", settings: settings)

8. Callbacks

Optional

trackingStatusChanged(_ isTracking: Bool)

  • gets called upon a change in the tracking state, whether directly toggled by the user, or due to changes in location authorizations.

locationAuthorizationStatusDidChange(_ status: CLAuthorizationStatus, precise: Bool)

  • if the user changes the location authorization status of the app this callback will be called. The precise parameter is status of the iOS 14 "Precise Location" authorization. This parameter will be true on versions before 14.

motionActivityAuthorized(_ authorized: Bool)

  • called once when the SDK starts tracking, reflecting the "Motion & Fitness" authorization status.

didTrackLocation(_ location: CLLocation)

  • gets called whenever the SDK tracks a new location, also providing the timestamp of the last event transmitted.

didTransmitData(_ transmissionTimestamp: Date, lastEventTimestamp: Date)

  • gets called whenever the SDK has successfully transmitted a data package to the backend.

9. Installation

The SDK contains both the armv64 and the x86_64 symbols (which are necessary to run it on the simulator). When building a release version the cocoapods scripts will strip out all x86_64 symbols so that the release will be compatible with the App Store.

  pod 'MotionTagSDK', git: "https://gitlab.com/motiontag-dist/tracker-library-ios.git"